diff --git a/cmake/OpenCVFindIPPAsync.cmake b/cmake/OpenCVFindIPPAsync.cmake deleted file mode 100644 index 6f4765cbc982..000000000000 --- a/cmake/OpenCVFindIPPAsync.cmake +++ /dev/null @@ -1,45 +0,0 @@ -# Main variables: -# IPP_A_LIBRARIES and IPP_A_INCLUDE to use IPP Async -# HAVE_IPP_A for conditional compilation OpenCV with/without IPP Async - -# IPP_ASYNC_ROOT - root of IPP Async installation - -if(X86_64) - find_path( - IPP_A_INCLUDE_DIR - NAMES ipp_async_defs.h - PATHS $ENV{IPP_ASYNC_ROOT} - PATH_SUFFIXES include - DOC "Path to Intel IPP Async interface headers") - - find_file( - IPP_A_LIBRARIES - NAMES ipp_async_preview.lib - PATHS $ENV{IPP_ASYNC_ROOT} - PATH_SUFFIXES lib/intel64 - DOC "Path to Intel IPP Async interface libraries") - -else() - find_path( - IPP_A_INCLUDE_DIR - NAMES ipp_async_defs.h - PATHS $ENV{IPP_ASYNC_ROOT} - PATH_SUFFIXES include - DOC "Path to Intel IPP Async interface headers") - - find_file( - IPP_A_LIBRARIES - NAMES ipp_async_preview.lib - PATHS $ENV{IPP_ASYNC_ROOT} - PATH_SUFFIXES lib/ia32 - DOC "Path to Intel IPP Async interface libraries") -endif() - -if(IPP_A_INCLUDE_DIR AND IPP_A_LIBRARIES) - set(HAVE_IPP_A TRUE) -else() - set(HAVE_IPP_A FALSE) - message(WARNING "Intel IPP Async library directory (set by IPP_A_LIBRARIES_DIR variable) is not found or does not have Intel IPP Async libraries.") -endif() - -mark_as_advanced(FORCE IPP_A_LIBRARIES IPP_A_INCLUDE_DIR) \ No newline at end of file diff --git a/cmake/OpenCVFindLibsPerf.cmake b/cmake/OpenCVFindLibsPerf.cmake index 651200dfeca3..70d78cc68950 100644 --- a/cmake/OpenCVFindLibsPerf.cmake +++ b/cmake/OpenCVFindLibsPerf.cmake @@ -35,17 +35,6 @@ if(WITH_IPP) endif() endif() -# --- IPP Async --- - -if(WITH_IPP_A) - include("${OpenCV_SOURCE_DIR}/cmake/OpenCVFindIPPAsync.cmake") - if(IPP_A_INCLUDE_DIR AND IPP_A_LIBRARIES) - ocv_include_directories(${IPP_A_INCLUDE_DIR}) - link_directories(${IPP_A_LIBRARIES}) - set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} ${IPP_A_LIBRARIES}) - endif() -endif(WITH_IPP_A) - # --- CUDA --- if(WITH_CUDA) include("${OpenCV_SOURCE_DIR}/cmake/OpenCVDetectCUDA.cmake") diff --git a/cmake/templates/cvconfig.h.in b/cmake/templates/cvconfig.h.in index ce779934ce2a..0f63651c38f1 100644 --- a/cmake/templates/cvconfig.h.in +++ b/cmake/templates/cvconfig.h.in @@ -103,9 +103,6 @@ #cmakedefine HAVE_IPP_ICV #cmakedefine HAVE_IPP_IW -/* Intel IPP Async */ -#cmakedefine HAVE_IPP_A - /* JPEG-2000 codec */ #cmakedefine HAVE_JASPER diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index ff6c18e34d36..1d2c43cbb1e9 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -227,7 +227,6 @@ SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = __cplusplus=1 \ - HAVE_IPP_A=1 \ CVAPI(x)=x \ CV_DOXYGEN= \ CV_EXPORTS= \ diff --git a/doc/tutorials/core/how_to_use_OpenCV_parallel_for_/how_to_use_OpenCV_parallel_for_.markdown b/doc/tutorials/core/how_to_use_OpenCV_parallel_for_/how_to_use_OpenCV_parallel_for_.markdown index fb876dad3b56..835409ce4b11 100644 --- a/doc/tutorials/core/how_to_use_OpenCV_parallel_for_/how_to_use_OpenCV_parallel_for_.markdown +++ b/doc/tutorials/core/how_to_use_OpenCV_parallel_for_/how_to_use_OpenCV_parallel_for_.markdown @@ -1,7 +1,7 @@ How to use the OpenCV parallel_for_ to parallelize your code {#tutorial_how_to_use_OpenCV_parallel_for_} ================================================================== -@prev_tutorial{tutorial_how_to_use_ippa_conversion} +@prev_tutorial{tutorial_interoperability_with_OpenCV_1} Goal ---- diff --git a/doc/tutorials/core/how_to_use_ippa_conversion/how_to_use_ippa_conversion.markdown b/doc/tutorials/core/how_to_use_ippa_conversion/how_to_use_ippa_conversion.markdown deleted file mode 100644 index 4bc56fa7339d..000000000000 --- a/doc/tutorials/core/how_to_use_ippa_conversion/how_to_use_ippa_conversion.markdown +++ /dev/null @@ -1,146 +0,0 @@ -Intel® IPP Asynchronous C/C++ library in OpenCV {#tutorial_how_to_use_ippa_conversion} -=============================================== - -@prev_tutorial{tutorial_interoperability_with_OpenCV_1} -@next_tutorial{tutorial_how_to_use_OpenCV_parallel_for_} - -Goal ----- - -The tutorial demonstrates the [Intel® IPP Asynchronous -C/C++](http://software.intel.com/en-us/intel-ipp-preview) library usage with OpenCV. The code -example below illustrates implementation of the Sobel operation, accelerated with Intel® IPP -Asynchronous C/C++ functions. In this code example, @ref cv::hpp::getMat and @ref cv::hpp::getHpp -functions are used for data conversion between -[hppiMatrix](http://software.intel.com/en-us/node/501660) and Mat matrices. - -Code ----- - -You may also find the source code in the -`samples/cpp/tutorial_code/core/ippasync/ippasync_sample.cpp` file of the OpenCV source library or -download it from [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/core/ippasync/ippasync_sample.cpp). - -@include cpp/tutorial_code/core/ippasync/ippasync_sample.cpp - -Explanation ------------ - --# Create parameters for OpenCV: - @code{.cpp} - VideoCapture cap; - Mat image, gray, result; - @endcode - and IPP Async: - @code{.cpp} - hppiMatrix* src,* dst; - hppAccel accel = 0; - hppAccelType accelType; - hppStatus sts; - hppiVirtualMatrix * virtMatrix; - @endcode --# Load input image or video. How to open and read video stream you can see in the - @ref tutorial_video_input_psnr_ssim tutorial. - @code{.cpp} - if( useCamera ) - { - printf("used camera\n"); - cap.open(0); - } - else - { - printf("used image %s\n", file.c_str()); - cap.open(file.c_str()); - } - - if( !cap.isOpened() ) - { - printf("can not open camera or video file\n"); - return -1; - } - @endcode --# Create accelerator instance using - [hppCreateInstance](http://software.intel.com/en-us/node/501686): - @code{.cpp} - accelType = sAccel == "cpu" ? HPP_ACCEL_TYPE_CPU: - sAccel == "gpu" ? HPP_ACCEL_TYPE_GPU: - HPP_ACCEL_TYPE_ANY; - - //Create accelerator instance - sts = hppCreateInstance(accelType, 0, &accel); - CHECK_STATUS(sts, "hppCreateInstance"); - @endcode --# Create an array of virtual matrices using - [hppiCreateVirtualMatrices](http://software.intel.com/en-us/node/501700) function. - @code{.cpp} - virtMatrix = hppiCreateVirtualMatrices(accel, 1); - @endcode --# Prepare a matrix for input and output data: - @code{.cpp} - cap >> image; - if(image.empty()) - break; - - cvtColor( image, gray, COLOR_BGR2GRAY ); - - result.create( image.rows, image.cols, CV_8U); - @endcode --# Convert Mat to [hppiMatrix](http://software.intel.com/en-us/node/501660) using @ref cv::hpp::getHpp - and call [hppiSobel](http://software.intel.com/en-us/node/474701) function. - @code{.cpp} - //convert Mat to hppiMatrix - src = getHpp(gray, accel); - dst = getHpp(result, accel); - - sts = hppiSobel(accel,src, HPP_MASK_SIZE_3X3,HPP_NORM_L1,virtMatrix[0]); - CHECK_STATUS(sts,"hppiSobel"); - - sts = hppiConvert(accel, virtMatrix[0], 0, HPP_RND_MODE_NEAR, dst, HPP_DATA_TYPE_8U); - CHECK_STATUS(sts,"hppiConvert"); - - // Wait for tasks to complete - sts = hppWait(accel, HPP_TIME_OUT_INFINITE); - CHECK_STATUS(sts, "hppWait"); - @endcode - We use [hppiConvert](http://software.intel.com/en-us/node/501746) because - [hppiSobel](http://software.intel.com/en-us/node/474701) returns destination matrix with - HPP_DATA_TYPE_16S data type for source matrix with HPP_DATA_TYPE_8U type. You should check - hppStatus after each call IPP Async function. - --# Create windows and show the images, the usual way. - @code{.cpp} - imshow("image", image); - imshow("rez", result); - - waitKey(15); - @endcode --# Delete hpp matrices. - @code{.cpp} - sts = hppiFreeMatrix(src); - CHECK_DEL_STATUS(sts,"hppiFreeMatrix"); - - sts = hppiFreeMatrix(dst); - CHECK_DEL_STATUS(sts,"hppiFreeMatrix"); - @endcode --# Delete virtual matrices and accelerator instance. - @code{.cpp} - if (virtMatrix) - { - sts = hppiDeleteVirtualMatrices(accel, virtMatrix); - CHECK_DEL_STATUS(sts,"hppiDeleteVirtualMatrices"); - } - - if (accel) - { - sts = hppDeleteInstance(accel); - CHECK_DEL_STATUS(sts, "hppDeleteInstance"); - } - @endcode - -Result ------- - -After compiling the code above we can execute it giving an image or video path and accelerator type -as an argument. For this tutorial we use baboon.png image as input. The result is below. - -![](images/How_To_Use_IPPA_Result.jpg) diff --git a/doc/tutorials/core/how_to_use_ippa_conversion/images/How_To_Use_IPPA_Result.jpg b/doc/tutorials/core/how_to_use_ippa_conversion/images/How_To_Use_IPPA_Result.jpg deleted file mode 100644 index 2bdeb830cb43..000000000000 Binary files a/doc/tutorials/core/how_to_use_ippa_conversion/images/How_To_Use_IPPA_Result.jpg and /dev/null differ diff --git a/doc/tutorials/core/images/How_To_Use_IPPA.jpg b/doc/tutorials/core/images/How_To_Use_IPPA.jpg deleted file mode 100644 index 8bba60530201..000000000000 Binary files a/doc/tutorials/core/images/How_To_Use_IPPA.jpg and /dev/null differ diff --git a/doc/tutorials/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.markdown b/doc/tutorials/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.markdown index 8895415164c7..6642144e7046 100644 --- a/doc/tutorials/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.markdown +++ b/doc/tutorials/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.markdown @@ -2,7 +2,7 @@ Interoperability with OpenCV 1 {#tutorial_interoperability_with_OpenCV_1} ============================== @prev_tutorial{tutorial_file_input_output_with_xml_yml} -@next_tutorial{tutorial_how_to_use_ippa_conversion} +@next_tutorial{tutorial_how_to_use_OpenCV_parallel_for_} Goal ---- diff --git a/doc/tutorials/core/table_of_content_core.markdown b/doc/tutorials/core/table_of_content_core.markdown index f3f5381ea914..d775d8f0ee5c 100644 --- a/doc/tutorials/core/table_of_content_core.markdown +++ b/doc/tutorials/core/table_of_content_core.markdown @@ -93,15 +93,6 @@ understanding how to manipulate the images on a pixel level. Look here to shed light on all this questions. -- @subpage tutorial_how_to_use_ippa_conversion - - *Compatibility:* \> OpenCV 2.0 - - *Author:* Elena Gvozdeva - - You will see how to use the IPP Async with OpenCV. - - - @subpage tutorial_how_to_use_OpenCV_parallel_for_ *Compatibility:* \>= OpenCV 2.4.3 diff --git a/doc/tutorials/imgproc/motion_deblur_filter/images/black_car.jpg b/doc/tutorials/imgproc/motion_deblur_filter/images/black_car.jpg new file mode 100755 index 000000000000..1305057729f6 Binary files /dev/null and b/doc/tutorials/imgproc/motion_deblur_filter/images/black_car.jpg differ diff --git a/doc/tutorials/imgproc/motion_deblur_filter/images/motion_original.jpg b/doc/tutorials/imgproc/motion_deblur_filter/images/motion_original.jpg new file mode 100755 index 000000000000..6c9b35dd5235 Binary files /dev/null and b/doc/tutorials/imgproc/motion_deblur_filter/images/motion_original.jpg differ diff --git a/doc/tutorials/imgproc/motion_deblur_filter/images/motion_psf.png b/doc/tutorials/imgproc/motion_deblur_filter/images/motion_psf.png new file mode 100755 index 000000000000..eb455e7e6ce3 Binary files /dev/null and b/doc/tutorials/imgproc/motion_deblur_filter/images/motion_psf.png differ diff --git a/doc/tutorials/imgproc/motion_deblur_filter/images/white_car.jpg b/doc/tutorials/imgproc/motion_deblur_filter/images/white_car.jpg new file mode 100755 index 000000000000..fd9f46faec26 Binary files /dev/null and b/doc/tutorials/imgproc/motion_deblur_filter/images/white_car.jpg differ diff --git a/doc/tutorials/imgproc/motion_deblur_filter/motion_deblur_filter.markdown b/doc/tutorials/imgproc/motion_deblur_filter/motion_deblur_filter.markdown new file mode 100755 index 000000000000..2821e413cd3e --- /dev/null +++ b/doc/tutorials/imgproc/motion_deblur_filter/motion_deblur_filter.markdown @@ -0,0 +1,72 @@ +Motion Deblur Filter {#tutorial_motion_deblur_filter} +========================== + +Goal +---- + +In this tutorial you will learn: + +- what the PSF of a motion blur image is +- how to restore a motion blur image + +Theory +------ + +For the degradation image model theory and the Wiener filter theory you can refer to the tutorial @ref tutorial_out_of_focus_deblur_filter "Out-of-focus Deblur Filter". +On this page only a linear motion blur distortion is considered. The motion blur image on this page is a real world image. The blur was caused by a moving subject. + +### What is the PSF of a motion blur image? + +The point spread function (PSF) of a linear motion blur distortion is a line segment. Such a PSF is specified by two parameters: \f$LEN\f$ is the length of the blur and \f$THETA\f$ is the angle of motion. + +![Point spread function of a linear motion blur distortion](images/motion_psf.png) + +### How to restore a blurred image? + +On this page the Wiener filter is used as the restoration filter, for details you can refer to the tutorial @ref tutorial_out_of_focus_deblur_filter "Out-of-focus Deblur Filter". +In order to synthesize the Wiener filter for a motion blur case, it needs to specify the signal-to-noise ratio (\f$SNR\f$), \f$LEN\f$ and \f$THETA\f$ of the PSF. + +Source code +----------- + +You can find source code in the `samples/cpp/tutorial_code/ImgProc/motion_deblur_filter/motion_deblur_filter.cpp` of the OpenCV source code library. + +@include cpp/tutorial_code/ImgProc/motion_deblur_filter/motion_deblur_filter.cpp + +Explanation +----------- + +A motion blur image recovering algorithm consists of PSF generation, Wiener filter generation and filtering a blurred image in a frequency domain: +@snippet samples/cpp/tutorial_code/ImgProc/motion_deblur_filter/motion_deblur_filter.cpp main + +A function calcPSF() forms a PSF according to input parameters \f$LEN\f$ and \f$THETA\f$ (in degrees): +@snippet samples/cpp/tutorial_code/ImgProc/motion_deblur_filter/motion_deblur_filter.cpp calcPSF + +A function edgetaper() tapers the input image’s edges in order to reduce the ringing effect in a restored image: +@snippet samples/cpp/tutorial_code/ImgProc/motion_deblur_filter/motion_deblur_filter.cpp edgetaper + +The functions calcWnrFilter(), fftshift() and filter2DFreq() realize an image filtration by a specified PSF in the frequency domain. The functions are copied from the tutorial +@ref tutorial_out_of_focus_deblur_filter "Out-of-focus Deblur Filter". + +Result +------ + +Below you can see the real world image with motion blur distortion. The license plate is not readable on both cars. The red markers show the car’s license plate location. +![Motion blur image. The license plates are not readable](images/motion_original.jpg) + + +Below you can see the restoration result for the black car license plate. The result has been computed with \f$LEN\f$ = 125, \f$THETA\f$ = 0, \f$SNR\f$ = 700. +![The restored image of the black car license plate](images/black_car.jpg) + +Below you can see the restoration result for the white car license plate. The result has been computed with \f$LEN\f$ = 78, \f$THETA\f$ = 15, \f$SNR\f$ = 300. +![The restored image of the white car license plate](images/white_car.jpg) + +The values of \f$SNR\f$, \f$LEN\f$ and \f$THETA\f$ were selected manually to give the best possible visual result. The \f$THETA\f$ parameter coincides with the car’s moving direction, and the +\f$LEN\f$ parameter depends on the car’s moving speed. +The result is not perfect, but at least it gives us a hint of the image’s content. With some effort, the car license plate is now readable. + +@note The parameters \f$LEN\f$ and \f$THETA\f$ are the most important. You should adjust \f$LEN\f$ and \f$THETA\f$ first, then \f$SNR\f$. + +You can also find a quick video demonstration of a license plate recovering method +[YouTube](https://youtu.be/xSrE0hdhb4o). +@youtube{xSrE0hdhb4o} diff --git a/doc/tutorials/imgproc/out_of_focus_deblur_filter/out_of_focus_deblur_filter.markdown b/doc/tutorials/imgproc/out_of_focus_deblur_filter/out_of_focus_deblur_filter.markdown index 993442168d56..0e1da4efaed3 100755 --- a/doc/tutorials/imgproc/out_of_focus_deblur_filter/out_of_focus_deblur_filter.markdown +++ b/doc/tutorials/imgproc/out_of_focus_deblur_filter/out_of_focus_deblur_filter.markdown @@ -8,54 +8,54 @@ Goal In this tutorial you will learn: -- what is a degradation image model -- what is PSF of out-of-focus image +- what a degradation image model is +- what the PSF of an out-of-focus image is - how to restore a blurred image -- what is Wiener filter +- what is a Wiener filter Theory ------ -@note The explanation is based on the books @cite gonzalez and @cite gruzman. Also, you can refer to Matlab's tutorial [Image Deblurring in Matlab] and an article [SmartDeblur]. -@note An out-of-focus image on this page is a real world image. An out-of-focus was done manually by camera optics. +@note The explanation is based on the books @cite gonzalez and @cite gruzman. Also, you can refer to Matlab's tutorial [Image Deblurring in Matlab] and the article [SmartDeblur]. +@note The out-of-focus image on this page is a real world image. The out-of-focus was achieved manually by camera optics. ### What is a degradation image model? -A mathematical model of the image degradation in frequency domain representation is: +Here is a mathematical model of the image degradation in frequency domain representation: \f[S = H\cdot U + N\f] where \f$S\f$ is a spectrum of blurred (degraded) image, \f$U\f$ is a spectrum of original true (undegraded) image, -\f$H\f$ is frequency response of point spread function (PSF), +\f$H\f$ is a frequency response of point spread function (PSF), \f$N\f$ is a spectrum of additive noise. -Circular PSF is a good approximation of out-of-focus distortion. Such PSF is specified by only one parameter - radius \f$R\f$. Circular PSF is used in this work. +The circular PSF is a good approximation of out-of-focus distortion. Such a PSF is specified by only one parameter - radius \f$R\f$. Circular PSF is used in this work. ![Circular point spread function](psf.png) -### How to restore an blurred image? +### How to restore a blurred image? -The objective of restoration (deblurring) is to obtain an estimate of the original image. Restoration formula in frequency domain is: +The objective of restoration (deblurring) is to obtain an estimate of the original image. The restoration formula in frequency domain is: \f[U' = H_w\cdot S\f] where -\f$U'\f$ is spectrum of estimation of original image \f$U\f$, -\f$H_w\f$ is restoration filter, for example, Wiener filter. +\f$U'\f$ is the spectrum of estimation of original image \f$U\f$, and +\f$H_w\f$ is the restoration filter, for example, the Wiener filter. -### What is Wiener filter? +### What is the Wiener filter? -Wiener filter is a way to restore a blurred image. Let's suppose that PSF is a real and symmetric signal, a power spectrum of the original true image and noise are not known, -then simplified Wiener formula is: +The Wiener filter is a way to restore a blurred image. Let's suppose that the PSF is a real and symmetric signal, a power spectrum of the original true image and noise are not known, +then a simplified Wiener formula is: \f[H_w = \frac{H}{|H|^2+\frac{1}{SNR}} \f] where \f$SNR\f$ is signal-to-noise ratio. -So, in order to recover an out-of-focus image by Wiener filter, it needs to know \f$SNR\f$ and \f$R\f$ of circular PSF. +So, in order to recover an out-of-focus image by Wiener filter, it needs to know the \f$SNR\f$ and \f$R\f$ of the circular PSF. Source code @@ -68,36 +68,36 @@ You can find source code in the `samples/cpp/tutorial_code/ImgProc/out_of_focus_ Explanation ----------- -An out-of-focus image recovering algorithm consists of PSF generation, Wiener filter generation and filtering an blurred image in frequency domain: +An out-of-focus image recovering algorithm consists of PSF generation, Wiener filter generation and filtering a blurred image in frequency domain: @snippet samples/cpp/tutorial_code/ImgProc/out_of_focus_deblur_filter/out_of_focus_deblur_filter.cpp main -A function calcPSF() forms an circular PSF according to input parameter radius \f$R\f$: +A function calcPSF() forms a circular PSF according to input parameter radius \f$R\f$: @snippet samples/cpp/tutorial_code/ImgProc/out_of_focus_deblur_filter/out_of_focus_deblur_filter.cpp calcPSF -A function calcWnrFilter() synthesizes simplified Wiener filter \f$H_w\f$ according to formula described above: +A function calcWnrFilter() synthesizes the simplified Wiener filter \f$H_w\f$ according to the formula described above: @snippet samples/cpp/tutorial_code/ImgProc/out_of_focus_deblur_filter/out_of_focus_deblur_filter.cpp calcWnrFilter -A function fftshift() rearranges PSF. This code was just copied from tutorial @ref tutorial_discrete_fourier_transform "Discrete Fourier Transform": +A function fftshift() rearranges the PSF. This code was just copied from the tutorial @ref tutorial_discrete_fourier_transform "Discrete Fourier Transform": @snippet samples/cpp/tutorial_code/ImgProc/out_of_focus_deblur_filter/out_of_focus_deblur_filter.cpp fftshift -A function filter2DFreq() filters an blurred image in frequency domain: +A function filter2DFreq() filters the blurred image in the frequency domain: @snippet samples/cpp/tutorial_code/ImgProc/out_of_focus_deblur_filter/out_of_focus_deblur_filter.cpp filter2DFreq Result ------ -Below you can see real out-of-focus image: +Below you can see the real out-of-focus image: ![Out-of-focus image](images/original.jpg) -Below result was done by \f$R\f$ = 53 and \f$SNR\f$ = 5200 parameters: +And the following result has been computed with \f$R\f$ = 53 and \f$SNR\f$ = 5200 parameters: ![The restored (deblurred) image](images/recovered.jpg) -The Wiener filter was used, values of \f$R\f$ and \f$SNR\f$ were selected manually to give the best possible visual result. -We can see that the result is not perfect, but it gives us a hint to the image content. With some difficulty, the text is readable. +The Wiener filter was used, and values of \f$R\f$ and \f$SNR\f$ were selected manually to give the best possible visual result. +We can see that the result is not perfect, but it gives us a hint to the image's content. With some difficulty, the text is readable. @note The parameter \f$R\f$ is the most important. So you should adjust \f$R\f$ first, then \f$SNR\f$. -@note Sometimes you can observe the ringing effect in an restored image. This effect can be reduced by several methods. For example, you can taper input image edges. +@note Sometimes you can observe the ringing effect in a restored image. This effect can be reduced with several methods. For example, you can taper input image edges. You can also find a quick video demonstration of this on [YouTube](https://youtu.be/0bEcE4B0XP4). diff --git a/doc/tutorials/imgproc/table_of_content_imgproc.markdown b/doc/tutorials/imgproc/table_of_content_imgproc.markdown index e90df59bce0d..bea1e1b9ac7d 100644 --- a/doc/tutorials/imgproc/table_of_content_imgproc.markdown +++ b/doc/tutorials/imgproc/table_of_content_imgproc.markdown @@ -320,3 +320,13 @@ In this section you will learn about the image processing (manipulation) functio *Author:* Karpushin Vladislav You will learn how to recover an out-of-focus image by Wiener filter. + +- @subpage tutorial_motion_deblur_filter + + *Languages:* C++ + + *Compatibility:* \> OpenCV 2.0 + + *Author:* Karpushin Vladislav + + You will learn how to recover an image with motion blur distortion using a Wiener filter. diff --git a/doc/tutorials/introduction/windows_install/windows_install.markdown b/doc/tutorials/introduction/windows_install/windows_install.markdown index 7f491d8fdd7d..c8f46cbdced2 100644 --- a/doc/tutorials/introduction/windows_install/windows_install.markdown +++ b/doc/tutorials/introduction/windows_install/windows_install.markdown @@ -142,8 +142,6 @@ of them, you need to download and install them on your system. - [Intel Integrated Performance Primitives (*IPP*)](http://software.intel.com/en-us/articles/intel-ipp/) may be used to improve the performance of color conversion, Haar training and DFT functions of the OpenCV library. Watch out, since this is not a free service. -- [Intel IPP Asynchronous C/C++](http://software.intel.com/en-us/intel-ipp-preview) is currently focused delivering Intel Graphics - support for advanced image processing and computer vision functions. - OpenCV offers a somewhat fancier and more useful graphical user interface, than the default one by using the [Qt framework](http://qt.nokia.com/downloads). For a quick overview of what this has to offer, look into the documentations *highgui* module, under the *Qt New Functions* section. Version 4.6 or later of @@ -204,10 +202,6 @@ libraries). If you do not need the support for some of these, you can just freel ![](images/IntelTBB.png) - -# For the [Intel IPP Asynchronous C/C++](http://software.intel.com/en-us/intel-ipp-preview) download the source files and set environment - variable **IPP_ASYNC_ROOT**. It should point to - `/Intel/IPP Preview */ipp directory`. Here \* denotes the - particular preview name. -# In case of the [Eigen](http://eigen.tuxfamily.org/index.php?title=Main_Page#Download) library it is again a case of download and extract to the `D:/OpenCV/dep` directory. -# Same as above with [OpenEXR](http://www.openexr.com/downloads.html). @@ -319,6 +313,7 @@ libraries). If you do not need the support for some of these, you can just freel you are concerned about performance, build them and run. - *BUILD_opencv_python* -\> Self-explanatory. Create the binaries to use OpenCV from the Python language. + - *BUILD_opencv_world* -\> Generate a single "opencv_world" binary (a shared or static library, depending on *BUILD_SHARED_LIBS*) including all the modules instead of a collection of separate binaries, one binary per module. Press again the *Configure* button and ensure no errors are reported. If this is the case, you can tell CMake to create the project files by pushing the *Generate* button. Go to the build diff --git a/modules/calib3d/src/stereosgbm.cpp b/modules/calib3d/src/stereosgbm.cpp index 374d7353d932..12d3f50bed3e 100644 --- a/modules/calib3d/src/stereosgbm.cpp +++ b/modules/calib3d/src/stereosgbm.cpp @@ -1487,12 +1487,14 @@ static void computeDisparitySGBM_HH4( const Mat& img1, const Mat& img2, size_t minLrSize = width1 , LrSize = minLrSize*D2; int hsumBufNRows = SH2*2 + 2; size_t totalBufSize = (LrSize + minLrSize)*NLR*sizeof(CostType) + // minLr[] and Lr[] - costBufSize*hsumBufNRows*sizeof(CostType) + // hsumBuf - CSBufSize*2*sizeof(CostType) + 1024; // C, S + costBufSize*hsumBufNRows*sizeof(CostType) + // hsumBuf + CSBufSize*2*sizeof(CostType) + 1024; // C, S if( buffer.empty() || !buffer.isContinuous() || buffer.cols*buffer.rows*buffer.elemSize() < totalBufSize ) - buffer.create(1, (int)totalBufSize, CV_8U); + { + buffer.reserveBuffer(totalBufSize); + } // summary cost over different (nDirs) directions CostType* Cbuf = (CostType*)alignPtr(buffer.ptr(), ALIGN); diff --git a/modules/core/include/opencv2/core/hal/intrin_avx.hpp b/modules/core/include/opencv2/core/hal/intrin_avx.hpp index 1c5ffbd1cab2..36c7c0f1a1e2 100644 --- a/modules/core/include/opencv2/core/hal/intrin_avx.hpp +++ b/modules/core/include/opencv2/core/hal/intrin_avx.hpp @@ -664,6 +664,8 @@ inline void v_mul_expand(const v_uint32x8& a, const v_uint32x8& b, v_zip(v_uint64x4(v0), v_uint64x4(v1), c, d); } +inline v_int16x16 v_mul_hi(const v_int16x16& a, const v_int16x16& b) { return v_int16x16(_mm256_mulhi_epi16(a.val, b.val)); } +inline v_uint16x16 v_mul_hi(const v_uint16x16& a, const v_uint16x16& b) { return v_uint16x16(_mm256_mulhi_epu16(a.val, b.val)); } /** Non-saturating arithmetics **/ #define OPENCV_HAL_IMPL_AVX_BIN_FUNC(func, _Tpvec, intrin) \ diff --git a/modules/core/include/opencv2/core/hal/intrin_cpp.hpp b/modules/core/include/opencv2/core/hal/intrin_cpp.hpp index 61d58dbb06e2..ccd317682d49 100644 --- a/modules/core/include/opencv2/core/hal/intrin_cpp.hpp +++ b/modules/core/include/opencv2/core/hal/intrin_cpp.hpp @@ -891,6 +891,20 @@ template inline void v_mul_expand(const v_reg<_Tp, n>& a, c } } +/** @brief Multiply and extract high part + +Multiply values two registers and store high part of the results. +Implemented only for 16-bit source types (v_int16x8, v_uint16x8). Returns \f$ a*b >> 16 \f$ +*/ +template inline v_reg<_Tp, n> v_mul_hi(const v_reg<_Tp, n>& a, const v_reg<_Tp, n>& b) +{ + typedef typename V_TypeTraits<_Tp>::w_type w_type; + v_reg<_Tp, n> c; + for (int i = 0; i < n; i++) + c.s[i] = (_Tp)(((w_type)a.s[i] * b.s[i]) >> sizeof(_Tp)*8); + return c; +} + //! @cond IGNORED template inline void v_hsum(const v_reg<_Tp, n>& a, v_reg::w_type, n/2>& c) diff --git a/modules/core/include/opencv2/core/hal/intrin_neon.hpp b/modules/core/include/opencv2/core/hal/intrin_neon.hpp index 04b6ba225930..c017b075f138 100644 --- a/modules/core/include/opencv2/core/hal/intrin_neon.hpp +++ b/modules/core/include/opencv2/core/hal/intrin_neon.hpp @@ -553,6 +553,21 @@ inline void v_mul_expand(const v_uint32x4& a, const v_uint32x4& b, d.val = vmull_u32(vget_high_u32(a.val), vget_high_u32(b.val)); } +inline v_int16x8 v_mul_hi(const v_int16x8& a, const v_int16x8& b) +{ + return v_int16x8(vcombine_s16( + vshrn_n_s32(vmull_s16( vget_low_s16(a.val), vget_low_s16(b.val)), 16), + vshrn_n_s32(vmull_s16(vget_high_s16(a.val), vget_high_s16(b.val)), 16) + )); +} +inline v_uint16x8 v_mul_hi(const v_uint16x8& a, const v_uint16x8& b) +{ + return v_uint16x8(vcombine_u16( + vshrn_n_u32(vmull_u16( vget_low_u16(a.val), vget_low_u16(b.val)), 16), + vshrn_n_u32(vmull_u16(vget_high_u16(a.val), vget_high_u16(b.val)), 16) + )); +} + inline v_int32x4 v_dotprod(const v_int16x8& a, const v_int16x8& b) { int32x4_t c = vmull_s16(vget_low_s16(a.val), vget_low_s16(b.val)); diff --git a/modules/core/include/opencv2/core/hal/intrin_sse.hpp b/modules/core/include/opencv2/core/hal/intrin_sse.hpp index 42a39d07f974..159ef356b52d 100644 --- a/modules/core/include/opencv2/core/hal/intrin_sse.hpp +++ b/modules/core/include/opencv2/core/hal/intrin_sse.hpp @@ -737,6 +737,9 @@ inline void v_mul_expand(const v_uint32x4& a, const v_uint32x4& b, d.val = _mm_unpackhi_epi64(c0, c1); } +inline v_int16x8 v_mul_hi(const v_int16x8& a, const v_int16x8& b) { return v_int16x8(_mm_mulhi_epi16(a.val, b.val)); } +inline v_uint16x8 v_mul_hi(const v_uint16x8& a, const v_uint16x8& b) { return v_uint16x8(_mm_mulhi_epu16(a.val, b.val)); } + inline v_int32x4 v_dotprod(const v_int16x8& a, const v_int16x8& b) { return v_int32x4(_mm_madd_epi16(a.val, b.val)); diff --git a/modules/core/include/opencv2/core/hal/intrin_vsx.hpp b/modules/core/include/opencv2/core/hal/intrin_vsx.hpp index 52bc2cc0baf6..a45e7a875fe2 100644 --- a/modules/core/include/opencv2/core/hal/intrin_vsx.hpp +++ b/modules/core/include/opencv2/core/hal/intrin_vsx.hpp @@ -457,6 +457,21 @@ inline void v_mul_expand(const v_uint32x4& a, const v_uint32x4& b, v_uint64x2& c d.val = vec_mul(vec_unpacklu(a.val), vec_unpacklu(b.val)); } +inline v_int16x8 v_mul_hi(const v_int16x8& a, const v_int16x8& b) +{ + return v_int16x8(vec_packs( + vec_sra(vec_mul(vec_unpackh(a.val), vec_unpackh(b.val)), vec_uint4_sp(16)), + vec_sra(vec_mul(vec_unpackl(a.val), vec_unpackl(b.val)), vec_uint4_sp(16)) + )); +} +inline v_uint16x8 v_mul_hi(const v_uint16x8& a, const v_uint16x8& b) +{ + return v_uint16x8(vec_packs( + vec_sr(vec_mul(vec_unpackhu(a.val), vec_unpackhu(b.val)), vec_uint4_sp(16)), + vec_sr(vec_mul(vec_unpacklu(a.val), vec_unpacklu(b.val)), vec_uint4_sp(16)) + )); +} + /** Non-saturating arithmetics **/ #define OPENCV_HAL_IMPL_VSX_BIN_FUNC(func, intrin) \ template \ diff --git a/modules/core/include/opencv2/core/ippasync.hpp b/modules/core/include/opencv2/core/ippasync.hpp index 0ed8264e1483..c35d8d81a19c 100644 --- a/modules/core/include/opencv2/core/ippasync.hpp +++ b/modules/core/include/opencv2/core/ippasync.hpp @@ -45,7 +45,7 @@ #ifndef OPENCV_CORE_IPPASYNC_HPP #define OPENCV_CORE_IPPASYNC_HPP -#ifdef HAVE_IPP_A +#ifdef HAVE_IPP_A // this file will be removed in OpenCV 4.0 #include "opencv2/core.hpp" #include diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index 1884abd66c0e..d918ee965206 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -146,6 +146,12 @@ synonym is needed to generate Python/Java etc. wrappers properly. At the functio level their use is similar, but _InputArray::getMat(idx) should be used to get header for the idx-th component of the outer vector and _InputArray::size().area() should be used to find the number of components (vectors/matrices) of the outer vector. + +In general, type support is limited to cv::Mat types. Other types are forbidden. +But in some cases we need to support passing of custom non-general Mat types, like arrays of cv::KeyPoint, cv::DMatch, etc. +This data is not intented to be interpreted as an image data, or processed somehow like regular cv::Mat. +To pass such custom type use rawIn() / rawOut() / rawInOut() wrappers. +Custom type is wrapped as Mat-compatible `CV_8UC` values (N = sizeof(T), N <= CV_CN_MAX). */ class CV_EXPORTS _InputArray { @@ -199,6 +205,9 @@ class CV_EXPORTS _InputArray template _InputArray(const std::array<_Tp, _Nm>& arr); template _InputArray(const std::array& arr); + template static _InputArray rawIn(const std::vector<_Tp>& vec); + template static _InputArray rawIn(const std::array<_Tp, _Nm>& arr); + Mat getMat(int idx=-1) const; Mat getMat_(int idx=-1) const; UMat getUMat(int idx=-1) const; @@ -328,12 +337,13 @@ class CV_EXPORTS _OutputArray : public _InputArray _OutputArray(const UMat& m); _OutputArray(const std::vector& vec); -#ifdef CV_CXX_STD_ARRAY template _OutputArray(std::array<_Tp, _Nm>& arr); template _OutputArray(const std::array<_Tp, _Nm>& arr); template _OutputArray(std::array& arr); template _OutputArray(const std::array& arr); -#endif + + template static _OutputArray rawOut(std::vector<_Tp>& vec); + template static _OutputArray rawOut(std::array<_Tp, _Nm>& arr); bool fixedSize() const; bool fixedType() const; @@ -397,15 +407,23 @@ class CV_EXPORTS _InputOutputArray : public _OutputArray _InputOutputArray(const UMat& m); _InputOutputArray(const std::vector& vec); -#ifdef CV_CXX_STD_ARRAY template _InputOutputArray(std::array<_Tp, _Nm>& arr); template _InputOutputArray(const std::array<_Tp, _Nm>& arr); template _InputOutputArray(std::array& arr); template _InputOutputArray(const std::array& arr); -#endif + + template static _InputOutputArray rawInOut(std::vector<_Tp>& vec); + template _InputOutputArray rawInOut(std::array<_Tp, _Nm>& arr); }; +/** Helper to wrap custom types. @see InputArray */ +template static inline _InputArray rawIn(_Tp& v); +/** Helper to wrap custom types. @see InputArray */ +template static inline _OutputArray rawOut(_Tp& v); +/** Helper to wrap custom types. @see InputArray */ +template static inline _InputOutputArray rawInOut(_Tp& v); + CV__DEBUG_NS_END typedef const _InputArray& InputArray; @@ -991,11 +1009,9 @@ class CV_EXPORTS Mat */ template explicit Mat(const std::initializer_list sizes, const std::initializer_list<_Tp> list); -#ifdef CV_CXX_STD_ARRAY /** @overload */ template explicit Mat(const std::array<_Tp, _Nm>& arr, bool copyData=false); -#endif /** @overload */ @@ -1630,9 +1646,7 @@ class CV_EXPORTS Mat template operator Vec<_Tp, n>() const; template operator Matx<_Tp, m, n>() const; -#ifdef CV_CXX_STD_ARRAY template operator std::array<_Tp, _Nm>() const; -#endif /** @brief Reports whether the matrix is continuous or not. @@ -2214,9 +2228,7 @@ template class Mat_ : public Mat Mat_(std::initializer_list<_Tp> values); explicit Mat_(const std::initializer_list sizes, const std::initializer_list<_Tp> values); -#ifdef CV_CXX_STD_ARRAY template explicit Mat_(const std::array<_Tp, _Nm>& arr, bool copyData=false); -#endif Mat_& operator = (const Mat& m); Mat_& operator = (const Mat_& m); @@ -2314,10 +2326,8 @@ template class Mat_ : public Mat //! conversion to vector. operator std::vector<_Tp>() const; -#ifdef CV_CXX_STD_ARRAY //! conversion to array. template operator std::array<_Tp, _Nm>() const; -#endif //! conversion to Vec template operator Vec::channel_type, n>() const; diff --git a/modules/core/include/opencv2/core/mat.inl.hpp b/modules/core/include/opencv2/core/mat.inl.hpp index 609f4bd57b35..d28a6251d742 100644 --- a/modules/core/include/opencv2/core/mat.inl.hpp +++ b/modules/core/include/opencv2/core/mat.inl.hpp @@ -61,6 +61,16 @@ CV__DEBUG_NS_BEGIN //! @cond IGNORED +////////////////////////// Custom (raw) type wrapper ////////////////////////// + +template static inline +int rawType() +{ + CV_StaticAssert(sizeof(_Tp) <= CV_CN_MAX, "sizeof(_Tp) is too large"); + const int elemSize = sizeof(_Tp); + return (int)CV_MAKETYPE(CV_8U, elemSize); +} + //////////////////////// Input/Output Arrays //////////////////////// inline void _InputArray::init(int _flags, const void* _obj) @@ -134,6 +144,25 @@ inline _InputArray::_InputArray(const ogl::Buffer& buf) inline _InputArray::_InputArray(const cuda::HostMem& cuda_mem) { init(CUDA_HOST_MEM + ACCESS_READ, &cuda_mem); } +template inline +_InputArray _InputArray::rawIn(const std::vector<_Tp>& vec) +{ + _InputArray v; + v.flags = _InputArray::FIXED_TYPE + _InputArray::STD_VECTOR + rawType<_Tp>() + ACCESS_READ; + v.obj = (void*)&vec; + return v; +} + +template inline +_InputArray _InputArray::rawIn(const std::array<_Tp, _Nm>& arr) +{ + _InputArray v; + v.flags = FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_READ; + v.obj = (void*)arr.data(); + v.sz = Size(1, _Nm); + return v; +} + inline _InputArray::~_InputArray() {} inline Mat _InputArray::getMat(int i) const @@ -261,6 +290,25 @@ inline _OutputArray::_OutputArray(const ogl::Buffer& buf) inline _OutputArray::_OutputArray(const cuda::HostMem& cuda_mem) { init(FIXED_TYPE + FIXED_SIZE + CUDA_HOST_MEM + ACCESS_WRITE, &cuda_mem); } +template inline +_OutputArray _OutputArray::rawOut(std::vector<_Tp>& vec) +{ + _OutputArray v; + v.flags = _InputArray::FIXED_TYPE + _InputArray::STD_VECTOR + rawType<_Tp>() + ACCESS_WRITE; + v.obj = (void*)&vec; + return v; +} + +template inline +_OutputArray _OutputArray::rawOut(std::array<_Tp, _Nm>& arr) +{ + _OutputArray v; + v.flags = FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_WRITE; + v.obj = (void*)arr.data(); + v.sz = Size(1, _Nm); + return v; +} + /////////////////////////////////////////////////////////////////////////////////////////// inline _InputOutputArray::_InputOutputArray() { init(ACCESS_RW, 0); } @@ -370,6 +418,30 @@ inline _InputOutputArray::_InputOutputArray(const ogl::Buffer& buf) inline _InputOutputArray::_InputOutputArray(const cuda::HostMem& cuda_mem) { init(FIXED_TYPE + FIXED_SIZE + CUDA_HOST_MEM + ACCESS_RW, &cuda_mem); } +template inline +_InputOutputArray _InputOutputArray::rawInOut(std::vector<_Tp>& vec) +{ + _InputOutputArray v; + v.flags = _InputArray::FIXED_TYPE + _InputArray::STD_VECTOR + rawType<_Tp>() + ACCESS_RW; + v.obj = (void*)&vec; + return v; +} + +template inline +_InputOutputArray _InputOutputArray::rawInOut(std::array<_Tp, _Nm>& arr) +{ + _InputOutputArray v; + v.flags = FIXED_TYPE + FIXED_SIZE + STD_ARRAY + traits::Type<_Tp>::value + ACCESS_RW; + v.obj = (void*)arr.data(); + v.sz = Size(1, _Nm); + return v; +} + + +template static inline _InputArray rawIn(_Tp& v) { return _InputArray::rawIn(v); } +template static inline _OutputArray rawOut(_Tp& v) { return _OutputArray::rawOut(v); } +template static inline _InputOutputArray rawInOut(_Tp& v) { return _InputOutputArray::rawInOut(v); } + CV__DEBUG_NS_END //////////////////////////////////////////// Mat ////////////////////////////////////////// diff --git a/modules/core/src/arithm.cpp b/modules/core/src/arithm.cpp index 1a464c9aeccc..be368ce7611f 100644 --- a/modules/core/src/arithm.cpp +++ b/modules/core/src/arithm.cpp @@ -270,7 +270,7 @@ static void binary_op( InputArray _src1, InputArray _src2, OutputArray _dst, if( !haveScalar ) { const Mat* arrays[] = { &src1, &src2, &dst, &mask, 0 }; - uchar* ptrs[4]{}; + uchar* ptrs[4] = {}; NAryMatIterator it(arrays, ptrs); size_t total = it.size, blocksize = total; @@ -306,7 +306,7 @@ static void binary_op( InputArray _src1, InputArray _src2, OutputArray _dst, else { const Mat* arrays[] = { &src1, &dst, &mask, 0 }; - uchar* ptrs[3]{}; + uchar* ptrs[3] = {}; NAryMatIterator it(arrays, ptrs); size_t total = it.size, blocksize = std::min(total, blocksize0); @@ -745,7 +745,7 @@ static void arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst, if( !haveScalar ) { const Mat* arrays[] = { &src1, &src2, &dst, &mask, 0 }; - uchar* ptrs[4]{}; + uchar* ptrs[4] = {}; NAryMatIterator it(arrays, ptrs); size_t total = it.size, blocksize = total; @@ -812,7 +812,7 @@ static void arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst, else { const Mat* arrays[] = { &src1, &dst, &mask, 0 }; - uchar* ptrs[3]{}; + uchar* ptrs[3] = {}; NAryMatIterator it(arrays, ptrs); size_t total = it.size, blocksize = std::min(total, blocksize0); @@ -1240,7 +1240,7 @@ void cv::compare(InputArray _src1, InputArray _src2, OutputArray _dst, int op) if( !haveScalar ) { const Mat* arrays[] = { &src1, &src2, &dst, 0 }; - uchar* ptrs[3]{}; + uchar* ptrs[3] = {}; NAryMatIterator it(arrays, ptrs); size_t total = it.size; @@ -1251,7 +1251,7 @@ void cv::compare(InputArray _src1, InputArray _src2, OutputArray _dst, int op) else { const Mat* arrays[] = { &src1, &dst, 0 }; - uchar* ptrs[2]{}; + uchar* ptrs[2] = {}; NAryMatIterator it(arrays, ptrs); size_t total = it.size, blocksize = std::min(total, blocksize0); @@ -1748,7 +1748,7 @@ void cv::inRange(InputArray _src, InputArray _lowerb, const Mat* arrays_sc[] = { &src, &dst, 0 }; const Mat* arrays_nosc[] = { &src, &dst, &lb, &ub, 0 }; - uchar* ptrs[4]{}; + uchar* ptrs[4] = {}; NAryMatIterator it(lbScalar && ubScalar ? arrays_sc : arrays_nosc, ptrs); size_t total = it.size, blocksize = std::min(total, blocksize0); diff --git a/modules/core/src/convert.cpp b/modules/core/src/convert.cpp index 7a027dd809ee..75b496719433 100644 --- a/modules/core/src/convert.cpp +++ b/modules/core/src/convert.cpp @@ -1347,7 +1347,7 @@ void cv::Mat::convertTo(OutputArray _dst, int _type, double alpha, double beta) else { const Mat* arrays[] = {&src, &dst, 0}; - uchar* ptrs[2]{}; + uchar* ptrs[2] = {}; NAryMatIterator it(arrays, ptrs); Size sz((int)(it.size*cn), 1); @@ -1496,7 +1496,7 @@ void cv::convertFp16( InputArray _src, OutputArray _dst) else { const Mat* arrays[] = {&src, &dst, 0}; - uchar* ptrs[2]{}; + uchar* ptrs[2] = {}; NAryMatIterator it(arrays, ptrs); Size sz((int)(it.size*cn), 1); diff --git a/modules/core/src/convert_scale.cpp b/modules/core/src/convert_scale.cpp index 44a968ff6c47..25f5a963b7fb 100644 --- a/modules/core/src/convert_scale.cpp +++ b/modules/core/src/convert_scale.cpp @@ -1775,7 +1775,7 @@ void cv::convertScaleAbs( InputArray _src, OutputArray _dst, double alpha, doubl else { const Mat* arrays[] = {&src, &dst, 0}; - uchar* ptrs[2]{}; + uchar* ptrs[2] = {}; NAryMatIterator it(arrays, ptrs); Size sz((int)it.size*cn, 1); diff --git a/modules/core/src/copy.cpp b/modules/core/src/copy.cpp index 66ce393b3fa4..8f93d4bb7290 100644 --- a/modules/core/src/copy.cpp +++ b/modules/core/src/copy.cpp @@ -306,7 +306,7 @@ void Mat::copyTo( OutputArray _dst ) const if( total() != 0 ) { const Mat* arrays[] = { this, &dst }; - uchar* ptrs[2]{}; + uchar* ptrs[2] = {}; NAryMatIterator it(arrays, ptrs, 2); size_t sz = it.size*elemSize(); @@ -399,7 +399,7 @@ void Mat::copyTo( OutputArray _dst, InputArray _mask ) const } const Mat* arrays[] = { this, &dst, &mask, 0 }; - uchar* ptrs[3]{}; + uchar* ptrs[3] = {}; NAryMatIterator it(arrays, ptrs); Size sz((int)(it.size*mcn), 1); diff --git a/modules/core/src/count_non_zero.cpp b/modules/core/src/count_non_zero.cpp index 804d46dc34e0..78d9e6907246 100644 --- a/modules/core/src/count_non_zero.cpp +++ b/modules/core/src/count_non_zero.cpp @@ -25,51 +25,34 @@ static int countNonZero_(const T* src, int len ) static int countNonZero8u( const uchar* src, int len ) { int i=0, nz = 0; -#if CV_SSE2 - if(USE_SSE2)//5x-6x - { - __m128i v_zero = _mm_setzero_si128(); - __m128i sum = _mm_setzero_si128(); - - for (; i<=len-16; i+=16) - { - __m128i r0 = _mm_loadu_si128((const __m128i*)(src+i)); - sum = _mm_add_epi32(sum, _mm_sad_epu8(_mm_sub_epi8(v_zero, _mm_cmpeq_epi8(r0, v_zero)), v_zero)); - } - nz = i - _mm_cvtsi128_si32(_mm_add_epi32(sum, _mm_unpackhi_epi64(sum, sum))); - } -#elif CV_NEON - int len0 = len & -16, blockSize1 = (1 << 8) - 16, blockSize0 = blockSize1 << 6; - uint32x4_t v_nz = vdupq_n_u32(0u); - uint8x16_t v_zero = vdupq_n_u8(0), v_1 = vdupq_n_u8(1); - const uchar * src0 = src; +#if CV_SIMD + int len0 = len & -v_uint8::nlanes; + v_uint8 v_zero = vx_setzero_u8(); + v_uint8 v_one = vx_setall_u8(1); - while( i < len0 ) + v_uint32 v_sum32 = vx_setzero_u32(); + while (i < len0) { - int blockSizei = std::min(len0 - i, blockSize0), j = 0; - - while (j < blockSizei) + v_uint16 v_sum16 = vx_setzero_u16(); + int j = i; + while (j < std::min(len0, i + 65280 * v_uint16::nlanes)) { - int blockSizej = std::min(blockSizei - j, blockSize1), k = 0; - uint8x16_t v_pz = v_zero; - - for( ; k <= blockSizej - 16; k += 16 ) - v_pz = vaddq_u8(v_pz, vandq_u8(vceqq_u8(vld1q_u8(src0 + k), v_zero), v_1)); - - uint16x8_t v_p1 = vmovl_u8(vget_low_u8(v_pz)), v_p2 = vmovl_u8(vget_high_u8(v_pz)); - v_nz = vaddq_u32(vaddl_u16(vget_low_u16(v_p1), vget_high_u16(v_p1)), v_nz); - v_nz = vaddq_u32(vaddl_u16(vget_low_u16(v_p2), vget_high_u16(v_p2)), v_nz); - - src0 += blockSizej; - j += blockSizej; + v_uint8 v_sum8 = vx_setzero_u8(); + int k = j; + for (; k < std::min(len0, j + 255 * v_uint8::nlanes); k += v_uint8::nlanes) + v_sum8 += v_one & (vx_load(src + k) == v_zero); + v_uint16 part1, part2; + v_expand(v_sum8, part1, part2); + v_sum16 += part1 + part2; + j = k; } - - i += blockSizei; + v_uint32 part1, part2; + v_expand(v_sum16, part1, part2); + v_sum32 += part1 + part2; + i = j; } - - CV_DECL_ALIGNED(16) unsigned int buf[4]; - vst1q_u32(buf, v_nz); - nz += i - saturate_cast(buf[0] + buf[1] + buf[2] + buf[3]); + nz = i - v_reduce_sum(v_sum32); + v_cleanup(); #endif for( ; i < len; i++ ) nz += src[i] != 0; @@ -79,159 +62,112 @@ static int countNonZero8u( const uchar* src, int len ) static int countNonZero16u( const ushort* src, int len ) { int i = 0, nz = 0; -#if CV_SSE2 - if (USE_SSE2) - { - __m128i v_zero = _mm_setzero_si128 (); - __m128i sum = _mm_setzero_si128(); +#if CV_SIMD + int len0 = len & -v_int8::nlanes; + v_uint16 v_zero = vx_setzero_u16(); + v_int8 v_one = vx_setall_s8(1); - for ( ; i <= len - 8; i += 8) - { - __m128i r0 = _mm_loadu_si128((const __m128i*)(src + i)); - sum = _mm_add_epi32(sum, _mm_sad_epu8(_mm_sub_epi8(v_zero, _mm_cmpeq_epi16(r0, v_zero)), v_zero)); - } - - nz = i - (_mm_cvtsi128_si32(_mm_add_epi32(sum, _mm_unpackhi_epi64(sum, sum))) >> 1); - src += i; - } -#elif CV_NEON - int len0 = len & -8, blockSize1 = (1 << 15), blockSize0 = blockSize1 << 6; - uint32x4_t v_nz = vdupq_n_u32(0u); - uint16x8_t v_zero = vdupq_n_u16(0), v_1 = vdupq_n_u16(1); - - while( i < len0 ) + v_int32 v_sum32 = vx_setzero_s32(); + while (i < len0) { - int blockSizei = std::min(len0 - i, blockSize0), j = 0; - - while (j < blockSizei) + v_int16 v_sum16 = vx_setzero_s16(); + int j = i; + while (j < std::min(len0, i + 32766 * v_int16::nlanes)) { - int blockSizej = std::min(blockSizei - j, blockSize1), k = 0; - uint16x8_t v_pz = v_zero; - - for( ; k <= blockSizej - 8; k += 8 ) - v_pz = vaddq_u16(v_pz, vandq_u16(vceqq_u16(vld1q_u16(src + k), v_zero), v_1)); - - v_nz = vaddq_u32(vaddl_u16(vget_low_u16(v_pz), vget_high_u16(v_pz)), v_nz); - - src += blockSizej; - j += blockSizej; + v_int8 v_sum8 = vx_setzero_s8(); + int k = j; + for (; k < std::min(len0, j + 127 * v_int8::nlanes); k += v_int8::nlanes) + v_sum8 += v_one & v_pack(v_reinterpret_as_s16(vx_load(src + k) == v_zero), v_reinterpret_as_s16(vx_load(src + k + v_uint16::nlanes) == v_zero)); + v_int16 part1, part2; + v_expand(v_sum8, part1, part2); + v_sum16 += part1 + part2; + j = k; } - - i += blockSizei; + v_int32 part1, part2; + v_expand(v_sum16, part1, part2); + v_sum32 += part1 + part2; + i = j; } - - CV_DECL_ALIGNED(16) unsigned int buf[4]; - vst1q_u32(buf, v_nz); - nz += i - saturate_cast(buf[0] + buf[1] + buf[2] + buf[3]); + nz = i - v_reduce_sum(v_sum32); + v_cleanup(); #endif - return nz + countNonZero_(src, len - i); + return nz + countNonZero_(src + i, len - i); } static int countNonZero32s( const int* src, int len ) { int i = 0, nz = 0; -#if CV_SSE2 - if (USE_SSE2) - { - __m128i v_zero = _mm_setzero_si128 (); - __m128i sum = _mm_setzero_si128(); +#if CV_SIMD + int len0 = len & -v_int8::nlanes; + v_int32 v_zero = vx_setzero_s32(); + v_int8 v_one = vx_setall_s8(1); - for ( ; i <= len - 4; i += 4) - { - __m128i r0 = _mm_loadu_si128((const __m128i*)(src + i)); - sum = _mm_add_epi32(sum, _mm_sad_epu8(_mm_sub_epi8(v_zero, _mm_cmpeq_epi32(r0, v_zero)), v_zero)); - } - - nz = i - (_mm_cvtsi128_si32(_mm_add_epi32(sum, _mm_unpackhi_epi64(sum, sum))) >> 2); - src += i; - } -#elif CV_NEON - int len0 = len & -8, blockSize1 = (1 << 15), blockSize0 = blockSize1 << 6; - uint32x4_t v_nz = vdupq_n_u32(0u); - int32x4_t v_zero = vdupq_n_s32(0.0f); - uint16x8_t v_1 = vdupq_n_u16(1u), v_zerou = vdupq_n_u16(0u); - - while( i < len0 ) + v_int32 v_sum32 = vx_setzero_s32(); + while (i < len0) { - int blockSizei = std::min(len0 - i, blockSize0), j = 0; - - while (j < blockSizei) + v_int16 v_sum16 = vx_setzero_s16(); + int j = i; + while (j < std::min(len0, i + 32766 * v_int16::nlanes)) { - int blockSizej = std::min(blockSizei - j, blockSize1), k = 0; - uint16x8_t v_pz = v_zerou; - - for( ; k <= blockSizej - 8; k += 8 ) - v_pz = vaddq_u16(v_pz, vandq_u16(vcombine_u16(vmovn_u32(vceqq_s32(vld1q_s32(src + k), v_zero)), - vmovn_u32(vceqq_s32(vld1q_s32(src + k + 4), v_zero))), v_1)); - - v_nz = vaddq_u32(vaddl_u16(vget_low_u16(v_pz), vget_high_u16(v_pz)), v_nz); - - src += blockSizej; - j += blockSizej; + v_int8 v_sum8 = vx_setzero_s8(); + int k = j; + for (; k < std::min(len0, j + 127 * v_int8::nlanes); k += v_int8::nlanes) + v_sum8 += v_one & v_pack( + v_pack(vx_load(src + k ) == v_zero, vx_load(src + k + v_int32::nlanes) == v_zero), + v_pack(vx_load(src + k + 2*v_int32::nlanes) == v_zero, vx_load(src + k + 3*v_int32::nlanes) == v_zero) + ); + v_int16 part1, part2; + v_expand(v_sum8, part1, part2); + v_sum16 += part1 + part2; + j = k; } - - i += blockSizei; + v_int32 part1, part2; + v_expand(v_sum16, part1, part2); + v_sum32 += part1 + part2; + i = j; } - - CV_DECL_ALIGNED(16) unsigned int buf[4]; - vst1q_u32(buf, v_nz); - nz += i - saturate_cast(buf[0] + buf[1] + buf[2] + buf[3]); + nz = i - v_reduce_sum(v_sum32); + v_cleanup(); #endif - return nz + countNonZero_(src, len - i); + return nz + countNonZero_(src + i, len - i); } static int countNonZero32f( const float* src, int len ) { int i = 0, nz = 0; -#if CV_SSE2 - if (USE_SSE2) - { - __m128 v_zero_f = _mm_setzero_ps(); - __m128i v_zero = _mm_setzero_si128 (); - __m128i sum = _mm_setzero_si128(); +#if CV_SIMD + int len0 = len & -v_int8::nlanes; + v_float32 v_zero = vx_setzero_f32(); + v_int8 v_one = vx_setall_s8(1); - for ( ; i <= len - 4; i += 4) - { - __m128 r0 = _mm_loadu_ps(src + i); - sum = _mm_add_epi32(sum, _mm_sad_epu8(_mm_sub_epi8(v_zero, _mm_castps_si128(_mm_cmpeq_ps(r0, v_zero_f))), v_zero)); - } - - nz = i - (_mm_cvtsi128_si32(_mm_add_epi32(sum, _mm_unpackhi_epi64(sum, sum))) >> 2); - src += i; - } -#elif CV_NEON - int len0 = len & -8, blockSize1 = (1 << 15), blockSize0 = blockSize1 << 6; - uint32x4_t v_nz = vdupq_n_u32(0u); - float32x4_t v_zero = vdupq_n_f32(0.0f); - uint16x8_t v_1 = vdupq_n_u16(1u), v_zerou = vdupq_n_u16(0u); - - while( i < len0 ) + v_int32 v_sum32 = vx_setzero_s32(); + while (i < len0) { - int blockSizei = std::min(len0 - i, blockSize0), j = 0; - - while (j < blockSizei) + v_int16 v_sum16 = vx_setzero_s16(); + int j = i; + while (j < std::min(len0, i + 32766 * v_int16::nlanes)) { - int blockSizej = std::min(blockSizei - j, blockSize1), k = 0; - uint16x8_t v_pz = v_zerou; - - for( ; k <= blockSizej - 8; k += 8 ) - v_pz = vaddq_u16(v_pz, vandq_u16(vcombine_u16(vmovn_u32(vceqq_f32(vld1q_f32(src + k), v_zero)), - vmovn_u32(vceqq_f32(vld1q_f32(src + k + 4), v_zero))), v_1)); - - v_nz = vaddq_u32(vaddl_u16(vget_low_u16(v_pz), vget_high_u16(v_pz)), v_nz); - - src += blockSizej; - j += blockSizej; + v_int8 v_sum8 = vx_setzero_s8(); + int k = j; + for (; k < std::min(len0, j + 127 * v_int8::nlanes); k += v_int8::nlanes) + v_sum8 += v_one & v_pack( + v_pack(v_reinterpret_as_s32(vx_load(src + k ) == v_zero), v_reinterpret_as_s32(vx_load(src + k + v_float32::nlanes) == v_zero)), + v_pack(v_reinterpret_as_s32(vx_load(src + k + 2*v_float32::nlanes) == v_zero), v_reinterpret_as_s32(vx_load(src + k + 3*v_float32::nlanes) == v_zero)) + ); + v_int16 part1, part2; + v_expand(v_sum8, part1, part2); + v_sum16 += part1 + part2; + j = k; } - - i += blockSizei; + v_int32 part1, part2; + v_expand(v_sum16, part1, part2); + v_sum32 += part1 + part2; + i = j; } - - CV_DECL_ALIGNED(16) unsigned int buf[4]; - vst1q_u32(buf, v_nz); - nz += i - saturate_cast(buf[0] + buf[1] + buf[2] + buf[3]); + nz = i - v_reduce_sum(v_sum32); + v_cleanup(); #endif - return nz + countNonZero_(src, len - i); + return nz + countNonZero_(src + i, len - i); } static int countNonZero64f( const double* src, int len ) @@ -378,7 +314,7 @@ int cv::countNonZero( InputArray _src ) CV_Assert( func != 0 ); const Mat* arrays[] = {&src, 0}; - uchar* ptrs[1]{}; + uchar* ptrs[1] = {}; NAryMatIterator it(arrays, ptrs); int total = (int)it.size, nz = 0; diff --git a/modules/core/src/lpsolver.cpp b/modules/core/src/lpsolver.cpp index e5f4d9973999..1a1307d5b549 100644 --- a/modules/core/src/lpsolver.cpp +++ b/modules/core/src/lpsolver.cpp @@ -98,6 +98,10 @@ int solveLP(const Mat& Func, const Mat& Constr, Mat& z){ CV_Assert(Constr.type()==CV_64FC1 || Constr.type()==CV_32FC1); CV_Assert((Func.rows==1 && (Constr.cols-Func.cols==1))|| (Func.cols==1 && (Constr.cols-Func.rows==1))); + if (!z.empty()) + CV_CheckTypeEQ(z.type(), CV_64FC1, ""); + else + CV_CheckType(z.type(), z.type() == CV_64FC1 || z.type() == CV_8UC1/*empty cv::Mat*/, ""); //copy arguments for we will shall modify them Mat_ bigC=Mat_(1,(Func.rows==1?Func.cols:Func.rows)+1), diff --git a/modules/core/src/lut.cpp b/modules/core/src/lut.cpp index 6ed26b69097b..3e91bd9fcbe1 100644 --- a/modules/core/src/lut.cpp +++ b/modules/core/src/lut.cpp @@ -342,7 +342,7 @@ class LUTParallelBody : public ParallelLoopBody int lutcn = lut_.channels(); const Mat* arrays[] = {&src, &dst, 0}; - uchar* ptrs[2]{}; + uchar* ptrs[2] = {}; NAryMatIterator it(arrays, ptrs); int len = (int)it.size; @@ -408,7 +408,7 @@ void cv::LUT( InputArray _src, InputArray _lut, OutputArray _dst ) CV_Assert( func != 0 ); const Mat* arrays[] = {&src, &dst, 0}; - uchar* ptrs[2]{}; + uchar* ptrs[2] = {}; NAryMatIterator it(arrays, ptrs); int len = (int)it.size; diff --git a/modules/core/src/mathfuncs.cpp b/modules/core/src/mathfuncs.cpp index 89fad4e73446..1bdac5ec9850 100644 --- a/modules/core/src/mathfuncs.cpp +++ b/modules/core/src/mathfuncs.cpp @@ -158,7 +158,7 @@ void magnitude( InputArray src1, InputArray src2, OutputArray dst ) Mat Mag = dst.getMat(); const Mat* arrays[] = {&X, &Y, &Mag, 0}; - uchar* ptrs[3]{}; + uchar* ptrs[3] = {}; NAryMatIterator it(arrays, ptrs); int len = (int)it.size*cn; @@ -194,7 +194,7 @@ void phase( InputArray src1, InputArray src2, OutputArray dst, bool angleInDegre Mat Angle = dst.getMat(); const Mat* arrays[] = {&X, &Y, &Angle, 0}; - uchar* ptrs[3]{}; + uchar* ptrs[3] = {}; NAryMatIterator it(arrays, ptrs); int j, total = (int)(it.size*cn), blockSize = total; size_t esz1 = X.elemSize1(); @@ -280,7 +280,7 @@ void cartToPolar( InputArray src1, InputArray src2, Mat Mag = dst1.getMat(), Angle = dst2.getMat(); const Mat* arrays[] = {&X, &Y, &Mag, &Angle, 0}; - uchar* ptrs[4]{}; + uchar* ptrs[4] = {}; NAryMatIterator it(arrays, ptrs); int j, total = (int)(it.size*cn), blockSize = std::min(total, ((BLOCK_SIZE+cn-1)/cn)*cn); size_t esz1 = X.elemSize1(); @@ -577,7 +577,7 @@ void polarToCart( InputArray src1, InputArray src2, CV_IPP_RUN(!angleInDegrees, ipp_polarToCart(Mag, Angle, X, Y)); const Mat* arrays[] = {&Mag, &Angle, &X, &Y, 0}; - uchar* ptrs[4]{}; + uchar* ptrs[4] = {}; NAryMatIterator it(arrays, ptrs); cv::AutoBuffer _buf; float* buf[2] = {0, 0}; @@ -676,7 +676,7 @@ void exp( InputArray _src, OutputArray _dst ) Mat dst = _dst.getMat(); const Mat* arrays[] = {&src, &dst, 0}; - uchar* ptrs[2]{}; + uchar* ptrs[2] = {}; NAryMatIterator it(arrays, ptrs); int len = (int)(it.size*cn); @@ -709,7 +709,7 @@ void log( InputArray _src, OutputArray _dst ) Mat dst = _dst.getMat(); const Mat* arrays[] = {&src, &dst, 0}; - uchar* ptrs[2]{}; + uchar* ptrs[2] = {}; NAryMatIterator it(arrays, ptrs); int len = (int)(it.size*cn); @@ -1241,7 +1241,7 @@ void pow( InputArray _src, double power, OutputArray _dst ) Mat dst = _dst.getMat(); const Mat* arrays[] = {&src, &dst, 0}; - uchar* ptrs[2]{}; + uchar* ptrs[2] = {}; NAryMatIterator it(arrays, ptrs); int len = (int)(it.size*cn); @@ -1588,7 +1588,7 @@ void patchNaNs( InputOutputArray _a, double _val ) Mat a = _a.getMat(); const Mat* arrays[] = {&a, 0}; - int* ptrs[1]{}; + int* ptrs[1] = {}; NAryMatIterator it(arrays, (uchar**)ptrs); size_t len = it.size*a.channels(); Cv32suf val; diff --git a/modules/core/src/matmul.cpp b/modules/core/src/matmul.cpp index 7c5655e9e6f2..676b390ce04f 100644 --- a/modules/core/src/matmul.cpp +++ b/modules/core/src/matmul.cpp @@ -2144,7 +2144,7 @@ void cv::transform( InputArray _src, OutputArray _dst, InputArray _mtx ) CV_Assert( func != 0 ); const Mat* arrays[] = {&src, &dst, 0}; - uchar* ptrs[2]{}; + uchar* ptrs[2] = {}; NAryMatIterator it(arrays, ptrs); size_t i, total = it.size; @@ -2290,7 +2290,7 @@ void cv::perspectiveTransform( InputArray _src, OutputArray _dst, InputArray _mt CV_Assert( func != 0 ); const Mat* arrays[] = {&src, &dst, 0}; - uchar* ptrs[2]{}; + uchar* ptrs[2] = {}; NAryMatIterator it(arrays, ptrs); size_t i, total = it.size; @@ -2441,7 +2441,7 @@ void cv::scaleAdd( InputArray _src1, double alpha, InputArray _src2, OutputArray } const Mat* arrays[] = {&src1, &src2, &dst, 0}; - uchar* ptrs[3]{}; + uchar* ptrs[3] = {}; NAryMatIterator it(arrays, ptrs); size_t i, len = it.size*cn; @@ -3301,7 +3301,7 @@ double Mat::dot(InputArray _mat) const } const Mat* arrays[] = {this, &mat, 0}; - uchar* ptrs[2]{}; + uchar* ptrs[2] = {}; NAryMatIterator it(arrays, ptrs); int len = (int)(it.size*cn); double r = 0; diff --git a/modules/core/src/matrix_wrap.cpp b/modules/core/src/matrix_wrap.cpp index d39de1870136..b5b4514ada00 100644 --- a/modules/core/src/matrix_wrap.cpp +++ b/modules/core/src/matrix_wrap.cpp @@ -1413,18 +1413,39 @@ void _OutputArray::create(int d, const int* sizes, int mtype, int i, case 16: ((std::vector*)v)->resize(len); break; + case 20: + ((std::vector >*)v)->resize(len); + break; case 24: ((std::vector*)v)->resize(len); break; + case 28: + ((std::vector >*)v)->resize(len); + break; case 32: ((std::vector*)v)->resize(len); break; case 36: ((std::vector >*)v)->resize(len); break; + case 40: + ((std::vector >*)v)->resize(len); + break; + case 44: + ((std::vector >*)v)->resize(len); + break; case 48: ((std::vector >*)v)->resize(len); break; + case 52: + ((std::vector >*)v)->resize(len); + break; + case 56: + ((std::vector >*)v)->resize(len); + break; + case 60: + ((std::vector >*)v)->resize(len); + break; case 64: ((std::vector >*)v)->resize(len); break; diff --git a/modules/core/src/mean.cpp b/modules/core/src/mean.cpp index 0badfa2f6529..30959f3bf900 100644 --- a/modules/core/src/mean.cpp +++ b/modules/core/src/mean.cpp @@ -121,7 +121,7 @@ cv::Scalar cv::mean( InputArray _src, InputArray _mask ) CV_Assert( cn <= 4 && func != 0 ); const Mat* arrays[] = {&src, &mask, 0}; - uchar* ptrs[2]{}; + uchar* ptrs[2] = {}; NAryMatIterator it(arrays, ptrs); int total = (int)it.size, blockSize = total, intSumBlockSize = 0; int j, count = 0; @@ -786,7 +786,7 @@ void cv::meanStdDev( InputArray _src, OutputArray _mean, OutputArray _sdv, Input CV_Assert( func != 0 ); const Mat* arrays[] = {&src, &mask, 0}; - uchar* ptrs[2]{}; + uchar* ptrs[2] = {}; NAryMatIterator it(arrays, ptrs); int total = (int)it.size, blockSize = total, intSumBlockSize = 0; int j, count = 0, nz0 = 0; diff --git a/modules/core/src/minmax.cpp b/modules/core/src/minmax.cpp index 371438184e72..4276b226342d 100644 --- a/modules/core/src/minmax.cpp +++ b/modules/core/src/minmax.cpp @@ -770,7 +770,7 @@ void cv::minMaxIdx(InputArray _src, double* minVal, CV_Assert( func != 0 ); const Mat* arrays[] = {&src, &mask, 0}; - uchar* ptrs[2]{}; + uchar* ptrs[2] = {}; NAryMatIterator it(arrays, ptrs); size_t minidx = 0, maxidx = 0; diff --git a/modules/core/src/norm.cpp b/modules/core/src/norm.cpp index 40d195c3f879..f2171a907a4e 100644 --- a/modules/core/src/norm.cpp +++ b/modules/core/src/norm.cpp @@ -710,7 +710,7 @@ double cv::norm( InputArray _src, int normType, InputArray _mask ) int cellSize = normType == NORM_HAMMING ? 1 : 2; const Mat* arrays[] = {&src, 0}; - uchar* ptrs[1]{}; + uchar* ptrs[1] = {}; NAryMatIterator it(arrays, ptrs); int total = (int)it.size; int result = 0; @@ -727,7 +727,7 @@ double cv::norm( InputArray _src, int normType, InputArray _mask ) CV_Assert( func != 0 ); const Mat* arrays[] = {&src, &mask, 0}; - uchar* ptrs[2]{}; + uchar* ptrs[2] = {}; union { double d; @@ -1168,7 +1168,7 @@ double cv::norm( InputArray _src1, InputArray _src2, int normType, InputArray _m int cellSize = normType == NORM_HAMMING ? 1 : 2; const Mat* arrays[] = {&src1, &src2, 0}; - uchar* ptrs[2]{}; + uchar* ptrs[2] = {}; NAryMatIterator it(arrays, ptrs); int total = (int)it.size; int result = 0; @@ -1185,7 +1185,7 @@ double cv::norm( InputArray _src1, InputArray _src2, int normType, InputArray _m CV_Assert( func != 0 ); const Mat* arrays[] = {&src1, &src2, &mask, 0}; - uchar* ptrs[3]{}; + uchar* ptrs[3] = {}; union { double d; diff --git a/modules/core/src/rand.cpp b/modules/core/src/rand.cpp index cc46345ecd3f..e791fd131ba5 100644 --- a/modules/core/src/rand.cpp +++ b/modules/core/src/rand.cpp @@ -584,6 +584,11 @@ void RNG::fill( InputOutputArray _mat, int disttype, } ip[j][1] = cvCeil(a); int idiff = ip[j][0] = cvFloor(b) - ip[j][1] - 1; + if (idiff < 0) + { + idiff = 0; + ip[j][0] = 0; + } double diff = b - a; fast_int_mode = fast_int_mode && diff <= 4294967296. && (idiff & (idiff+1)) == 0; diff --git a/modules/core/src/sum.cpp b/modules/core/src/sum.cpp index be68f13abd22..660e176777d8 100644 --- a/modules/core/src/sum.cpp +++ b/modules/core/src/sum.cpp @@ -602,7 +602,7 @@ cv::Scalar cv::sum( InputArray _src ) CV_Assert( cn <= 4 && func != 0 ); const Mat* arrays[] = {&src, 0}; - uchar* ptrs[1]{}; + uchar* ptrs[1] = {}; NAryMatIterator it(arrays, ptrs); Scalar s; int total = (int)it.size, blockSize = total, intSumBlockSize = 0; diff --git a/modules/core/test/test_ippasync.cpp b/modules/core/test/test_ippasync.cpp deleted file mode 100644 index d52f5c419dc2..000000000000 --- a/modules/core/test/test_ippasync.cpp +++ /dev/null @@ -1,171 +0,0 @@ -// This file is part of OpenCV project. -// It is subject to the license terms in the LICENSE file found in the top-level directory -// of this distribution and at http://opencv.org/license.html. -#include "test_precomp.hpp" -#include "opencv2/ts/ocl_test.hpp" - -#ifdef HAVE_IPP_A -#include "opencv2/core/ippasync.hpp" - -using namespace cv; -using namespace std; -using namespace opencv_test; - -namespace opencv_test { -namespace ocl { - -PARAM_TEST_CASE(IPPAsync, MatDepth, Channels, hppAccelType) -{ - int type; - int cn; - int depth; - hppAccelType accelType; - - Mat matrix, result; - hppiMatrix * hppMat; - hppAccel accel; - hppiVirtualMatrix * virtMatrix; - hppStatus sts; - - virtual void SetUp() - { - type = CV_MAKE_TYPE(GET_PARAM(0), GET_PARAM(1)); - depth = GET_PARAM(0); - cn = GET_PARAM(1); - accelType = GET_PARAM(2); - } - - void generateTestData() - { - Size matrix_Size = randomSize(2, 100); - const double upValue = 100; - - matrix = randomMat(matrix_Size, type, -upValue, upValue); - } - - void Near(double threshold = 0.0) - { - EXPECT_MAT_NEAR(matrix, result, threshold); - } -}; - -TEST_P(IPPAsync, accuracy) -{ - sts = hppCreateInstance(accelType, 0, &accel); - if (sts!=HPP_STATUS_NO_ERROR) printf("hppStatus = %d\n",sts); - CV_Assert(sts==HPP_STATUS_NO_ERROR); - - virtMatrix = hppiCreateVirtualMatrices(accel, 2); - - for (int j = 0; j < test_loop_times; j++) - { - generateTestData(); - hppMat = hpp::getHpp(matrix,accel); - - hppScalar a = 3; - - sts = hppiAddC(accel, hppMat, a, 0, virtMatrix[0]); - CV_Assert(sts==HPP_STATUS_NO_ERROR); - sts = hppiSubC(accel, virtMatrix[0], a, 0, virtMatrix[1]); - CV_Assert(sts==HPP_STATUS_NO_ERROR); - - sts = hppWait(accel, HPP_TIME_OUT_INFINITE); - CV_Assert(sts==HPP_STATUS_NO_ERROR); - - result = hpp::getMat(virtMatrix[1], accel, cn); - - Near(5.0e-6); - - sts = hppiFreeMatrix(hppMat); - CV_Assert(sts==HPP_STATUS_NO_ERROR); - } - - sts = hppiDeleteVirtualMatrices(accel, virtMatrix); - CV_Assert(sts==HPP_STATUS_NO_ERROR); - sts = hppDeleteInstance(accel); - CV_Assert(sts==HPP_STATUS_NO_ERROR); -} - -PARAM_TEST_CASE(IPPAsyncShared, Channels, hppAccelType) -{ - int cn; - int type; - hppAccelType accelType; - - Mat matrix, result; - hppiMatrix* hppMat; - hppAccel accel; - hppiVirtualMatrix * virtMatrix; - hppStatus sts; - - virtual void SetUp() - { - cn = GET_PARAM(0); - accelType = GET_PARAM(1); - type=CV_MAKE_TYPE(CV_8U, GET_PARAM(0)); - } - - void generateTestData() - { - Size matrix_Size = randomSize(2, 100); - hpp32u pitch, size; - const int upValue = 100; - - sts = hppQueryMatrixAllocParams(accel, (hpp32u)(matrix_Size.width*cn), (hpp32u)matrix_Size.height, HPP_DATA_TYPE_8U, &pitch, &size); - - matrix = randomMat(matrix_Size, type, 0, upValue); - } - - void Near(double threshold = 0.0) - { - EXPECT_MAT_NEAR(matrix, result, threshold); - } -}; - -TEST_P(IPPAsyncShared, accuracy) -{ - sts = hppCreateInstance(accelType, 0, &accel); - if (sts!=HPP_STATUS_NO_ERROR) printf("hppStatus = %d\n",sts); - CV_Assert(sts==HPP_STATUS_NO_ERROR); - - virtMatrix = hppiCreateVirtualMatrices(accel, 2); - - for (int j = 0; j < test_loop_times; j++) - { - generateTestData(); - hppMat = hpp::getHpp(matrix,accel); - - hppScalar a = 3; - - sts = hppiAddC(accel, hppMat, a, 0, virtMatrix[0]); - CV_Assert(sts==HPP_STATUS_NO_ERROR); - sts = hppiSubC(accel, virtMatrix[0], a, 0, virtMatrix[1]); - CV_Assert(sts==HPP_STATUS_NO_ERROR); - - sts = hppWait(accel, HPP_TIME_OUT_INFINITE); - CV_Assert(sts==HPP_STATUS_NO_ERROR); - - result = hpp::getMat(virtMatrix[1], accel, cn); - - Near(0); - - sts = hppiFreeMatrix(hppMat); - CV_Assert(sts==HPP_STATUS_NO_ERROR); - } - - sts = hppiDeleteVirtualMatrices(accel, virtMatrix); - CV_Assert(sts==HPP_STATUS_NO_ERROR); - sts = hppDeleteInstance(accel); - CV_Assert(sts==HPP_STATUS_NO_ERROR); -} - -INSTANTIATE_TEST_CASE_P(IppATest, IPPAsyncShared, Combine(Values(1, 2, 3, 4), - Values( HPP_ACCEL_TYPE_CPU, HPP_ACCEL_TYPE_GPU))); - -INSTANTIATE_TEST_CASE_P(IppATest, IPPAsync, Combine(Values(CV_8U, CV_16U, CV_16S, CV_32F), - Values(1, 2, 3, 4), - Values( HPP_ACCEL_TYPE_CPU, HPP_ACCEL_TYPE_GPU))); - -} -} -#endif \ No newline at end of file diff --git a/modules/core/test/test_lpsolver.cpp b/modules/core/test/test_lpsolver.cpp index b47a6eb08079..97f87f4c2fc2 100644 --- a/modules/core/test/test_lpsolver.cpp +++ b/modules/core/test/test_lpsolver.cpp @@ -141,4 +141,14 @@ TEST(Core_LPSolver, regression_cycling){ #endif } +TEST(Core_LPSolver, issue_12337) +{ + Mat A=(cv::Mat_(3,1)<<3,1,2); + Mat B=(cv::Mat_(3,4)<<1,1,3,30,2,2,5,24,4,1,2,36); + EXPECT_ANY_THROW(Mat1f z_float; cv::solveLP(A, B, z_float)); + EXPECT_NO_THROW(Mat1d z_double; cv::solveLP(A, B, z_double)); + EXPECT_ANY_THROW(Mat1i z_int; cv::solveLP(A, B, z_int)); + //need to update interface: EXPECT_ANY_THROW(Mat1b z_8u; cv::solveLP(A, B, z_8u)); +} + }} // namespace diff --git a/modules/core/test/test_mat.cpp b/modules/core/test/test_mat.cpp index 4a8c347c68a9..e7ccd95c8cef 100644 --- a/modules/core/test/test_mat.cpp +++ b/modules/core/test/test_mat.cpp @@ -1872,4 +1872,63 @@ TEST(Core_Split, crash_12171) EXPECT_EQ(2, dst2.ptr(1)[1]); } +struct CustomType // like cv::Keypoint +{ + Point2f pt; + float size; + float angle; + float response; + int octave; + int class_id; +}; + +static void test_CustomType(InputArray src_, OutputArray dst_) +{ + Mat src = src_.getMat(); + ASSERT_EQ(sizeof(CustomType), src.elemSize()); + CV_CheckTypeEQ(src.type(), CV_MAKETYPE(CV_8U, sizeof(CustomType)), ""); + + CustomType* kpt = NULL; + { + Mat dst = dst_.getMat(); + for (size_t i = 0; i < dst.total(); i++) + { + kpt = dst.ptr(0) + i; + kpt->octave = (int)i; + } + } + const int N = (int)src.total(); + dst_.create(1, N * 2, rawType()); + Mat dst = dst_.getMat(); + for (size_t i = N; i < dst.total(); i++) + { + kpt = dst.ptr(0) + i; + kpt->octave = -(int)i; + } +#if 0 // Compilation error + CustomType& kpt = dst.at(0, 5); +#endif +} + +TEST(Core_InputArray, support_CustomType) +{ + std::vector kp1(5); + std::vector kp2(3); + test_CustomType(rawIn(kp1), rawOut(kp2)); + ASSERT_EQ((size_t)10, kp2.size()); + for (int i = 0; i < 3; i++) + { + EXPECT_EQ(i, kp2[i].octave); + } + for (int i = 3; i < 5; i++) + { + EXPECT_EQ(0, kp2[i].octave); + } + for (int i = 5; i < 10; i++) + { + EXPECT_EQ(-i, kp2[i].octave); + } +} + + }} // namespace diff --git a/modules/cudafeatures2d/test/test_features2d.cpp b/modules/cudafeatures2d/test/test_features2d.cpp index 6ab23beaffa4..787b4fb34508 100644 --- a/modules/cudafeatures2d/test/test_features2d.cpp +++ b/modules/cudafeatures2d/test/test_features2d.cpp @@ -222,7 +222,7 @@ CUDA_TEST_P(ORB, Accuracy) { std::vector keypoints; cv::cuda::GpuMat descriptors; - orb->detectAndComputeAsync(loadMat(image), loadMat(mask), keypoints, descriptors); + orb->detectAndComputeAsync(loadMat(image), loadMat(mask), rawOut(keypoints), descriptors); } catch (const cv::Exception& e) { diff --git a/modules/dnn/CMakeLists.txt b/modules/dnn/CMakeLists.txt index 64fefb3509b4..40b573f45a3c 100644 --- a/modules/dnn/CMakeLists.txt +++ b/modules/dnn/CMakeLists.txt @@ -95,7 +95,7 @@ ocv_glob_module_sources(${sources_options} SOURCES ${fw_srcs}) ocv_create_module(${libs} ${INF_ENGINE_TARGET}) ocv_add_samples() ocv_add_accuracy_tests(${INF_ENGINE_TARGET}) -ocv_add_perf_tests() +ocv_add_perf_tests(${INF_ENGINE_TARGET}) ocv_option(${the_module}_PERF_CAFFE "Add performance tests of Caffe framework" OFF) ocv_option(${the_module}_PERF_CLCAFFE "Add performance tests of clCaffe framework" OFF) diff --git a/modules/dnn/include/opencv2/dnn/dnn.hpp b/modules/dnn/include/opencv2/dnn/dnn.hpp index a50c50cd0588..c322d47b82b3 100644 --- a/modules/dnn/include/opencv2/dnn/dnn.hpp +++ b/modules/dnn/include/opencv2/dnn/dnn.hpp @@ -878,6 +878,14 @@ CV__DNN_INLINE_NS_BEGIN CV_EXPORTS_W void shrinkCaffeModel(const String& src, const String& dst, const std::vector& layersTypes = std::vector()); + /** @brief Create a text representation for a binary network stored in protocol buffer format. + * @param[in] model A path to binary network. + * @param[in] output A path to output text file to be created. + * + * @note To reduce output file size, trained weights are not included. + */ + CV_EXPORTS_W void writeTextGraph(const String& model, const String& output); + /** @brief Performs non maximum suppression given boxes and corresponding scores. * @param bboxes a set of bounding boxes to apply NMS. diff --git a/modules/dnn/misc/java/test/DnnListRegressionTest.java b/modules/dnn/misc/java/test/DnnListRegressionTest.java new file mode 100644 index 000000000000..4c357aff869c --- /dev/null +++ b/modules/dnn/misc/java/test/DnnListRegressionTest.java @@ -0,0 +1,119 @@ +package org.opencv.test.dnn; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import org.opencv.core.Core; +import org.opencv.core.Mat; +import org.opencv.core.MatOfInt; +import org.opencv.core.MatOfFloat; +import org.opencv.core.MatOfByte; +import org.opencv.core.Scalar; +import org.opencv.core.Size; +import org.opencv.dnn.DictValue; +import org.opencv.dnn.Dnn; +import org.opencv.dnn.Layer; +import org.opencv.dnn.Net; +import org.opencv.imgcodecs.Imgcodecs; +import org.opencv.imgproc.Imgproc; +import org.opencv.test.OpenCVTestCase; + +/* +* regression test for #12324, +* testing various java.util.List invocations, +* which use the LIST_GET macro +*/ + +public class DnnListRegressionTest extends OpenCVTestCase { + + private final static String ENV_OPENCV_DNN_TEST_DATA_PATH = "OPENCV_DNN_TEST_DATA_PATH"; + + private final static String ENV_OPENCV_TEST_DATA_PATH = "OPENCV_TEST_DATA_PATH"; + + String modelFileName = ""; + String sourceImageFile = ""; + + Net net; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + String envDnnTestDataPath = System.getenv(ENV_OPENCV_DNN_TEST_DATA_PATH); + + if(envDnnTestDataPath == null){ + isTestCaseEnabled = false; + return; + } + + File dnnTestDataPath = new File(envDnnTestDataPath); + modelFileName = new File(dnnTestDataPath, "dnn/tensorflow_inception_graph.pb").toString(); + + String envTestDataPath = System.getenv(ENV_OPENCV_TEST_DATA_PATH); + + if(envTestDataPath == null) throw new Exception(ENV_OPENCV_TEST_DATA_PATH + " has to be defined!"); + + File testDataPath = new File(envTestDataPath); + + File f = new File(testDataPath, "dnn/grace_hopper_227.png"); + sourceImageFile = f.toString(); + if(!f.exists()) throw new Exception("Test image is missing: " + sourceImageFile); + + net = Dnn.readNetFromTensorflow(modelFileName); + + Mat image = Imgcodecs.imread(sourceImageFile); + assertNotNull("Loading image from file failed!", image); + + Mat inputBlob = Dnn.blobFromImage(image, 1.0, new Size(224, 224), new Scalar(0), true, true); + assertNotNull("Converting image to blob failed!", inputBlob); + + net.setInput(inputBlob, "input"); + } + + public void testSetInputsNames() { + List inputs = new ArrayList(); + inputs.add("input"); + try { + net.setInputsNames(inputs); + } catch(Exception e) { + fail("Net setInputsNames failed: " + e.getMessage()); + } + } + + public void testForward() { + List outs = new ArrayList(); + List outNames = new ArrayList(); + outNames.add("softmax2"); + try { + net.forward(outs,outNames); + } catch(Exception e) { + fail("Net forward failed: " + e.getMessage()); + } + } + + public void testGetMemoryConsumption() { + int layerId = 1; + List netInputShapes = new ArrayList(); + netInputShapes.add(new MatOfInt(1, 3, 224, 224)); + long[] weights=null; + long[] blobs=null; + try { + net.getMemoryConsumption(layerId, netInputShapes, weights, blobs); + } catch(Exception e) { + fail("Net getMemoryConsumption failed: " + e.getMessage()); + } + } + + public void testGetFLOPS() { + int layerId = 1; + List netInputShapes = new ArrayList(); + netInputShapes.add(new MatOfInt(1, 3, 224, 224)); + try { + net.getFLOPS(layerId, netInputShapes); + } catch(Exception e) { + fail("Net getFLOPS failed: " + e.getMessage()); + } + } +} diff --git a/modules/dnn/perf/opencl/perf_convolution.cpp b/modules/dnn/perf/opencl/perf_convolution.cpp deleted file mode 100644 index 28fbf3ae83b4..000000000000 --- a/modules/dnn/perf/opencl/perf_convolution.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include "../perf_precomp.hpp" -#include "opencv2/ts/ocl_perf.hpp" -#include - -#ifdef HAVE_OPENCL - -namespace opencv_test { namespace ocl { -using namespace ::perf; - -namespace { -enum {STRIDE_OFF = 1, STRIDE_ON = 2}; -CV_ENUM(StrideSize, STRIDE_OFF, STRIDE_ON); - -enum {GROUP_OFF = 1, GROUP_2 = 2}; -CV_ENUM(GroupSize, GROUP_OFF, GROUP_2); -} // namespace - -//Squared Size -#define SSZ(n) cv::Size(n, n) - -typedef std::pair InpShapeNumOut; -typedef tuple ConvParam; //kernel_size, inp shape, groups, stride -typedef TestBaseWithParam ConvolutionPerfTest; - -static inline MatShape blobShape(int count, int nplanes, int height, int width) -{ - int data[] = {count, nplanes, height, width}; - return MatShape(data, data+4); -} - -OCL_PERF_TEST_P( ConvolutionPerfTest, perf, Combine( - Values(Size(1, 1), Size(3, 3), Size(5, 5), Size(11, 11)), - Values(make_pair(blobShape(1, 4, 224, 224), 64), - make_pair(blobShape(1, 64, 112, 122), 128), - make_pair(blobShape(1, 256, 28, 28), 512)), - GroupSize::all(), - StrideSize::all()) -) -{ - RNG rng(0); - - ConvParam params = GetParam(); - int ksz = get<0>(params).width; - MatShape inpShape = get<1>(params).first; - int outCn = get<1>(params).second; - int groups = get<2>(params); - int stride = (ksz >= 11) ? 4 : (int)get<3>(params); - - int inpCn = inpShape[1]; - int wgtSize[] = { outCn, inpCn/groups, ksz, ksz }; - int biasSize[] = { outCn, 1, 1, 1 }; - const int wtype = CV_32F; - Mat wgtBlob(4, wgtSize, wtype), biasBlob(4, biasSize, wtype); - Mat inpBlob(4, &inpShape[0], wtype); - rng.fill(biasBlob, RNG::UNIFORM, -1, +1); - rng.fill(wgtBlob, RNG::UNIFORM, -1, +1); - rng.fill(inpBlob, RNG::UNIFORM, -1, +1); - - LayerParams lp; - lp.set("num_output", outCn); - lp.set("group", groups); - lp.set("stride", stride); - lp.set("kernel_size", ksz); - lp.blobs.reserve(2); - lp.blobs.push_back(wgtBlob); - lp.blobs.push_back(biasBlob); - - std::vector inpBlobs(1, &inpBlob); - std::vector outBlobs, internalBlobs; - - Ptr layer = cv::dnn::LayerFactory::createLayerInstance("Convolution", lp); - std::vector inputShapes(1, shape(inpBlob)), outShapes, internals; - layer->getMemoryShapes(inputShapes, 0, outShapes, internals); - for (size_t i = 0; i < outShapes.size(); i++) - { - outBlobs.push_back(Mat(outShapes[i], CV_32F)); - } - for (size_t i = 0; i < internals.size(); i++) - { - internalBlobs.push_back(Mat()); - if (total(internals[i])) - internalBlobs.back().create(internals[i], CV_32F); - } - - layer->finalize(inpBlobs, outBlobs); - layer->preferableTarget = DNN_TARGET_OPENCL; - - Mat inpBlob2D = inpBlob.reshape(1, outCn); - Mat wgtBlob2D = wgtBlob.reshape(1, outCn*(inpCn/groups)); - Mat outBlob2D = outBlobs[0].reshape(1, outBlobs[0].size[0]); - declare.in(inpBlob2D, wgtBlob2D, WARMUP_RNG).out(outBlob2D); - - // warmup - layer->forward(inpBlobs, outBlobs, internalBlobs); - - TEST_CYCLE() - { - layer->forward(inpBlobs, outBlobs, internalBlobs); - } - - SANITY_CHECK_NOTHING(); -} - -} -} - -#endif diff --git a/modules/dnn/perf/perf_convolution.cpp b/modules/dnn/perf/perf_convolution.cpp index 16006d75dac9..be742ea48b2d 100644 --- a/modules/dnn/perf/perf_convolution.cpp +++ b/modules/dnn/perf/perf_convolution.cpp @@ -1,92 +1,674 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + #include "perf_precomp.hpp" #include namespace opencv_test { -enum {STRIDE_OFF = 1, STRIDE_ON = 2}; -CV_ENUM(StrideSize, STRIDE_OFF, STRIDE_ON); +// Flops_Kernel_Input_OutCN_Group_Stride_Pad_Dilation_PadAdjust_PadMode_Bias +struct TestSize_ { + int width, height; + operator Size() const { return Size(width, height); } +}; +struct ConvParam_t { + struct TestSize_ kernel; + struct BlobShape { int dims[4]; } shapeIn; + int outCN; + int groups; + struct TestSize_ stride; + struct TestSize_ dilation; + struct TestSize_ pad; + struct TestSize_ padAdjust; + const char* padMode; + bool hasBias; + double declared_flops; +}; +// Details: #12142 +static const ConvParam_t testConvolutionConfigs[] = { + /* GFLOPS 10.087 x 1 = 10.087 */ {{3, 3}, {{1, 576, 38, 50}}, 512, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 10086963200.}, + /* GFLOPS 1.704 x 5 = 8.518 */ {{3, 3}, {{1, 512, 19, 19}}, 512, 512, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 1703596544.}, + /* GFLOPS 1.704 x 5 = 8.518 */ {{3, 3}, {{1, 512, 19, 19}}, 512, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 1703596544.}, + /* GFLOPS 6.641 x 1 = 6.641 */ {{3, 3}, {{1, 64, 150, 200}}, 192, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 6641280000.}, + /* GFLOPS 1.659 x 3 = 4.977 */ {{3, 3}, {{1, 960, 10, 10}}, 960, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 1658976000.}, + /* GFLOPS 2.156 x 2 = 4.312 */ {{3, 3}, {{1, 576, 19, 19}}, 576, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 2156088384.}, + /* GFLOPS 0.958 x 4 = 3.833 */ {{3, 3}, {{1, 384, 19, 19}}, 384, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 958307712.}, + /* GFLOPS 0.830 x 4 = 3.321 */ {{3, 3}, {{1, 64, 75, 100}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 830160000.}, + /* GFLOPS 1.245 x 2 = 2.490 */ {{3, 3}, {{1, 96, 75, 100}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 1244880000.}, + /* GFLOPS 2.100 x 1 = 2.100 */ {{3, 3}, {{1, 144, 75, 75}}, 144, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 2100330000.}, + /* GFLOPS 1.022 x 2 = 2.044 */ {{3, 3}, {{1, 576, 19, 19}}, 273, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 1021896057.}, + /* GFLOPS 0.958 x 2 = 1.917 */ {{3, 3}, {{1, 192, 38, 38}}, 192, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 958446336.}, + /* GFLOPS 1.888 x 1 = 1.888 */ {{3, 3}, {{1, 1024, 10, 10}}, 1024, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 1887539200.}, + /* GFLOPS 1.888 x 1 = 1.888 */ {{3, 3}, {{1, 1024, 10, 10}}, 1024, 1024, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 1887539200.}, + /* GFLOPS 1.704 x 1 = 1.704 */ {{3, 3}, {{1, 256, 38, 38}}, 256, 256, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 1703781376.}, + /* GFLOPS 1.704 x 1 = 1.704 */ {{3, 3}, {{1, 256, 38, 38}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 1703781376.}, + /* GFLOPS 1.660 x 1 = 1.660 */ {{3, 3}, {{1, 128, 75, 75}}, 128, 128, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 1659600000.}, + /* GFLOPS 1.660 x 1 = 1.660 */ {{3, 3}, {{1, 128, 75, 75}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 1659600000.}, + /* GFLOPS 0.280 x 5 = 1.402 */ {{1, 1}, {{1, 576, 38, 50}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 280409600.}, + /* GFLOPS 0.701 x 2 = 1.401 */ {{3, 3}, {{1, 128, 38, 50}}, 160, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 700720000.}, + /* GFLOPS 0.231 x 6 = 1.388 */ {{3, 3}, {{1, 128, 56, 56}}, 32, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", false, 231311360.}, + /* GFLOPS 0.231 x 6 = 1.388 */ {{3, 3}, {{1, 256, 14, 14}}, 256, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", false, 231261184.}, + /* GFLOPS 0.210 x 6 = 1.262 */ {{1, 1}, {{1, 576, 38, 50}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 210307200.}, + /* GFLOPS 0.420 x 3 = 1.261 */ {{3, 3}, {{1, 96, 38, 50}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 420492800.}, + /* GFLOPS 1.261 x 1 = 1.261 */ {{3, 3}, {{1, 192, 38, 50}}, 192, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 1261113600.}, + /* GFLOPS 1.258 x 1 = 1.258 */ {{3, 3}, {{1, 1280, 10, 10}}, 546, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 1258038600.}, + /* GFLOPS 1.245 x 1 = 1.245 */ {{3, 3}, {{1, 64, 75, 75}}, 192, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 1245240000.}, + /* GFLOPS 0.561 x 2 = 1.121 */ {{3, 3}, {{1, 128, 38, 50}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 560576000.}, + /* GFLOPS 1.051 x 1 = 1.051 */ {{3, 3}, {{1, 160, 38, 50}}, 192, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 1050988800.}, + /* GFLOPS 1.006 x 1 = 1.006 */ {{3, 3}, {{1, 1024, 10, 10}}, 546, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 1006441800.}, + /* GFLOPS 0.246 x 4 = 0.985 */ {{1, 1}, {{1, 256, 75, 100}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 246240000.}, + /* GFLOPS 0.189 x 5 = 0.947 */ {{1, 1}, {{1, 512, 19, 19}}, 512, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 189452800.}, + /* GFLOPS 0.189 x 5 = 0.947 */ {{1, 1}, {{1, 512, 19, 19}}, 512, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 189452800.}, + /* GFLOPS 0.934 x 1 = 0.934 */ {{3, 3}, {{1, 96, 150, 150}}, 96, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 933660000.}, + /* GFLOPS 0.231 x 4 = 0.925 */ {{3, 3}, {{1, 128, 28, 28}}, 128, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", false, 231311360.}, + /* GFLOPS 0.896 x 1 = 0.896 */ {{5, 5}, {{1, 96, 27, 27}}, 256, 2, {1, 1}, {1, 1}, {2, 2}, {0, 0}, "", true, 895981824.}, + /* GFLOPS 0.876 x 1 = 0.876 */ {{3, 3}, {{1, 160, 38, 50}}, 160, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 875824000.}, + /* GFLOPS 0.850 x 1 = 0.850 */ {{7, 7}, {{1, 3, 600, 800}}, 24, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 849600000.}, + /* GFLOPS 0.841 x 1 = 0.841 */ {{3, 3}, {{1, 128, 38, 50}}, 192, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 840864000.}, + /* GFLOPS 0.415 x 2 = 0.831 */ {{3, 3}, {{1, 32, 150, 150}}, 32, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 415440000.}, + /* GFLOPS 0.351 x 2 = 0.701 */ {{1, 1}, {{1, 576, 38, 50}}, 160, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 350512000.}, + /* GFLOPS 0.701 x 1 = 0.701 */ {{3, 3}, {{1, 128, 75, 100}}, 160, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 700720000.}, + /* GFLOPS 0.694 x 1 = 0.694 */ {{3, 3}, {{1, 64, 56, 56}}, 192, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 694235136.}, + /* GFLOPS 0.694 x 1 = 0.694 */ {{3, 3}, {{1, 64, 56, 56}}, 192, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 694235136.}, + /* GFLOPS 0.231 x 3 = 0.694 */ {{3, 3}, {{1, 64, 56, 56}}, 64, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", false, 231411712.}, + /* GFLOPS 0.058 x 12 = 0.694 */ {{3, 3}, {{1, 128, 28, 28}}, 32, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", false, 57827840.}, + /* GFLOPS 0.231 x 3 = 0.694 */ {{3, 3}, {{1, 512, 7, 7}}, 512, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", false, 231236096.}, + /* GFLOPS 0.160 x 4 = 0.639 */ {{3, 3}, {{1, 64, 38, 38}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 159833472.}, + /* GFLOPS 0.103 x 6 = 0.618 */ {{1, 1}, {{1, 256, 14, 14}}, 1024, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 102961152.}, + /* GFLOPS 0.615 x 1 = 0.615 */ {{1, 1}, {{1, 320, 75, 100}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 615360000.}, + /* GFLOPS 0.597 x 1 = 0.597 */ {{3, 3}, {{1, 576, 19, 19}}, 576, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 597254400.}, + /* GFLOPS 0.185 x 3 = 0.554 */ {{1, 1}, {{1, 192, 75, 100}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 184800000.}, + /* GFLOPS 0.553 x 1 = 0.553 */ {{3, 3}, {{1, 64, 75, 100}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 553440000.}, + /* GFLOPS 0.539 x 1 = 0.539 */ {{3, 3}, {{1, 144, 75, 75}}, 144, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 539178048.}, + /* GFLOPS 0.103 x 5 = 0.514 */ {{1, 1}, {{1, 1024, 14, 14}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 102810624.}, + /* GFLOPS 0.491 x 1 = 0.491 */ {{1, 1}, {{1, 576, 38, 50}}, 224, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 490716800.}, + /* GFLOPS 0.240 x 2 = 0.479 */ {{3, 3}, {{1, 96, 38, 38}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 239680896.}, + /* GFLOPS 0.237 x 2 = 0.474 */ {{7, 7}, {{1, 3, 224, 224}}, 64, 1, {2, 2}, {1, 1}, {3, 3}, {0, 0}, "", true, 236830720.}, + /* GFLOPS 0.472 x 1 = 0.472 */ {{3, 3}, {{1, 512, 19, 19}}, 512, 512, {2, 2}, {1, 1}, {1, 1}, {0, 0}, "", true, 471910400.}, + /* GFLOPS 0.472 x 1 = 0.472 */ {{3, 3}, {{1, 512, 19, 19}}, 512, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 471910400.}, + /* GFLOPS 0.449 x 1 = 0.449 */ {{3, 3}, {{1, 384, 13, 13}}, 384, 2, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 448626048.}, + /* GFLOPS 0.426 x 1 = 0.426 */ {{3, 3}, {{1, 128, 75, 75}}, 128, 128, {2, 2}, {1, 1}, {1, 1}, {0, 0}, "", true, 426037760.}, + /* GFLOPS 0.426 x 1 = 0.426 */ {{3, 3}, {{1, 128, 75, 75}}, 128, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 426037760.}, + /* GFLOPS 0.426 x 1 = 0.426 */ {{3, 3}, {{1, 128, 38, 38}}, 128, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", false, 426037760.}, + /* GFLOPS 0.426 x 1 = 0.426 */ {{3, 3}, {{1, 256, 38, 38}}, 256, 256, {2, 2}, {1, 1}, {1, 1}, {0, 0}, "", true, 425945344.}, + /* GFLOPS 0.426 x 1 = 0.426 */ {{3, 3}, {{1, 256, 38, 38}}, 256, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 425945344.}, + /* GFLOPS 0.426 x 1 = 0.426 */ {{3, 3}, {{1, 256, 19, 19}}, 256, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", false, 425945344.}, + /* GFLOPS 0.421 x 1 = 0.421 */ {{1, 1}, {{1, 576, 38, 50}}, 192, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 420614400.}, + /* GFLOPS 0.415 x 1 = 0.415 */ {{3, 3}, {{1, 32, 150, 150}}, 32, 32, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 415440000.}, + /* GFLOPS 0.415 x 1 = 0.415 */ {{3, 3}, {{1, 64, 150, 150}}, 64, 64, {2, 2}, {1, 1}, {1, 1}, {0, 0}, "", true, 415080000.}, + /* GFLOPS 0.415 x 1 = 0.415 */ {{3, 3}, {{1, 64, 150, 150}}, 64, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 415080000.}, + /* GFLOPS 0.104 x 4 = 0.414 */ {{1, 1}, {{1, 64, 56, 56}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 103563264.}, + /* GFLOPS 0.103 x 4 = 0.413 */ {{1, 1}, {{1, 128, 28, 28}}, 512, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 103161856.}, + /* GFLOPS 0.376 x 1 = 0.376 */ {{1, 1}, {{1, 24, 300, 400}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "VALID", true, 376320000.}, + /* GFLOPS 0.347 x 1 = 0.347 */ {{3, 3}, {{1, 128, 28, 28}}, 192, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 346967040.}, + /* GFLOPS 0.347 x 1 = 0.347 */ {{3, 3}, {{1, 128, 28, 28}}, 192, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 346967040.}, + /* GFLOPS 0.014 x 24 = 0.347 */ {{3, 3}, {{1, 128, 14, 14}}, 32, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", false, 14456960.}, + /* GFLOPS 0.053 x 6 = 0.320 */ {{1, 1}, {{1, 576, 19, 19}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 53277824.}, + /* GFLOPS 0.319 x 1 = 0.319 */ {{3, 3}, {{1, 192, 19, 19}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 319482112.}, + /* GFLOPS 0.315 x 1 = 0.315 */ {{3, 3}, {{1, 96, 75, 100}}, 96, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 315369600.}, + /* GFLOPS 0.103 x 3 = 0.309 */ {{1, 1}, {{1, 512, 7, 7}}, 2048, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 102860800.}, + /* GFLOPS 0.103 x 3 = 0.309 */ {{1, 1}, {{1, 512, 28, 28}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 102860800.}, + /* GFLOPS 0.308 x 1 = 0.308 */ {{1, 1}, {{1, 320, 75, 100}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 307680000.}, + /* GFLOPS 0.299 x 1 = 0.299 */ {{3, 3}, {{1, 256, 13, 13}}, 384, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 299105664.}, + /* GFLOPS 0.299 x 1 = 0.299 */ {{3, 3}, {{1, 384, 13, 13}}, 256, 2, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 299084032.}, + /* GFLOPS 0.017 x 17 = 0.290 */ {{1, 1}, {{1, 32, 32, 64}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 17039360.}, + /* GFLOPS 0.017 x 16 = 0.269 */ {{1, 1}, {{1, 128, 32, 64}}, 32, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 16842752.}, + /* GFLOPS 0.133 x 2 = 0.266 */ {{3, 3}, {{1, 128, 19, 19}}, 160, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 133136800.}, + /* GFLOPS 0.038 x 7 = 0.265 */ {{3, 3}, {{1, 16, 64, 128}}, 16, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 37879808.}, + /* GFLOPS 0.126 x 2 = 0.252 */ {{3, 3}, {{1, 512, 5, 5}}, 546, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 125812050.}, + /* GFLOPS 0.248 x 1 = 0.248 */ {{1, 1}, {{1, 64, 150, 200}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 247680000.}, + /* GFLOPS 0.040 x 6 = 0.240 */ {{1, 1}, {{1, 576, 19, 19}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 39958368.}, + /* GFLOPS 0.080 x 3 = 0.240 */ {{3, 3}, {{1, 96, 19, 19}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 79893632.}, + /* GFLOPS 0.240 x 1 = 0.240 */ {{3, 3}, {{1, 192, 38, 38}}, 192, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 239611584.}, + /* GFLOPS 0.240 x 1 = 0.240 */ {{3, 3}, {{1, 192, 19, 19}}, 192, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 239611584.}, + /* GFLOPS 0.237 x 1 = 0.237 */ {{7, 7}, {{1, 3, 224, 224}}, 64, 1, {2, 2}, {1, 1}, {3, 3}, {0, 0}, "", false, 236830720.}, + /* GFLOPS 0.237 x 1 = 0.237 */ {{7, 7}, {{1, 3, 224, 224}}, 64, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 236830720.}, + /* GFLOPS 0.111 x 2 = 0.221 */ {{3, 3}, {{1, 192, 10, 10}}, 320, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 110624000.}, + /* GFLOPS 0.213 x 1 = 0.213 */ {{3, 3}, {{1, 128, 38, 38}}, 256, 1, {2, 2}, {1, 1}, {1, 1}, {0, 0}, "", false, 213018880.}, + /* GFLOPS 0.213 x 1 = 0.213 */ {{3, 3}, {{1, 128, 19, 19}}, 256, 1, {1, 1}, {2, 2}, {2, 2}, {0, 0}, "", false, 213018880.}, + /* GFLOPS 0.107 x 2 = 0.213 */ {{3, 3}, {{1, 128, 19, 19}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 106509440.}, + /* GFLOPS 0.213 x 1 = 0.213 */ {{3, 3}, {{1, 256, 19, 19}}, 128, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", false, 212972672.}, + /* GFLOPS 0.212 x 1 = 0.212 */ {{7, 7}, {{1, 3, 300, 300}}, 32, 1, {2, 2}, {1, 1}, {3, 3}, {0, 0}, "", true, 212400000.}, + /* GFLOPS 0.211 x 1 = 0.211 */ {{11, 11}, {{1, 3, 227, 227}}, 96, 1, {4, 4}, {1, 1}, {0, 0}, {0, 0}, "", true, 211120800.}, + /* GFLOPS 0.210 x 1 = 0.210 */ {{3, 3}, {{1, 64, 38, 50}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 210307200.}, + /* GFLOPS 0.210 x 1 = 0.210 */ {{1, 1}, {{1, 1024, 10, 10}}, 1024, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 209817600.}, + /* GFLOPS 0.210 x 1 = 0.210 */ {{1, 1}, {{1, 1024, 10, 10}}, 1024, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 209817600.}, + /* GFLOPS 0.104 x 2 = 0.208 */ {{3, 3}, {{1, 32, 75, 75}}, 32, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", false, 103860000.}, + /* GFLOPS 0.206 x 1 = 0.206 */ {{1, 1}, {{1, 256, 56, 56}}, 512, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "", false, 205922304.}, + /* GFLOPS 0.206 x 1 = 0.206 */ {{1, 1}, {{1, 256, 56, 56}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 205922304.}, + /* GFLOPS 0.103 x 2 = 0.206 */ {{1, 1}, {{1, 256, 56, 56}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 102961152.}, + /* GFLOPS 0.206 x 1 = 0.206 */ {{1, 1}, {{1, 512, 28, 28}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 205721600.}, + /* GFLOPS 0.206 x 1 = 0.206 */ {{1, 1}, {{1, 512, 28, 28}}, 1024, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "", false, 205721600.}, + /* GFLOPS 0.206 x 1 = 0.206 */ {{1, 1}, {{1, 1024, 14, 14}}, 512, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 205621248.}, + /* GFLOPS 0.206 x 1 = 0.206 */ {{1, 1}, {{1, 1024, 14, 14}}, 2048, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "", false, 205621248.}, + /* GFLOPS 0.103 x 2 = 0.206 */ {{1, 1}, {{1, 2048, 7, 7}}, 512, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 102785536.}, + /* GFLOPS 0.201 x 1 = 0.201 */ {{1, 1}, {{1, 512, 14, 14}}, 1000, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 200900000.}, + /* GFLOPS 0.200 x 1 = 0.200 */ {{3, 3}, {{1, 160, 19, 19}}, 192, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 199687872.}, + /* GFLOPS 0.190 x 1 = 0.190 */ {{1, 1}, {{1, 256, 38, 38}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 189637632.}, + /* GFLOPS 0.190 x 1 = 0.190 */ {{1, 1}, {{1, 256, 38, 38}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 189637632.}, + /* GFLOPS 0.047 x 4 = 0.190 */ {{1, 1}, {{1, 256, 38, 38}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 47409408.}, + /* GFLOPS 0.038 x 5 = 0.189 */ {{3, 3}, {{1, 32, 32, 64}}, 32, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 37814272.}, + /* GFLOPS 0.185 x 1 = 0.185 */ {{1, 1}, {{1, 128, 75, 75}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 185040000.}, + /* GFLOPS 0.185 x 1 = 0.185 */ {{1, 1}, {{1, 128, 75, 75}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 185040000.}, + /* GFLOPS 0.181 x 1 = 0.181 */ {{3, 3}, {{1, 160, 14, 14}}, 320, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 180696320.}, + /* GFLOPS 0.181 x 1 = 0.181 */ {{3, 3}, {{1, 160, 14, 14}}, 320, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 180696320.}, + /* GFLOPS 0.090 x 2 = 0.181 */ {{3, 3}, {{1, 224, 10, 10}}, 224, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 90339200.}, + /* GFLOPS 0.180 x 1 = 0.180 */ {{1, 1}, {{1, 224, 56, 56}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 180232192.}, + /* GFLOPS 0.174 x 1 = 0.174 */ {{3, 3}, {{1, 96, 28, 28}}, 128, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 173508608.}, + /* GFLOPS 0.174 x 1 = 0.174 */ {{3, 3}, {{1, 96, 28, 28}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 173508608.}, + /* GFLOPS 0.166 x 1 = 0.166 */ {{3, 3}, {{1, 160, 19, 19}}, 160, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 166406560.}, + /* GFLOPS 0.080 x 2 = 0.160 */ {{1, 1}, {{1, 576, 19, 19}}, 192, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 79916736.}, + /* GFLOPS 0.160 x 1 = 0.160 */ {{3, 3}, {{1, 128, 19, 19}}, 192, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 159764160.}, + /* GFLOPS 0.159 x 1 = 0.159 */ {{7, 7}, {{1, 3, 300, 300}}, 24, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 159300000.}, + /* GFLOPS 0.155 x 1 = 0.155 */ {{1, 1}, {{1, 192, 56, 56}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 154542080.}, + /* GFLOPS 0.146 x 1 = 0.146 */ {{3, 3}, {{1, 144, 14, 14}}, 288, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 146369664.}, + /* GFLOPS 0.146 x 1 = 0.146 */ {{3, 3}, {{1, 144, 14, 14}}, 288, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 146369664.}, + /* GFLOPS 0.072 x 2 = 0.144 */ {{1, 1}, {{1, 1024, 10, 10}}, 352, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 72124800.}, + /* GFLOPS 0.140 x 1 = 0.140 */ {{1, 1}, {{1, 576, 38, 50}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 140204800.}, + /* GFLOPS 0.017 x 8 = 0.138 */ {{1, 1}, {{1, 16, 64, 128}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 17301504.}, + /* GFLOPS 0.067 x 2 = 0.133 */ {{1, 1}, {{1, 576, 19, 19}}, 160, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 66597280.}, + /* GFLOPS 0.133 x 1 = 0.133 */ {{3, 3}, {{1, 128, 38, 38}}, 160, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 133136800.}, + /* GFLOPS 0.129 x 1 = 0.129 */ {{1, 1}, {{1, 160, 56, 56}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 128851968.}, + /* GFLOPS 0.128 x 1 = 0.128 */ {{3, 3}, {{1, 64, 24, 24}}, 192, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 127512576.}, + /* GFLOPS 0.120 x 1 = 0.120 */ {{5, 5}, {{1, 32, 28, 28}}, 96, 1, {1, 1}, {1, 1}, {2, 2}, {0, 0}, "", true, 120497664.}, + /* GFLOPS 0.120 x 1 = 0.120 */ {{5, 5}, {{1, 32, 28, 28}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 120497664.}, + /* GFLOPS 0.040 x 3 = 0.120 */ {{1, 1}, {{1, 96, 19, 19}}, 576, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 40131648.}, + /* GFLOPS 0.118 x 1 = 0.118 */ {{1, 1}, {{1, 320, 38, 38}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 118477312.}, + /* GFLOPS 0.017 x 7 = 0.118 */ {{1, 1}, {{1, 64, 64, 128}}, 16, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 16908288.}, + /* GFLOPS 0.039 x 3 = 0.118 */ {{1, 1}, {{1, 1024, 10, 10}}, 192, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 39340800.}, + /* GFLOPS 0.118 x 1 = 0.118 */ {{3, 3}, {{1, 256, 19, 19}}, 256, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 117990400.}, + /* GFLOPS 0.058 x 2 = 0.116 */ {{3, 3}, {{1, 16, 56, 56}}, 64, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 58003456.}, + /* GFLOPS 0.058 x 2 = 0.116 */ {{3, 3}, {{1, 32, 28, 28}}, 128, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 57903104.}, + /* GFLOPS 0.058 x 2 = 0.116 */ {{3, 3}, {{1, 64, 14, 14}}, 256, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 57852928.}, + /* GFLOPS 0.116 x 1 = 0.116 */ {{3, 3}, {{1, 128, 14, 14}}, 256, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 115655680.}, + /* GFLOPS 0.116 x 1 = 0.116 */ {{3, 3}, {{1, 128, 14, 14}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 115655680.}, + /* GFLOPS 0.112 x 1 = 0.112 */ {{1, 1}, {{1, 1024, 10, 10}}, 546, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 111875400.}, + /* GFLOPS 0.036 x 3 = 0.107 */ {{1, 1}, {{1, 192, 38, 38}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 35580160.}, + /* GFLOPS 0.107 x 1 = 0.107 */ {{3, 3}, {{1, 32, 75, 75}}, 128, 1, {2, 2}, {1, 1}, {1, 1}, {0, 0}, "", false, 106648064.}, + /* GFLOPS 0.107 x 1 = 0.107 */ {{3, 3}, {{1, 64, 38, 38}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 106555648.}, + /* GFLOPS 0.105 x 1 = 0.105 */ {{1, 1}, {{1, 512, 10, 10}}, 1024, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 104960000.}, + /* GFLOPS 0.105 x 1 = 0.105 */ {{1, 1}, {{1, 512, 10, 10}}, 1024, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 104960000.}, + /* GFLOPS 0.103 x 1 = 0.103 */ {{1, 1}, {{1, 128, 56, 56}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 103161856.}, + /* GFLOPS 0.051 x 2 = 0.103 */ {{1, 1}, {{1, 256, 28, 28}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 51480576.}, + /* GFLOPS 0.051 x 2 = 0.103 */ {{1, 1}, {{1, 256, 28, 28}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 51480576.}, + /* GFLOPS 0.101 x 1 = 0.101 */ {{1, 1}, {{1, 512, 19, 19}}, 273, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 101016825.}, + /* GFLOPS 0.096 x 1 = 0.096 */ {{1, 1}, {{1, 480, 28, 28}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 96438272.}, + /* GFLOPS 0.095 x 1 = 0.095 */ {{1, 1}, {{1, 128, 38, 38}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 95003648.}, + /* GFLOPS 0.095 x 1 = 0.095 */ {{1, 1}, {{1, 128, 38, 38}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 95003648.}, + /* GFLOPS 0.095 x 1 = 0.095 */ {{1, 1}, {{1, 256, 19, 19}}, 512, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 94818816.}, + /* GFLOPS 0.095 x 1 = 0.095 */ {{1, 1}, {{1, 256, 19, 19}}, 512, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 94818816.}, + /* GFLOPS 0.094 x 1 = 0.094 */ {{1, 1}, {{1, 32, 150, 150}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 93600000.}, + /* GFLOPS 0.094 x 1 = 0.094 */ {{1, 1}, {{1, 32, 150, 150}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 93600000.}, + /* GFLOPS 0.093 x 1 = 0.093 */ {{1, 1}, {{1, 512, 38, 50}}, 48, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 93480000.}, + /* GFLOPS 0.093 x 1 = 0.093 */ {{1, 1}, {{1, 576, 19, 19}}, 224, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 93236192.}, + /* GFLOPS 0.093 x 1 = 0.093 */ {{1, 1}, {{1, 64, 75, 75}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 92880000.}, + /* GFLOPS 0.093 x 1 = 0.093 */ {{1, 1}, {{1, 64, 75, 75}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 92880000.}, + /* GFLOPS 0.031 x 3 = 0.092 */ {{1, 1}, {{1, 160, 10, 10}}, 960, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 30816000.}, + /* GFLOPS 0.092 x 1 = 0.092 */ {{1, 1}, {{1, 192, 75, 100}}, 32, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 92400000.}, + /* GFLOPS 0.090 x 1 = 0.090 */ {{1, 1}, {{1, 448, 28, 28}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 90015744.}, + /* GFLOPS 0.045 x 2 = 0.090 */ {{3, 3}, {{1, 576, 19, 19}}, 12, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 44918508.}, + /* GFLOPS 0.089 x 1 = 0.089 */ {{3, 3}, {{1, 112, 14, 14}}, 224, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 88554368.}, + /* GFLOPS 0.089 x 1 = 0.089 */ {{3, 3}, {{1, 112, 14, 14}}, 224, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 88554368.}, + /* GFLOPS 0.021 x 4 = 0.084 */ {{5, 1}, {{1, 32, 32, 64}}, 32, 1, {1, 1}, {1, 1}, {2, 0}, {0, 0}, "", false, 21037056.}, + /* GFLOPS 0.021 x 4 = 0.084 */ {{1, 5}, {{1, 32, 32, 64}}, 32, 1, {1, 1}, {1, 1}, {0, 2}, {0, 0}, "", true, 21037056.}, + /* GFLOPS 0.084 x 1 = 0.084 */ {{1, 1}, {{1, 416, 28, 28}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 83593216.}, + /* GFLOPS 0.082 x 1 = 0.082 */ {{1, 1}, {{1, 320, 10, 10}}, 1280, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 82048000.}, + /* GFLOPS 0.040 x 2 = 0.080 */ {{1, 1}, {{1, 576, 19, 19}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 39958368.}, + /* GFLOPS 0.040 x 2 = 0.079 */ {{1, 1}, {{1, 24, 75, 75}}, 144, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 39690000.}, + /* GFLOPS 0.040 x 2 = 0.079 */ {{3, 3}, {{1, 3, 300, 300}}, 32, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 39600000.}, + /* GFLOPS 0.077 x 1 = 0.077 */ {{1, 1}, {{1, 96, 56, 56}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 77471744.}, + /* GFLOPS 0.077 x 1 = 0.077 */ {{3, 3}, {{1, 192, 10, 10}}, 224, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 77436800.}, + /* GFLOPS 0.077 x 1 = 0.077 */ {{1, 1}, {{1, 384, 28, 28}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 77170688.}, + /* GFLOPS 0.038 x 2 = 0.076 */ {{3, 3}, {{1, 32, 32, 64}}, 32, 1, {1, 1}, {8, 8}, {8, 8}, {0, 0}, "", true, 37814272.}, + /* GFLOPS 0.038 x 2 = 0.076 */ {{3, 3}, {{1, 32, 32, 64}}, 32, 1, {1, 1}, {4, 4}, {4, 4}, {0, 0}, "", true, 37814272.}, + /* GFLOPS 0.038 x 2 = 0.076 */ {{3, 3}, {{1, 32, 32, 64}}, 32, 1, {1, 1}, {2, 2}, {2, 2}, {0, 0}, "", true, 37814272.}, + /* GFLOPS 0.038 x 2 = 0.076 */ {{3, 3}, {{1, 32, 32, 64}}, 32, 1, {1, 1}, {16, 16}, {16, 16}, {0, 0}, "", true, 37814272.}, + /* GFLOPS 0.018 x 4 = 0.072 */ {{1, 1}, {{1, 64, 19, 19}}, 384, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 17882496.}, + /* GFLOPS 0.071 x 1 = 0.071 */ {{1, 1}, {{1, 16, 150, 150}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 71280000.}, + /* GFLOPS 0.071 x 1 = 0.071 */ {{1, 1}, {{1, 352, 28, 28}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 70748160.}, + /* GFLOPS 0.071 x 1 = 0.071 */ {{1, 1}, {{1, 24, 150, 150}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "VALID", true, 70560000.}, + /* GFLOPS 0.070 x 1 = 0.070 */ {{3, 3}, {{1, 96, 14, 14}}, 208, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 70487872.}, + /* GFLOPS 0.069 x 1 = 0.069 */ {{3, 3}, {{1, 96, 14, 14}}, 204, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 69132336.}, + /* GFLOPS 0.066 x 1 = 0.066 */ {{1, 1}, {{1, 1280, 10, 10}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 65561600.}, + /* GFLOPS 0.033 x 2 = 0.065 */ {{3, 3}, {{1, 48, 14, 14}}, 192, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 32551680.}, + /* GFLOPS 0.065 x 1 = 0.065 */ {{3, 3}, {{1, 192, 7, 7}}, 384, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 65046912.}, + /* GFLOPS 0.065 x 1 = 0.065 */ {{3, 3}, {{1, 192, 7, 7}}, 384, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 65046912.}, + /* GFLOPS 0.065 x 1 = 0.065 */ {{3, 3}, {{1, 160, 10, 10}}, 224, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 64534400.}, + /* GFLOPS 0.064 x 1 = 0.064 */ {{1, 1}, {{1, 320, 28, 28}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 64325632.}, + /* GFLOPS 0.032 x 2 = 0.064 */ {{3, 3}, {{1, 96, 12, 12}}, 128, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 31868928.}, + /* GFLOPS 0.061 x 1 = 0.061 */ {{1, 1}, {{1, 960, 10, 10}}, 320, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 61472000.}, + /* GFLOPS 0.031 x 2 = 0.061 */ {{1, 1}, {{1, 960, 10, 10}}, 160, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 30736000.}, + /* GFLOPS 0.060 x 1 = 0.060 */ {{3, 3}, {{1, 96, 38, 38}}, 96, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 59920224.}, + /* GFLOPS 0.059 x 1 = 0.059 */ {{1, 1}, {{1, 320, 38, 38}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 59238656.}, + /* GFLOPS 0.059 x 1 = 0.059 */ {{3, 3}, {{1, 128, 19, 19}}, 256, 1, {2, 2}, {1, 1}, {1, 1}, {0, 0}, "", true, 59008000.}, + /* GFLOPS 0.059 x 1 = 0.059 */ {{3, 3}, {{1, 256, 10, 10}}, 512, 1, {2, 2}, {1, 1}, {1, 1}, {0, 0}, "", true, 58995200.}, + /* GFLOPS 0.059 x 1 = 0.059 */ {{3, 3}, {{1, 256, 10, 10}}, 512, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 58995200.}, + /* GFLOPS 0.059 x 1 = 0.059 */ {{3, 3}, {{1, 256, 10, 10}}, 512, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 58995200.}, + /* GFLOPS 0.058 x 1 = 0.058 */ {{1, 1}, {{1, 288, 28, 28}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 57903104.}, + /* GFLOPS 0.004 x 16 = 0.058 */ {{3, 3}, {{1, 128, 7, 7}}, 32, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", false, 3614240.}, + /* GFLOPS 0.055 x 1 = 0.055 */ {{3, 3}, {{1, 1280, 10, 10}}, 24, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 55298400.}, + /* GFLOPS 0.018 x 3 = 0.054 */ {{1, 1}, {{1, 32, 38, 38}}, 192, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 18021120.}, + /* GFLOPS 0.018 x 3 = 0.053 */ {{1, 1}, {{1, 384, 19, 19}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 17766976.}, + /* GFLOPS 0.053 x 1 = 0.053 */ {{3, 3}, {{1, 128, 38, 38}}, 16, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 53254720.}, + /* GFLOPS 0.053 x 1 = 0.053 */ {{1, 1}, {{1, 528, 14, 14}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 53036032.}, + /* GFLOPS 0.053 x 1 = 0.053 */ {{1, 1}, {{1, 528, 14, 14}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 53036032.}, + /* GFLOPS 0.052 x 1 = 0.052 */ {{1, 1}, {{1, 1024, 10, 10}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 52454400.}, + /* GFLOPS 0.052 x 1 = 0.052 */ {{1, 1}, {{1, 1024, 10, 10}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 52454400.}, + /* GFLOPS 0.052 x 1 = 0.052 */ {{1, 1}, {{1, 1024, 10, 10}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 52454400.}, + /* GFLOPS 0.026 x 2 = 0.052 */ {{1, 1}, {{1, 1024, 10, 10}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 26227200.}, + /* GFLOPS 0.052 x 1 = 0.052 */ {{1, 1}, {{1, 64, 56, 56}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 51781632.}, + /* GFLOPS 0.051 x 1 = 0.051 */ {{1, 1}, {{1, 256, 56, 56}}, 128, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "", false, 51480576.}, + /* GFLOPS 0.051 x 1 = 0.051 */ {{1, 1}, {{1, 256, 28, 28}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 51480576.}, + /* GFLOPS 0.051 x 1 = 0.051 */ {{1, 1}, {{1, 512, 28, 28}}, 256, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "", false, 51430400.}, + /* GFLOPS 0.026 x 2 = 0.051 */ {{1, 1}, {{1, 512, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 25715200.}, + /* GFLOPS 0.026 x 2 = 0.051 */ {{1, 1}, {{1, 512, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 25715200.}, + /* GFLOPS 0.013 x 4 = 0.051 */ {{1, 1}, {{1, 512, 14, 14}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 12857600.}, + /* GFLOPS 0.051 x 1 = 0.051 */ {{1, 1}, {{1, 1024, 14, 14}}, 512, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "", false, 51405312.}, + /* GFLOPS 0.050 x 1 = 0.050 */ {{1, 1}, {{1, 992, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 49799680.}, + /* GFLOPS 0.048 x 1 = 0.048 */ {{1, 1}, {{1, 960, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 48194048.}, + /* GFLOPS 0.047 x 1 = 0.047 */ {{1, 1}, {{1, 256, 19, 19}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 47409408.}, + /* GFLOPS 0.047 x 1 = 0.047 */ {{1, 1}, {{1, 512, 38, 50}}, 24, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 46740000.}, + /* GFLOPS 0.047 x 1 = 0.047 */ {{1, 1}, {{1, 928, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 46588416.}, + /* GFLOPS 0.046 x 1 = 0.046 */ {{1, 1}, {{1, 64, 75, 75}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 46440000.}, + /* GFLOPS 0.023 x 2 = 0.045 */ {{3, 3}, {{1, 256, 3, 3}}, 546, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 22648626.}, + /* GFLOPS 0.045 x 1 = 0.045 */ {{3, 3}, {{1, 160, 7, 7}}, 320, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 45174080.}, + /* GFLOPS 0.045 x 1 = 0.045 */ {{3, 3}, {{1, 160, 7, 7}}, 320, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 45174080.}, + /* GFLOPS 0.045 x 1 = 0.045 */ {{1, 1}, {{1, 224, 28, 28}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 45058048.}, + /* GFLOPS 0.023 x 2 = 0.045 */ {{1, 1}, {{1, 512, 14, 14}}, 112, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 22500800.}, + /* GFLOPS 0.045 x 1 = 0.045 */ {{1, 1}, {{1, 896, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 44982784.}, + /* GFLOPS 0.045 x 1 = 0.045 */ {{3, 3}, {{1, 3, 227, 227}}, 64, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "", true, 44946880.}, + /* GFLOPS 0.044 x 1 = 0.044 */ {{3, 3}, {{1, 128, 19, 19}}, 192, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 44256000.}, + /* GFLOPS 0.044 x 1 = 0.044 */ {{3, 3}, {{1, 1024, 10, 10}}, 24, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 44239200.}, + /* GFLOPS 0.043 x 1 = 0.043 */ {{7, 7}, {{1, 3, 96, 96}}, 64, 1, {2, 2}, {1, 1}, {3, 3}, {0, 0}, "", true, 43499520.}, + /* GFLOPS 0.043 x 1 = 0.043 */ {{1, 1}, {{1, 864, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 43377152.}, + /* GFLOPS 0.042 x 1 = 0.042 */ {{1, 1}, {{1, 832, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 41771520.}, + /* GFLOPS 0.040 x 1 = 0.040 */ {{5, 5}, {{1, 32, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {2, 2}, {0, 0}, "", true, 40165888.}, + /* GFLOPS 0.040 x 1 = 0.040 */ {{5, 5}, {{1, 32, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 40165888.}, + /* GFLOPS 0.040 x 1 = 0.040 */ {{1, 1}, {{1, 800, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 40165888.}, + /* GFLOPS 0.040 x 1 = 0.040 */ {{3, 3}, {{1, 64, 19, 19}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 39958368.}, + /* GFLOPS 0.040 x 1 = 0.040 */ {{3, 3}, {{1, 256, 19, 19}}, 24, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 39932376.}, + /* GFLOPS 0.040 x 1 = 0.040 */ {{3, 3}, {{1, 3, 300, 300}}, 32, 1, {2, 2}, {1, 1}, {1, 1}, {0, 0}, "", true, 39600000.}, + /* GFLOPS 0.039 x 1 = 0.039 */ {{1, 1}, {{1, 144, 75, 75}}, 24, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 39015000.}, + /* GFLOPS 0.039 x 1 = 0.039 */ {{1, 1}, {{1, 192, 28, 28}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 38635520.}, + /* GFLOPS 0.039 x 1 = 0.039 */ {{1, 1}, {{1, 768, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 38560256.}, + /* GFLOPS 0.037 x 1 = 0.037 */ {{1, 1}, {{1, 736, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 36954624.}, + /* GFLOPS 0.036 x 1 = 0.036 */ {{1, 1}, {{1, 480, 14, 14}}, 192, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 36164352.}, + /* GFLOPS 0.036 x 1 = 0.036 */ {{1, 1}, {{1, 480, 14, 14}}, 192, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 36164352.}, + /* GFLOPS 0.018 x 2 = 0.036 */ {{1, 1}, {{1, 192, 38, 38}}, 32, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 17790080.}, + /* GFLOPS 0.035 x 1 = 0.035 */ {{1, 1}, {{1, 704, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 35348992.}, + /* GFLOPS 0.034 x 1 = 0.034 */ {{1, 1}, {{1, 672, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 33743360.}, + /* GFLOPS 0.034 x 1 = 0.034 */ {{1, 1}, {{1, 128, 32, 64}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 33685504.}, + /* GFLOPS 0.034 x 1 = 0.034 */ {{2, 2}, {{1, 64, 64, 128}}, 32, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "", false, 33619968.}, + /* GFLOPS 0.033 x 1 = 0.033 */ {{1, 1}, {{1, 528, 14, 14}}, 160, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 33147520.}, + /* GFLOPS 0.033 x 1 = 0.033 */ {{1, 1}, {{1, 528, 14, 14}}, 160, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 33147520.}, + /* GFLOPS 0.033 x 1 = 0.033 */ {{1, 1}, {{1, 1024, 10, 10}}, 160, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 32784000.}, + /* GFLOPS 0.032 x 1 = 0.032 */ {{1, 1}, {{1, 160, 28, 28}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 32212992.}, + /* GFLOPS 0.032 x 1 = 0.032 */ {{1, 1}, {{1, 512, 14, 14}}, 160, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 32144000.}, + /* GFLOPS 0.032 x 1 = 0.032 */ {{1, 1}, {{1, 640, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 32137728.}, + /* GFLOPS 0.032 x 1 = 0.032 */ {{1, 1}, {{1, 508, 14, 14}}, 160, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 31893120.}, + /* GFLOPS 0.031 x 1 = 0.031 */ {{1, 1}, {{1, 832, 7, 7}}, 384, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 31328640.}, + /* GFLOPS 0.031 x 1 = 0.031 */ {{1, 1}, {{1, 832, 7, 7}}, 384, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 31328640.}, + /* GFLOPS 0.031 x 1 = 0.031 */ {{1, 1}, {{1, 608, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 30532096.}, + /* GFLOPS 0.015 x 2 = 0.030 */ {{5, 5}, {{1, 24, 14, 14}}, 64, 1, {1, 1}, {1, 1}, {2, 2}, {0, 0}, "", true, 15065344.}, + /* GFLOPS 0.015 x 2 = 0.030 */ {{5, 5}, {{1, 24, 14, 14}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 15065344.}, + /* GFLOPS 0.015 x 2 = 0.030 */ {{5, 5}, {{1, 48, 7, 7}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 15059072.}, + /* GFLOPS 0.029 x 1 = 0.029 */ {{3, 3}, {{1, 256, 10, 10}}, 256, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 29497600.}, + /* GFLOPS 0.029 x 1 = 0.029 */ {{1, 1}, {{1, 192, 28, 28}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 28976640.}, + /* GFLOPS 0.029 x 1 = 0.029 */ {{1, 1}, {{1, 192, 28, 28}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 28976640.}, + /* GFLOPS 0.029 x 1 = 0.029 */ {{1, 1}, {{1, 512, 14, 14}}, 144, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 28929600.}, + /* GFLOPS 0.029 x 1 = 0.029 */ {{1, 1}, {{1, 512, 14, 14}}, 144, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 28929600.}, + /* GFLOPS 0.029 x 1 = 0.029 */ {{1, 1}, {{1, 576, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 28926464.}, + /* GFLOPS 0.027 x 1 = 0.027 */ {{1, 1}, {{1, 544, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 27320832.}, + /* GFLOPS 0.027 x 1 = 0.027 */ {{1, 1}, {{1, 384, 19, 19}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 26650464.}, + /* GFLOPS 0.027 x 1 = 0.027 */ {{1, 1}, {{1, 576, 19, 19}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 26638912.}, + /* GFLOPS 0.027 x 1 = 0.027 */ {{3, 3}, {{1, 128, 38, 38}}, 8, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 26627360.}, + /* GFLOPS 0.027 x 1 = 0.027 */ {{1, 1}, {{1, 528, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 26518016.}, + /* GFLOPS 0.027 x 1 = 0.027 */ {{1, 1}, {{1, 528, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 26518016.}, + /* GFLOPS 0.026 x 1 = 0.026 */ {{1, 1}, {{1, 96, 75, 75}}, 24, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 26055000.}, + /* GFLOPS 0.026 x 1 = 0.026 */ {{1, 1}, {{1, 64, 56, 56}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "VALID", true, 25890816.}, + /* GFLOPS 0.026 x 1 = 0.026 */ {{1, 1}, {{1, 64, 56, 56}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 25890816.}, + /* GFLOPS 0.026 x 1 = 0.026 */ {{1, 1}, {{1, 64, 56, 56}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 25890816.}, + /* GFLOPS 0.026 x 1 = 0.026 */ {{1, 1}, {{1, 1024, 10, 10}}, 126, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 25817400.}, + /* GFLOPS 0.026 x 1 = 0.026 */ {{1, 1}, {{1, 128, 28, 28}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 25790464.}, + /* GFLOPS 0.026 x 1 = 0.026 */ {{1, 1}, {{1, 256, 28, 28}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 25740288.}, + /* GFLOPS 0.026 x 1 = 0.026 */ {{1, 1}, {{1, 256, 28, 28}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 25740288.}, + /* GFLOPS 0.013 x 2 = 0.026 */ {{1, 1}, {{1, 256, 28, 28}}, 32, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 12870144.}, + /* GFLOPS 0.026 x 1 = 0.026 */ {{1, 1}, {{1, 512, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 25715200.}, + /* GFLOPS 0.013 x 2 = 0.026 */ {{1, 1}, {{1, 512, 14, 14}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 12857600.}, + /* GFLOPS 0.024 x 1 = 0.024 */ {{1, 1}, {{1, 480, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 24109568.}, + /* GFLOPS 0.024 x 1 = 0.024 */ {{1, 1}, {{1, 128, 38, 38}}, 256, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "", false, 23750912.}, + /* GFLOPS 0.024 x 1 = 0.024 */ {{1, 1}, {{1, 256, 19, 19}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 23704704.}, + /* GFLOPS 0.023 x 1 = 0.023 */ {{3, 3}, {{1, 3, 256, 512}}, 13, 1, {2, 2}, {1, 1}, {1, 1}, {0, 0}, "", true, 23429120.}, + /* GFLOPS 0.023 x 1 = 0.023 */ {{1, 1}, {{1, 32, 150, 150}}, 16, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 23400000.}, + /* GFLOPS 0.023 x 1 = 0.023 */ {{1, 1}, {{1, 512, 19, 19}}, 63, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 23311575.}, + /* GFLOPS 0.023 x 1 = 0.023 */ {{1, 1}, {{1, 448, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 22503936.}, + /* GFLOPS 0.023 x 1 = 0.023 */ {{1, 1}, {{1, 512, 14, 14}}, 112, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 22500800.}, + /* GFLOPS 0.022 x 1 = 0.022 */ {{1, 1}, {{1, 508, 14, 14}}, 112, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 22325184.}, + /* GFLOPS 0.021 x 1 = 0.021 */ {{3, 3}, {{1, 128, 12, 12}}, 256, 1, {2, 2}, {1, 1}, {1, 1}, {0, 0}, "", true, 21242880.}, + /* GFLOPS 0.021 x 1 = 0.021 */ {{1, 1}, {{1, 416, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 20898304.}, + /* GFLOPS 0.021 x 1 = 0.021 */ {{1, 1}, {{1, 832, 7, 7}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 20885760.}, + /* GFLOPS 0.021 x 1 = 0.021 */ {{1, 1}, {{1, 832, 7, 7}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 20885760.}, + /* GFLOPS 0.010 x 2 = 0.021 */ {{1, 1}, {{1, 832, 7, 7}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 10442880.}, + /* GFLOPS 0.010 x 2 = 0.021 */ {{1, 1}, {{1, 832, 7, 7}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 10442880.}, + /* GFLOPS 0.010 x 2 = 0.020 */ {{3, 3}, {{1, 256, 2, 2}}, 546, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 10066056.}, + /* GFLOPS 0.020 x 1 = 0.020 */ {{5, 5}, {{1, 16, 28, 28}}, 32, 1, {1, 1}, {1, 1}, {2, 2}, {0, 0}, "", true, 20095488.}, + /* GFLOPS 0.020 x 1 = 0.020 */ {{5, 5}, {{1, 16, 28, 28}}, 32, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 20095488.}, + /* GFLOPS 0.020 x 1 = 0.020 */ {{5, 5}, {{1, 32, 14, 14}}, 64, 1, {1, 1}, {1, 1}, {2, 2}, {0, 0}, "", true, 20082944.}, + /* GFLOPS 0.020 x 1 = 0.020 */ {{5, 5}, {{1, 32, 14, 14}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 20082944.}, + /* GFLOPS 0.020 x 1 = 0.020 */ {{3, 3}, {{1, 256, 19, 19}}, 12, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 19966188.}, + /* GFLOPS 0.019 x 1 = 0.019 */ {{1, 1}, {{1, 192, 28, 28}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 19317760.}, + /* GFLOPS 0.019 x 1 = 0.019 */ {{1, 1}, {{1, 192, 28, 28}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 19317760.}, + /* GFLOPS 0.019 x 1 = 0.019 */ {{1, 1}, {{1, 384, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 19292672.}, + /* GFLOPS 0.018 x 1 = 0.018 */ {{1, 1}, {{1, 576, 10, 10}}, 160, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 18448000.}, + /* GFLOPS 0.018 x 1 = 0.018 */ {{1, 1}, {{1, 480, 14, 14}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 18082176.}, + /* GFLOPS 0.018 x 1 = 0.018 */ {{1, 1}, {{1, 480, 14, 14}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 18082176.}, + /* GFLOPS 0.018 x 1 = 0.018 */ {{1, 1}, {{1, 192, 38, 38}}, 32, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 17790080.}, + /* GFLOPS 0.018 x 1 = 0.018 */ {{1, 1}, {{1, 352, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 17687040.}, + /* GFLOPS 0.017 x 1 = 0.017 */ {{2, 2}, {{1, 16, 128, 256}}, 16, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "", false, 16908288.}, + /* GFLOPS 0.016 x 1 = 0.016 */ {{1, 1}, {{1, 320, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 16081408.}, + /* GFLOPS 0.016 x 1 = 0.016 */ {{1, 1}, {{1, 832, 7, 7}}, 192, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 15664320.}, + /* GFLOPS 0.016 x 1 = 0.016 */ {{1, 1}, {{1, 832, 7, 7}}, 192, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 15664320.}, + /* GFLOPS 0.015 x 1 = 0.015 */ {{5, 5}, {{1, 48, 7, 7}}, 128, 1, {1, 1}, {1, 1}, {2, 2}, {0, 0}, "", true, 15059072.}, + /* GFLOPS 0.015 x 1 = 0.015 */ {{5, 5}, {{1, 32, 12, 12}}, 64, 1, {1, 1}, {1, 1}, {2, 2}, {0, 0}, "", true, 14754816.}, + /* GFLOPS 0.014 x 1 = 0.014 */ {{1, 1}, {{1, 288, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 14475776.}, + /* GFLOPS 0.014 x 1 = 0.014 */ {{1, 1}, {{1, 512, 5, 5}}, 546, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 13991250.}, + /* GFLOPS 0.013 x 1 = 0.013 */ {{1, 1}, {{1, 144, 38, 38}}, 32, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 13354112.}, + /* GFLOPS 0.007 x 2 = 0.013 */ {{1, 1}, {{1, 16, 56, 56}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 6623232.}, + /* GFLOPS 0.013 x 1 = 0.013 */ {{1, 1}, {{1, 832, 7, 7}}, 160, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 13053600.}, + /* GFLOPS 0.013 x 1 = 0.013 */ {{1, 1}, {{1, 832, 7, 7}}, 160, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 13053600.}, + /* GFLOPS 0.007 x 2 = 0.013 */ {{1, 1}, {{1, 32, 28, 28}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 6522880.}, + /* GFLOPS 0.006 x 2 = 0.013 */ {{1, 1}, {{1, 64, 14, 14}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 6472704.}, + /* GFLOPS 0.013 x 1 = 0.013 */ {{1, 1}, {{1, 128, 56, 56}}, 16, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 12895232.}, + /* GFLOPS 0.013 x 1 = 0.013 */ {{1, 1}, {{1, 256, 28, 28}}, 32, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 12870144.}, + /* GFLOPS 0.013 x 1 = 0.013 */ {{1, 1}, {{1, 256, 14, 14}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 12870144.}, + /* GFLOPS 0.013 x 1 = 0.013 */ {{1, 1}, {{1, 508, 14, 14}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 12757248.}, + /* GFLOPS 0.012 x 1 = 0.012 */ {{1, 1}, {{1, 992, 7, 7}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 12449920.}, + /* GFLOPS 0.012 x 1 = 0.012 */ {{1, 1}, {{1, 480, 14, 14}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 12054784.}, + /* GFLOPS 0.012 x 1 = 0.012 */ {{1, 1}, {{1, 480, 14, 14}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 12054784.}, + /* GFLOPS 0.012 x 1 = 0.012 */ {{1, 1}, {{1, 960, 7, 7}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 12048512.}, + /* GFLOPS 0.012 x 1 = 0.012 */ {{1, 1}, {{1, 32, 75, 75}}, 128, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "", false, 12014080.}, + /* GFLOPS 0.012 x 1 = 0.012 */ {{3, 3}, {{1, 96, 6, 6}}, 192, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 11950848.}, + /* GFLOPS 0.006 x 2 = 0.012 */ {{3, 3}, {{1, 96, 3, 3}}, 384, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 5975424.}, + /* GFLOPS 0.012 x 1 = 0.012 */ {{1, 1}, {{1, 320, 12, 12}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 11814912.}, + /* GFLOPS 0.012 x 1 = 0.012 */ {{1, 1}, {{1, 640, 6, 6}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 11805696.}, + /* GFLOPS 0.012 x 1 = 0.012 */ {{1, 1}, {{1, 928, 7, 7}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 11647104.}, + /* GFLOPS 0.011 x 1 = 0.011 */ {{1, 1}, {{1, 896, 7, 7}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 11245696.}, + /* GFLOPS 0.011 x 1 = 0.011 */ {{3, 3}, {{1, 256, 10, 10}}, 24, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 11061600.}, + /* GFLOPS 0.006 x 2 = 0.011 */ {{3, 3}, {{1, 512, 5, 5}}, 24, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 5530200.}, + /* GFLOPS 0.011 x 1 = 0.011 */ {{1, 1}, {{1, 864, 7, 7}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 10844288.}, + /* GFLOPS 0.010 x 1 = 0.010 */ {{1, 1}, {{1, 832, 7, 7}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 10442880.}, + /* GFLOPS 0.010 x 1 = 0.010 */ {{5, 5}, {{1, 32, 7, 7}}, 128, 1, {1, 1}, {1, 1}, {2, 2}, {0, 0}, "", true, 10041472.}, + /* GFLOPS 0.010 x 1 = 0.010 */ {{1, 1}, {{1, 800, 7, 7}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 10041472.}, + /* GFLOPS 0.010 x 1 = 0.010 */ {{1, 1}, {{1, 192, 28, 28}}, 32, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 9658880.}, + /* GFLOPS 0.010 x 1 = 0.010 */ {{1, 1}, {{1, 192, 28, 28}}, 32, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 9658880.}, + /* GFLOPS 0.010 x 1 = 0.010 */ {{1, 1}, {{1, 384, 14, 14}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 9646336.}, + /* GFLOPS 0.005 x 2 = 0.010 */ {{1, 1}, {{1, 512, 14, 14}}, 24, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 4821600.}, + /* GFLOPS 0.010 x 1 = 0.010 */ {{1, 1}, {{1, 768, 7, 7}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 9640064.}, + /* GFLOPS 0.010 x 1 = 0.010 */ {{3, 3}, {{1, 4, 128, 256}}, 4, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 9568256.}, + /* GFLOPS 0.005 x 2 = 0.009 */ {{1, 1}, {{1, 4, 128, 256}}, 16, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 4718592.}, + /* GFLOPS 0.009 x 1 = 0.009 */ {{1, 1}, {{1, 736, 7, 7}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 9238656.}, + /* GFLOPS 0.009 x 1 = 0.009 */ {{1, 1}, {{1, 192, 19, 19}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 8895040.}, + /* GFLOPS 0.009 x 1 = 0.009 */ {{1, 1}, {{1, 704, 7, 7}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 8837248.}, + /* GFLOPS 0.008 x 1 = 0.008 */ {{1, 1}, {{1, 672, 7, 7}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 8435840.}, + /* GFLOPS 0.008 x 1 = 0.008 */ {{1, 1}, {{1, 128, 32, 64}}, 16, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 8421376.}, + /* GFLOPS 0.008 x 1 = 0.008 */ {{1, 1}, {{1, 640, 7, 7}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 8034432.}, + /* GFLOPS 0.004 x 2 = 0.008 */ {{1, 1}, {{1, 832, 7, 7}}, 48, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 3916080.}, + /* GFLOPS 0.008 x 1 = 0.008 */ {{1, 1}, {{1, 608, 7, 7}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 7633024.}, + /* GFLOPS 0.008 x 1 = 0.008 */ {{5, 5}, {{1, 16, 14, 14}}, 48, 1, {1, 1}, {1, 1}, {2, 2}, {0, 0}, "", true, 7535808.}, + /* GFLOPS 0.008 x 1 = 0.008 */ {{5, 5}, {{1, 16, 14, 14}}, 48, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 7535808.}, + /* GFLOPS 0.004 x 2 = 0.007 */ {{3, 3}, {{1, 64, 5, 5}}, 128, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 3689600.}, + /* GFLOPS 0.007 x 1 = 0.007 */ {{1, 1}, {{1, 640, 6, 6}}, 160, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 7378560.}, + /* GFLOPS 0.004 x 2 = 0.007 */ {{1, 1}, {{1, 48, 14, 14}}, 192, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 3650304.}, + /* GFLOPS 0.007 x 1 = 0.007 */ {{1, 1}, {{1, 384, 14, 14}}, 48, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 7234752.}, + /* GFLOPS 0.007 x 1 = 0.007 */ {{1, 1}, {{1, 576, 7, 7}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 7231616.}, + /* GFLOPS 0.007 x 1 = 0.007 */ {{1, 1}, {{1, 256, 12, 12}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 7091712.}, + /* GFLOPS 0.007 x 1 = 0.007 */ {{1, 1}, {{1, 544, 7, 7}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 6830208.}, + /* GFLOPS 0.007 x 1 = 0.007 */ {{3, 3}, {{1, 160, 6, 6}}, 256, 1, {2, 2}, {1, 1}, {1, 1}, {0, 0}, "", true, 6637824.}, + /* GFLOPS 0.007 x 1 = 0.007 */ {{1, 1}, {{1, 528, 14, 14}}, 32, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 6629504.}, + /* GFLOPS 0.007 x 1 = 0.007 */ {{1, 1}, {{1, 528, 14, 14}}, 32, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 6629504.}, + /* GFLOPS 0.007 x 1 = 0.007 */ {{1, 1}, {{1, 256, 5, 5}}, 512, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 6566400.}, + /* GFLOPS 0.003 x 2 = 0.007 */ {{1, 1}, {{1, 512, 5, 5}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 3280000.}, + /* GFLOPS 0.006 x 1 = 0.006 */ {{1, 1}, {{1, 64, 56, 56}}, 16, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 6472704.}, + /* GFLOPS 0.006 x 1 = 0.006 */ {{1, 1}, {{1, 128, 28, 28}}, 32, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 6447616.}, + /* GFLOPS 0.006 x 1 = 0.006 */ {{1, 1}, {{1, 512, 7, 7}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 6428800.}, + /* GFLOPS 0.006 x 1 = 0.006 */ {{1, 1}, {{1, 512, 14, 14}}, 32, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 6428800.}, + /* GFLOPS 0.006 x 1 = 0.006 */ {{1, 1}, {{1, 512, 14, 14}}, 32, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 6428800.}, + /* GFLOPS 0.006 x 1 = 0.006 */ {{3, 3}, {{1, 256, 10, 10}}, 12, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 5530800.}, + /* GFLOPS 0.005 x 1 = 0.005 */ {{1, 1}, {{1, 192, 12, 12}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 5322240.}, + /* GFLOPS 0.005 x 1 = 0.005 */ {{3, 3}, {{1, 128, 5, 5}}, 256, 1, {2, 2}, {1, 1}, {1, 1}, {0, 0}, "", true, 5310720.}, + /* GFLOPS 0.005 x 1 = 0.005 */ {{3, 3}, {{1, 128, 5, 5}}, 256, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 5310720.}, + /* GFLOPS 0.005 x 1 = 0.005 */ {{3, 3}, {{1, 128, 5, 5}}, 256, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 5310720.}, + /* GFLOPS 0.005 x 1 = 0.005 */ {{1, 1}, {{1, 1024, 10, 10}}, 24, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 4917600.}, + /* GFLOPS 0.005 x 1 = 0.005 */ {{1, 1}, {{1, 1024, 10, 10}}, 24, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 4917600.}, + /* GFLOPS 0.005 x 1 = 0.005 */ {{1, 1}, {{1, 192, 28, 28}}, 16, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 4829440.}, + /* GFLOPS 0.005 x 1 = 0.005 */ {{1, 1}, {{1, 192, 28, 28}}, 16, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 4829440.}, + /* GFLOPS 0.005 x 1 = 0.005 */ {{1, 1}, {{1, 256, 14, 14}}, 48, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 4826304.}, + /* GFLOPS 0.005 x 1 = 0.005 */ {{1, 1}, {{1, 512, 14, 14}}, 24, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 4821600.}, + /* GFLOPS 0.005 x 1 = 0.005 */ {{1, 1}, {{1, 508, 14, 14}}, 24, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 4783968.}, + /* GFLOPS 0.005 x 1 = 0.005 */ {{1, 1}, {{1, 64, 24, 24}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 4755456.}, + /* GFLOPS 0.005 x 1 = 0.005 */ {{1, 1}, {{1, 256, 12, 12}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 4727808.}, + /* GFLOPS 0.005 x 1 = 0.005 */ {{1, 1}, {{1, 1024, 3, 3}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 4720896.}, + /* GFLOPS 0.004 x 1 = 0.004 */ {{1, 1}, {{1, 512, 19, 19}}, 12, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 4440300.}, + /* GFLOPS 0.004 x 1 = 0.004 */ {{1, 1}, {{1, 512, 19, 19}}, 12, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 4440300.}, + /* GFLOPS 0.004 x 1 = 0.004 */ {{1, 1}, {{1, 640, 6, 6}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 4427136.}, + /* GFLOPS 0.004 x 1 = 0.004 */ {{1, 1}, {{1, 16, 128, 256}}, 4, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 4325376.}, + /* GFLOPS 0.004 x 1 = 0.004 */ {{1, 1}, {{1, 64, 64, 128}}, 4, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", false, 4227072.}, + /* GFLOPS 0.004 x 1 = 0.004 */ {{1, 1}, {{1, 832, 7, 7}}, 48, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 3916080.}, + /* GFLOPS 0.004 x 1 = 0.004 */ {{5, 5}, {{1, 16, 12, 12}}, 32, 1, {1, 1}, {1, 1}, {2, 2}, {0, 0}, "", true, 3691008.}, + /* GFLOPS 0.004 x 1 = 0.004 */ {{3, 3}, {{1, 64, 10, 10}}, 128, 1, {2, 2}, {1, 1}, {1, 1}, {0, 0}, "", true, 3689600.}, + /* GFLOPS 0.004 x 1 = 0.004 */ {{5, 5}, {{1, 32, 6, 6}}, 64, 1, {1, 1}, {1, 1}, {2, 2}, {0, 0}, "", true, 3688704.}, + /* GFLOPS 0.004 x 1 = 0.004 */ {{5, 5}, {{1, 32, 12, 12}}, 64, 1, {2, 2}, {1, 1}, {2, 2}, {0, 0}, "", true, 3688704.}, + /* GFLOPS 0.004 x 1 = 0.004 */ {{5, 5}, {{1, 64, 6, 6}}, 128, 1, {2, 2}, {1, 1}, {2, 2}, {0, 0}, "", true, 3687552.}, + /* GFLOPS 0.004 x 1 = 0.004 */ {{1, 1}, {{1, 192, 12, 12}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 3548160.}, + /* GFLOPS 0.003 x 1 = 0.003 */ {{1, 1}, {{1, 736, 3, 3}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 3393792.}, + /* GFLOPS 0.003 x 1 = 0.003 */ {{1, 1}, {{1, 256, 10, 10}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 3283200.}, + /* GFLOPS 0.003 x 1 = 0.003 */ {{1, 1}, {{1, 512, 5, 5}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 3280000.}, + /* GFLOPS 0.003 x 1 = 0.003 */ {{1, 1}, {{1, 512, 5, 5}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 3280000.}, + /* GFLOPS 0.003 x 1 = 0.003 */ {{1, 1}, {{1, 512, 5, 5}}, 126, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 3228750.}, + /* GFLOPS 0.003 x 1 = 0.003 */ {{1, 1}, {{1, 480, 14, 14}}, 16, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 3013696.}, + /* GFLOPS 0.003 x 1 = 0.003 */ {{1, 1}, {{1, 480, 14, 14}}, 16, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 3013696.}, + /* GFLOPS 0.003 x 1 = 0.003 */ {{1, 1}, {{1, 320, 12, 12}}, 32, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 2953728.}, + /* GFLOPS 0.003 x 1 = 0.003 */ {{1, 1}, {{1, 640, 6, 6}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 2951424.}, + /* GFLOPS 0.003 x 1 = 0.003 */ {{3, 3}, {{1, 128, 5, 5}}, 128, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 2655360.}, + /* GFLOPS 0.003 x 1 = 0.003 */ {{1, 1}, {{1, 832, 7, 7}}, 32, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 2610720.}, + /* GFLOPS 0.003 x 1 = 0.003 */ {{1, 1}, {{1, 256, 3, 3}}, 546, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 2520882.}, + /* GFLOPS 0.001 x 2 = 0.003 */ {{3, 3}, {{1, 128, 1, 1}}, 546, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 1258530.}, + /* GFLOPS 0.002 x 1 = 0.002 */ {{1, 1}, {{1, 256, 12, 12}}, 32, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 2363904.}, + /* GFLOPS 0.002 x 1 = 0.002 */ {{3, 3}, {{1, 128, 3, 3}}, 256, 1, {2, 2}, {1, 1}, {1, 1}, {0, 0}, "", true, 2360320.}, + /* GFLOPS 0.002 x 1 = 0.002 */ {{3, 3}, {{1, 128, 3, 3}}, 256, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 2360320.}, + /* GFLOPS 0.002 x 1 = 0.002 */ {{3, 3}, {{1, 128, 3, 3}}, 256, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 2360320.}, + /* GFLOPS 0.002 x 1 = 0.002 */ {{1, 1}, {{1, 528, 4, 4}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 2164736.}, + /* GFLOPS 0.002 x 1 = 0.002 */ {{1, 1}, {{1, 508, 4, 4}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 2082816.}, + /* GFLOPS 0.002 x 1 = 0.002 */ {{1, 1}, {{1, 1024, 1, 1}}, 1000, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 2049000.}, + /* GFLOPS 0.001 x 2 = 0.002 */ {{3, 3}, {{1, 256, 3, 3}}, 24, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 995544.}, + /* GFLOPS 0.001 x 2 = 0.002 */ {{3, 3}, {{1, 128, 5, 5}}, 16, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 922000.}, + /* GFLOPS 0.002 x 1 = 0.002 */ {{1, 1}, {{1, 1024, 3, 3}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 1770336.}, + /* GFLOPS 0.001 x 1 = 0.001 */ {{1, 1}, {{1, 640, 6, 6}}, 32, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 1475712.}, + /* GFLOPS 0.001 x 1 = 0.001 */ {{3, 3}, {{1, 128, 5, 5}}, 24, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 1383000.}, + /* GFLOPS 0.001 x 1 = 0.001 */ {{1, 1}, {{1, 736, 3, 3}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 1272672.}, + /* GFLOPS 0.001 x 2 = 0.001 */ {{1, 1}, {{1, 256, 3, 3}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 590976.}, + /* GFLOPS 0.001 x 1 = 0.001 */ {{3, 3}, {{1, 128, 3, 3}}, 128, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 1180160.}, + /* GFLOPS 0.001 x 1 = 0.001 */ {{1, 1}, {{1, 256, 2, 2}}, 546, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 1120392.}, + /* GFLOPS 0.000 x 2 = 0.001 */ {{3, 3}, {{1, 128, 5, 5}}, 8, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 461000.}, + /* GFLOPS 0.001 x 1 = 0.001 */ {{1, 1}, {{1, 192, 12, 12}}, 16, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 887040.}, + /* GFLOPS 0.000 x 2 = 0.001 */ {{3, 3}, {{1, 256, 2, 2}}, 24, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 442464.}, + /* GFLOPS 0.000 x 2 = 0.001 */ {{1, 1}, {{1, 128, 5, 5}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 411200.}, + /* GFLOPS 0.001 x 1 = 0.001 */ {{3, 3}, {{1, 128, 5, 5}}, 12, 1, {1, 1}, {1, 1}, {1, 1}, {0, 0}, "", true, 691500.}, + /* GFLOPS 0.001 x 1 = 0.001 */ {{1, 1}, {{1, 640, 2, 2}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 655872.}, + /* GFLOPS 0.001 x 1 = 0.001 */ {{1, 1}, {{1, 512, 5, 5}}, 24, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 615000.}, + /* GFLOPS 0.001 x 1 = 0.001 */ {{1, 1}, {{1, 512, 5, 5}}, 24, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 615000.}, + /* GFLOPS 0.001 x 1 = 0.001 */ {{1, 1}, {{1, 128, 3, 3}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 592128.}, + /* GFLOPS 0.001 x 1 = 0.001 */ {{1, 1}, {{1, 256, 3, 3}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 590976.}, + /* GFLOPS 0.001 x 1 = 0.001 */ {{1, 1}, {{1, 256, 3, 3}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 590976.}, + /* GFLOPS 0.001 x 1 = 0.001 */ {{1, 1}, {{1, 256, 3, 3}}, 126, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 581742.}, + /* GFLOPS 0.001 x 1 = 0.001 */ {{1, 1}, {{1, 256, 4, 4}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 525312.}, + /* GFLOPS 0.000 x 1 = 0.000 */ {{1, 1}, {{1, 192, 5, 5}}, 32, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 308000.}, + /* GFLOPS 0.000 x 1 = 0.000 */ {{1, 1}, {{1, 128, 2, 2}}, 256, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 263168.}, + /* GFLOPS 0.000 x 2 = 0.000 */ {{1, 1}, {{1, 256, 2, 2}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 131328.}, + /* GFLOPS 0.000 x 1 = 0.000 */ {{1, 1}, {{1, 256, 2, 2}}, 126, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 258552.}, + /* GFLOPS 0.000 x 1 = 0.000 */ {{1, 1}, {{1, 1024, 1, 1}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 196704.}, + /* GFLOPS 0.000 x 1 = 0.000 */ {{3, 3}, {{1, 64, 2, 2}}, 128, 1, {2, 2}, {1, 1}, {1, 1}, {0, 0}, "", true, 147584.}, + /* GFLOPS 0.000 x 1 = 0.000 */ {{3, 3}, {{1, 64, 2, 2}}, 128, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 147584.}, + /* GFLOPS 0.000 x 1 = 0.000 */ {{3, 3}, {{1, 64, 2, 2}}, 128, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 147584.}, + /* GFLOPS 0.000 x 1 = 0.000 */ {{1, 1}, {{1, 736, 1, 1}}, 96, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 141408.}, + /* GFLOPS 0.000 x 1 = 0.000 */ {{1, 1}, {{1, 128, 1, 1}}, 546, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 140322.}, + /* GFLOPS 0.000 x 1 = 0.000 */ {{1, 1}, {{1, 256, 2, 2}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 131328.}, + /* GFLOPS 0.000 x 1 = 0.000 */ {{1, 1}, {{1, 256, 2, 2}}, 64, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 131328.}, + /* GFLOPS 0.000 x 1 = 0.000 */ {{1, 1}, {{1, 256, 3, 3}}, 24, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 110808.}, + /* GFLOPS 0.000 x 1 = 0.000 */ {{1, 1}, {{1, 256, 3, 3}}, 24, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 110808.}, + /* GFLOPS 0.000 x 2 = 0.000 */ {{3, 3}, {{1, 128, 1, 1}}, 24, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 55320.}, + /* GFLOPS 0.000 x 1 = 0.000 */ {{3, 3}, {{1, 64, 2, 2}}, 64, 1, {2, 2}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 73792.}, + /* GFLOPS 0.000 x 1 = 0.000 */ {{1, 1}, {{1, 256, 2, 2}}, 24, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 49248.}, + /* GFLOPS 0.000 x 1 = 0.000 */ {{1, 1}, {{1, 256, 2, 2}}, 24, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 49248.}, + /* GFLOPS 0.000 x 1 = 0.000 */ {{1, 1}, {{1, 128, 1, 1}}, 126, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 32382.}, + /* GFLOPS 0.000 x 1 = 0.000 */ {{1, 1}, {{1, 64, 1, 1}}, 128, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", false, 16512.}, + /* GFLOPS 0.000 x 1 = 0.000 */ {{1, 1}, {{1, 128, 1, 1}}, 24, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "", true, 6168.}, + /* GFLOPS 0.000 x 1 = 0.000 */ {{1, 1}, {{1, 128, 1, 1}}, 24, 1, {1, 1}, {1, 1}, {0, 0}, {0, 0}, "SAME", true, 6168.} +}; +struct ConvParamID +{ + enum { + CONV_0 = 0, + CONV_100 = 100, + CONV_LAST = sizeof(testConvolutionConfigs) / sizeof(testConvolutionConfigs[0]) + }; + int val_; \ + ConvParamID(int val = 0) : val_(val) {} + operator int() const { return val_; } + static ::testing::internal::ParamGenerator all() + { +#if 0 + enum { NUM = (int)CONV_LAST }; +#else + enum { NUM = (int)CONV_100 }; +#endif + ConvParamID v_[NUM]; for (int i = 0; i < NUM; ++i) { v_[i] = ConvParamID(i); } // reduce generated code size + return ::testing::ValuesIn(v_, v_ + NUM); + } +}; \ +static inline void PrintTo(const ConvParamID& v, std::ostream* os) +{ + CV_Assert((int)v >= 0); CV_Assert((int)v < ConvParamID::CONV_LAST); + const ConvParam_t& p = testConvolutionConfigs[(int)v]; -enum {GROUP_OFF = 1, GROUP_2 = 2}; -CV_ENUM(GroupSize, GROUP_OFF, GROUP_2); + *os << "GFLOPS=" << cv::format("%.3f", p.declared_flops * 1e-9) + << ", K=" << (Size)p.kernel + << ", IN={" << p.shapeIn.dims[0] << ", " << p.shapeIn.dims[1] << ", " << p.shapeIn.dims[2] << ", " << p.shapeIn.dims[3] << "}" + << ", OCN=" << p.outCN; + if (p.groups > 1) + *os << ", G=" << p.groups; + if (((Size)p.stride).area() != 1) + *os << ", S=" << ((Size)p.stride); + if (((Size)p.dilation).area() != 1) + *os << ", D=" << ((Size)p.dilation); + if (((Size)p.pad).area() != 0) + *os << ", P=" << ((Size)p.pad); + if (((Size)p.padAdjust).area() != 0) + *os << ", PAdj=" << ((Size)p.padAdjust); + if (!((std::string)p.padMode).empty()) + *os << ", PM=" << ((std::string)p.padMode); + if (p.hasBias) + *os << ", BIAS"; +} -typedef std::pair InpShapeNumOut; -typedef tuple ConvParam; //kernel_size, inp shape, groups, stride -typedef TestBaseWithParam ConvolutionPerfTest; -static inline MatShape blobShape(int count, int nplanes, int height, int width) -{ - int data[] = {count, nplanes, height, width}; - return MatShape(data, data+4); -} -PERF_TEST_P( ConvolutionPerfTest, perf, Combine( - Values(Size(1, 1), Size(3, 3), Size(5, 5), Size(11, 11)), - Values(make_pair(blobShape(1, 4, 224, 224), 64), - make_pair(blobShape(1, 64, 112, 122), 128), - make_pair(blobShape(1, 256, 28, 28), 512)), - GroupSize::all(), - StrideSize::all()) -) +typedef tuple > ConvTestParam_t; +typedef TestBaseWithParam Conv; + +PERF_TEST_P_(Conv, conv) { - RNG rng(0); - - ConvParam params = GetParam(); - int ksz = get<0>(params).width; - MatShape inpShape = get<1>(params).first; - int outCn = get<1>(params).second; - int groups = get<2>(params); - int stride = (ksz >= 11) ? 4 : (int)get<3>(params); - - int inpCn = inpShape[1]; - int wgtSize[] = { outCn, inpCn/groups, ksz, ksz }; - int biasSize[] = { outCn, 1, 1, 1 }; - const int wtype = CV_32F; - Mat wgtBlob(4, wgtSize, wtype), biasBlob(4, biasSize, wtype); - Mat inpBlob(4, &inpShape[0], wtype); - rng.fill(biasBlob, RNG::UNIFORM, -1, +1); - rng.fill(wgtBlob, RNG::UNIFORM, -1, +1); - rng.fill(inpBlob, RNG::UNIFORM, -1, +1); + int test_id = (int)get<0>(GetParam()); + ASSERT_GE(test_id, 0); ASSERT_LT(test_id, ConvParamID::CONV_LAST); + const ConvParam_t& params = testConvolutionConfigs[test_id]; + double declared_flops = params.declared_flops; + Size kernel = params.kernel; + MatShape inputShape = MatShape(params.shapeIn.dims, params.shapeIn.dims + 4); + int outChannels = params.outCN; + int groups = params.groups; + Size stride = params.stride; + Size dilation = params.dilation; + Size pad = params.pad; + Size padAdjust = params.padAdjust; + std::string padMode(params.padMode); + bool hasBias = params.hasBias; + Backend backendId = get<0>(get<1>(GetParam())); + Target targetId = get<1>(get<1>(GetParam())); + + int inChannels = inputShape[1]; + Size inSize(inputShape[3], inputShape[2]); + + int sz[] = {outChannels, inChannels / groups, kernel.height, kernel.width}; + Mat weights(4, &sz[0], CV_32F); + randu(weights, -1.0f, 1.0f); LayerParams lp; - lp.set("num_output", outCn); - lp.set("group", groups); - lp.set("stride", stride); - lp.set("kernel_size", ksz); - lp.blobs.reserve(2); - lp.blobs.push_back(wgtBlob); - lp.blobs.push_back(biasBlob); - - std::vector inpBlobs(1, &inpBlob); - std::vector outBlobs, internalBlobs; - - Ptr layer = cv::dnn::LayerFactory::createLayerInstance("Convolution", lp); - std::vector inputShapes(1, shape(inpBlob)), outShapes, internals; - layer->getMemoryShapes(inputShapes, 0, outShapes, internals); - for (size_t i = 0; i < outShapes.size(); i++) + lp.set("kernel_w", kernel.width); + lp.set("kernel_h", kernel.height); + lp.set("pad_w", pad.width); + lp.set("pad_h", pad.height); + if (padAdjust.width > 0 || padAdjust.height > 0) { - outBlobs.push_back(Mat(outShapes[i], CV_32F)); + lp.set("adj_w", padAdjust.width); + lp.set("adj_h", padAdjust.height); } - for (size_t i = 0; i < internals.size(); i++) + if (!padMode.empty()) + lp.set("pad_mode", padMode); + lp.set("stride_w", stride.width); + lp.set("stride_h", stride.height); + lp.set("dilation_w", dilation.width); + lp.set("dilation_h", dilation.height); + lp.set("num_output", outChannels); + lp.set("group", groups); + lp.set("bias_term", hasBias); + lp.type = "Convolution"; + lp.name = "testLayer"; + lp.blobs.push_back(weights); + if (hasBias) { - internalBlobs.push_back(Mat()); - if (total(internals[i])) - internalBlobs.back().create(internals[i], CV_32F); + Mat bias(1, outChannels, CV_32F); + randu(bias, -1.0f, 1.0f); + lp.blobs.push_back(bias); } + int inpSz[] = {1, inChannels, inSize.height, inSize.width}; + Mat input(4, &inpSz[0], CV_32F); + randu(input, -1.0f, 1.0f); + + Net net; + net.addLayerToPrev(lp.name, lp.type, lp); - layer->finalize(inpBlobs, outBlobs); + net.setInput(input); + net.setPreferableBackend(backendId); + net.setPreferableTarget(targetId); - Mat inpBlob2D = inpBlob.reshape(1, outCn); - Mat wgtBlob2D = wgtBlob.reshape(1, outCn*(inpCn/groups)); - Mat outBlob2D = outBlobs[0].reshape(1, outBlobs[0].size[0]); - declare.in(inpBlob2D, wgtBlob2D, WARMUP_RNG).out(outBlob2D); + // warmup + Mat output = net.forward(); - layer->forward(inpBlobs, outBlobs, internalBlobs); /// warmup + MatShape netInputShape = shape(input); + size_t weightsMemory = 0, blobsMemory = 0; + net.getMemoryConsumption(netInputShape, weightsMemory, blobsMemory); + int64 flops = net.getFLOPS(netInputShape); + CV_Assert(flops > 0); - PERF_SAMPLE_BEGIN() - layer->forward(inpBlobs, outBlobs, internalBlobs); - PERF_SAMPLE_END() + std::cout + << "IN=" << divUp(input.total() * input.elemSize(), 1u<<10) << " Kb " << netInputShape + << " OUT=" << divUp(output.total() * output.elemSize(), 1u<<10) << " Kb " << shape(output) + << " Weights(parameters): " << divUp(weightsMemory, 1u<<10) << " Kb" + << " MFLOPS=" << flops * 1e-6 << std::endl; + TEST_CYCLE() + { + Mat res = net.forward(); + } + + EXPECT_NEAR(flops, declared_flops, declared_flops * 1e-6); SANITY_CHECK_NOTHING(); } +INSTANTIATE_TEST_CASE_P(/**/, Conv, Combine( + ConvParamID::all(), + dnnBackendsAndTargets(false, false) // defined in ../test/test_common.hpp +)); + } // namespace diff --git a/modules/dnn/perf/perf_net.cpp b/modules/dnn/perf/perf_net.cpp index c6cef9f4f766..192604b86191 100644 --- a/modules/dnn/perf/perf_net.cpp +++ b/modules/dnn/perf/perf_net.cpp @@ -14,10 +14,7 @@ namespace opencv_test { -CV_ENUM(DNNBackend, DNN_BACKEND_DEFAULT, DNN_BACKEND_HALIDE, DNN_BACKEND_INFERENCE_ENGINE, DNN_BACKEND_OPENCV) -CV_ENUM(DNNTarget, DNN_TARGET_CPU, DNN_TARGET_OPENCL, DNN_TARGET_OPENCL_FP16, DNN_TARGET_MYRIAD) - -class DNNTestNetwork : public ::perf::TestBaseWithParam< tuple > +class DNNTestNetwork : public ::perf::TestBaseWithParam< tuple > { public: dnn::Backend backend; @@ -269,22 +266,6 @@ PERF_TEST_P_(DNNTestNetwork, Inception_v2_Faster_RCNN) Mat(cv::Size(800, 600), CV_32FC3)); } -const tuple testCases[] = { -#ifdef HAVE_HALIDE - tuple(DNN_BACKEND_HALIDE, DNN_TARGET_CPU), - tuple(DNN_BACKEND_HALIDE, DNN_TARGET_OPENCL), -#endif -#ifdef HAVE_INF_ENGINE - tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_CPU), - tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL), - tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL_FP16), - tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_MYRIAD), -#endif - tuple(DNN_BACKEND_OPENCV, DNN_TARGET_CPU), - tuple(DNN_BACKEND_OPENCV, DNN_TARGET_OPENCL), - tuple(DNN_BACKEND_OPENCV, DNN_TARGET_OPENCL_FP16) -}; - -INSTANTIATE_TEST_CASE_P(/*nothing*/, DNNTestNetwork, testing::ValuesIn(testCases)); +INSTANTIATE_TEST_CASE_P(/*nothing*/, DNNTestNetwork, dnnBackendsAndTargets()); } // namespace diff --git a/modules/dnn/perf/perf_precomp.hpp b/modules/dnn/perf/perf_precomp.hpp index 5e58a312fb91..81816ca7ecc8 100644 --- a/modules/dnn/perf/perf_precomp.hpp +++ b/modules/dnn/perf/perf_precomp.hpp @@ -4,6 +4,8 @@ #include #include +#include "../test/test_common.hpp" + namespace opencv_test { using namespace perf; using namespace cv::dnn; diff --git a/modules/dnn/src/dnn.cpp b/modules/dnn/src/dnn.cpp index 5248d74cb601..51cba618da75 100644 --- a/modules/dnn/src/dnn.cpp +++ b/modules/dnn/src/dnn.cpp @@ -1676,14 +1676,6 @@ struct Net::Impl // with the current layer if they follow it. Normally, the are fused with the convolution layer, // but some of them (like activation) may be fused with fully-connected, elemwise (+) and // some other layers. - - // TODO: OpenCL target support more fusion styles. - if ( preferableBackend == DNN_BACKEND_OPENCV && IS_DNN_OPENCL_TARGET(preferableTarget) && - (!cv::ocl::useOpenCL() || (ld.layerInstance->type != "Convolution" && - ld.layerInstance->type != "MVN" && ld.layerInstance->type != "Pooling" && - ld.layerInstance->type != "Concat")) ) - continue; - Ptr& currLayer = ld.layerInstance; if( ld.consumers.size() == 1 && pinsToKeep.count(LayerPin(lid, 0)) == 0 ) { @@ -1717,6 +1709,13 @@ struct Net::Impl if (preferableBackend != DNN_BACKEND_OPENCV) continue; // Go to the next layer. + // TODO: OpenCL target support more fusion styles. + if ( preferableBackend == DNN_BACKEND_OPENCV && IS_DNN_OPENCL_TARGET(preferableTarget) && + (!cv::ocl::useOpenCL() || (ld.layerInstance->type != "Convolution" && + ld.layerInstance->type != "MVN" && ld.layerInstance->type != "Pooling" && + ld.layerInstance->type != "Concat")) ) + continue; + while (nextData) { // For now, OpenCL target support fusion with activation of ReLU/ChannelsPReLU/Power/Tanh @@ -2693,8 +2692,7 @@ void Net::setInput(InputArray blob, const String& name, double scalefactor, cons Mat Net::getParam(LayerId layer, int numParam) { LayerData &ld = impl->getLayerData(layer); - - std::vector &layerBlobs = ld.layerInstance->blobs; + std::vector &layerBlobs = ld.getLayerInstance()->blobs; CV_Assert(numParam < (int)layerBlobs.size()); return layerBlobs[numParam]; } @@ -2703,7 +2701,7 @@ void Net::setParam(LayerId layer, int numParam, const Mat &blob) { LayerData &ld = impl->getLayerData(layer); - std::vector &layerBlobs = ld.layerInstance->blobs; + std::vector &layerBlobs = ld.getLayerInstance()->blobs; CV_Assert(numParam < (int)layerBlobs.size()); //we don't make strong checks, use this function carefully layerBlobs[numParam] = blob; diff --git a/modules/dnn/src/layers/convolution_layer.cpp b/modules/dnn/src/layers/convolution_layer.cpp index 169e2808409a..54b324538aac 100644 --- a/modules/dnn/src/layers/convolution_layer.cpp +++ b/modules/dnn/src/layers/convolution_layer.cpp @@ -350,12 +350,14 @@ class ConvolutionLayerImpl CV_FINAL : public BaseConvolutionLayerImpl return false; } - void fuseWeights(const Mat& w, const Mat& b) + void fuseWeights(const Mat& w_, const Mat& b_) { // Convolution weights have OIHW data layout. Parameters fusion in case of // (conv(I) + b1 ) * w + b2 // means to replace convolution's weights to [w*conv(I)] and bias to [b1 * w + b2] const int outCn = weightsMat.size[0]; + Mat w = w_.total() == 1 ? Mat(1, outCn, CV_32F, Scalar(w_.at(0))) : w_; + Mat b = b_.total() == 1 ? Mat(1, outCn, CV_32F, Scalar(b_.at(0))) : b_; CV_Assert_N(!weightsMat.empty(), biasvec.size() == outCn + 2, w.empty() || outCn == w.total(), b.empty() || outCn == b.total()); diff --git a/modules/dnn/src/layers/crop_layer.cpp b/modules/dnn/src/layers/crop_layer.cpp index 8b56f6f43900..3572b883374d 100644 --- a/modules/dnn/src/layers/crop_layer.cpp +++ b/modules/dnn/src/layers/crop_layer.cpp @@ -41,6 +41,7 @@ //M*/ #include "../precomp.hpp" +#include "../op_inf_engine.hpp" #include "layers_common.hpp" namespace cv @@ -64,6 +65,12 @@ class CropLayerImpl CV_FINAL : public CropLayer } } + virtual bool supportBackend(int backendId) CV_OVERRIDE + { + return backendId == DNN_BACKEND_OPENCV || + backendId == DNN_BACKEND_INFERENCE_ENGINE && crop_ranges.size() == 4; + } + bool getMemoryShapes(const std::vector &inputs, const int requiredOutputs, std::vector &outputs, @@ -109,7 +116,11 @@ class CropLayerImpl CV_FINAL : public CropLayer offset_final[i] = offset[i - start_axis]; } - crop_ranges.resize(dims, Range::all()); + crop_ranges.resize(dims); + for (int i = 0; i < start_axis; i++) + { + crop_ranges[i] = Range(0, inpBlob.size[i]); + } for (int i = start_axis; i < dims; i++) { if (offset_final[i] < 0 || offset_final[i] + inpSzBlob.size[i] > inpBlob.size[i]) @@ -138,6 +149,38 @@ class CropLayerImpl CV_FINAL : public CropLayer input(&crop_ranges[0]).copyTo(output); } + virtual Ptr initInfEngine(const std::vector >&) CV_OVERRIDE + { +#ifdef HAVE_INF_ENGINE + InferenceEngine::LayerParams lp; + lp.name = name; + lp.type = "Crop"; + lp.precision = InferenceEngine::Precision::FP32; + std::shared_ptr ieLayer(new InferenceEngine::CropLayer(lp)); + + CV_Assert(crop_ranges.size() == 4); + + ieLayer->axis.push_back(0); // batch + ieLayer->offset.push_back(crop_ranges[0].start); + ieLayer->dim.push_back(crop_ranges[0].end - crop_ranges[0].start); + + ieLayer->axis.push_back(1); // channels + ieLayer->offset.push_back(crop_ranges[1].start); + ieLayer->dim.push_back(crop_ranges[1].end - crop_ranges[1].start); + + ieLayer->axis.push_back(3); // height + ieLayer->offset.push_back(crop_ranges[2].start); + ieLayer->dim.push_back(crop_ranges[2].end - crop_ranges[2].start); + + ieLayer->axis.push_back(2); // width + ieLayer->offset.push_back(crop_ranges[3].start); + ieLayer->dim.push_back(crop_ranges[3].end - crop_ranges[3].start); + + return Ptr(new InfEngineBackendNode(ieLayer)); +#endif // HAVE_INF_ENGINE + return Ptr(); + } + std::vector crop_ranges; }; diff --git a/modules/dnn/src/layers/elementwise_layers.cpp b/modules/dnn/src/layers/elementwise_layers.cpp index 0a5ed54ca8ff..74c89e62decc 100644 --- a/modules/dnn/src/layers/elementwise_layers.cpp +++ b/modules/dnn/src/layers/elementwise_layers.cpp @@ -161,6 +161,16 @@ class ElementWiseLayer : public Func::Layer return Ptr(); } + virtual bool tryFuse(Ptr& top) CV_OVERRIDE + { + return func.tryFuse(top); + } + + void getScaleShift(Mat& scale_, Mat& shift_) const CV_OVERRIDE + { + func.getScaleShift(scale_, shift_); + } + bool getMemoryShapes(const std::vector &inputs, const int requiredOutputs, std::vector &outputs, @@ -343,6 +353,10 @@ struct ReLUFunctor } #endif // HAVE_INF_ENGINE + bool tryFuse(Ptr&) { return false; } + + void getScaleShift(Mat&, Mat&) const {} + int64 getFLOPSPerElement() const { return 1; } }; @@ -448,6 +462,10 @@ struct ReLU6Functor } #endif // HAVE_INF_ENGINE + bool tryFuse(Ptr&) { return false; } + + void getScaleShift(Mat&, Mat&) const {} + int64 getFLOPSPerElement() const { return 2; } }; @@ -518,6 +536,10 @@ struct TanHFunctor } #endif // HAVE_INF_ENGINE + bool tryFuse(Ptr&) { return false; } + + void getScaleShift(Mat&, Mat&) const {} + int64 getFLOPSPerElement() const { return 1; } }; @@ -588,6 +610,10 @@ struct SigmoidFunctor } #endif // HAVE_INF_ENGINE + bool tryFuse(Ptr&) { return false; } + + void getScaleShift(Mat&, Mat&) const {} + int64 getFLOPSPerElement() const { return 3; } }; @@ -659,6 +685,10 @@ struct ELUFunctor } #endif // HAVE_INF_ENGINE + bool tryFuse(Ptr&) { return false; } + + void getScaleShift(Mat&, Mat&) const {} + int64 getFLOPSPerElement() const { return 2; } }; @@ -727,6 +757,10 @@ struct AbsValFunctor } #endif // HAVE_INF_ENGINE + bool tryFuse(Ptr&) { return false; } + + void getScaleShift(Mat&, Mat&) const {} + int64 getFLOPSPerElement() const { return 1; } }; @@ -775,6 +809,10 @@ struct BNLLFunctor } #endif // HAVE_INF_ENGINE + bool tryFuse(Ptr&) { return false; } + + void getScaleShift(Mat&, Mat&) const {} + int64 getFLOPSPerElement() const { return 5; } }; @@ -875,15 +913,51 @@ struct PowerFunctor #ifdef HAVE_INF_ENGINE InferenceEngine::CNNLayerPtr initInfEngine(InferenceEngine::LayerParams& lp) { - lp.type = "Power"; - std::shared_ptr ieLayer(new InferenceEngine::PowerLayer(lp)); - ieLayer->power = power; - ieLayer->scale = scale; - ieLayer->offset = shift; - return ieLayer; + if (power == 1.0f && scale == 1.0f && shift == 0.0f) + { + // It looks like there is a bug in Inference Engine for DNN_TARGET_OPENCL and DNN_TARGET_OPENCL_FP16 + // if power layer do nothing so we replace it to Identity. + lp.type = "Split"; + return std::shared_ptr(new InferenceEngine::SplitLayer(lp)); + } + else + { + lp.type = "Power"; + std::shared_ptr ieLayer(new InferenceEngine::PowerLayer(lp)); + ieLayer->power = power; + ieLayer->scale = scale; + ieLayer->offset = shift; + return ieLayer; + } } #endif // HAVE_INF_ENGINE + bool tryFuse(Ptr& top) + { + if (power != 1.0f && shift != 0.0f) + return false; + + Mat w, b; + top->getScaleShift(w, b); + if ((w.empty() && b.empty()) || w.total() > 1 || b.total() > 1) + return false; + + float nextScale = w.empty() ? 1.0f : w.at(0); + float nextShift = b.empty() ? 0.0f : b.at(0); + scale = std::pow(scale, power) * nextScale; + shift = nextScale * shift + nextShift; + return true; + } + + void getScaleShift(Mat& _scale, Mat& _shift) const + { + if (power == 1.0f) + { + _scale = Mat(1, 1, CV_32F, Scalar(scale)); + _shift = Mat(1, 1, CV_32F, Scalar(shift)); + } + } + int64 getFLOPSPerElement() const { return power == 1 ? 2 : 10; } }; @@ -989,6 +1063,10 @@ struct ChannelsPReLUFunctor } #endif // HAVE_INF_ENGINE + bool tryFuse(Ptr&) { return false; } + + void getScaleShift(Mat&, Mat&) const {} + int64 getFLOPSPerElement() const { return 1; } }; diff --git a/modules/dnn/src/layers/flatten_layer.cpp b/modules/dnn/src/layers/flatten_layer.cpp index 2fd9242ed3d7..41ec8dfc5380 100644 --- a/modules/dnn/src/layers/flatten_layer.cpp +++ b/modules/dnn/src/layers/flatten_layer.cpp @@ -83,12 +83,6 @@ class FlattenLayerImpl CV_FINAL : public FlattenLayer int startAxis = clamp(_startAxis, numAxes); int endAxis = clamp(_endAxis, numAxes); - for (size_t i = 1; i < inputs.size(); i++) - { - CV_Assert(inputs[i] == inputs[0]); - } - - CV_Assert(startAxis >= 0); CV_Assert(endAxis >= startAxis && endAxis < (int)numAxes); diff --git a/modules/dnn/src/layers/fully_connected_layer.cpp b/modules/dnn/src/layers/fully_connected_layer.cpp index d17ca2738364..e40f8c6bdd7a 100644 --- a/modules/dnn/src/layers/fully_connected_layer.cpp +++ b/modules/dnn/src/layers/fully_connected_layer.cpp @@ -350,17 +350,33 @@ class FullyConnectedLayerImpl CV_FINAL : public InnerProductLayer inshape = shape(outerSize, innerSize); outshape = shape(outerSize, numOutput); - UMat srcMat, dstMat; + UMat srcMat, dstMat, srcMat_fp32, dstMat_fp32; srcMat = inputs[i].reshape(1, inshape.size(), &inshape[0]); dstMat = outputs[i].reshape(1, outshape.size(), &outshape[0]); - cv::gemm(srcMat, weights, 1, noArray(), 0, dstMat, GEMM_2_T); + if (use_half) + { + convertFp16(srcMat, srcMat_fp32); + convertFp16(dstMat, dstMat_fp32); + } + else + { + srcMat_fp32 = srcMat; + dstMat_fp32 = dstMat; + } + + cv::gemm(srcMat_fp32, weights, 1, noArray(), 0, dstMat_fp32, GEMM_2_T); if (bias) { UMat biasOnesMat = UMat::ones(outerSize, 1, umat_blobs[0].type()); UMat& biases = umat_blobs[1]; - cv::gemm(biasOnesMat, biases, 1, dstMat, 1, dstMat, 0); + cv::gemm(biasOnesMat, biases, 1, dstMat_fp32, 1, dstMat_fp32, 0); + } + if (use_half) + { + convertFp16(srcMat_fp32, srcMat); + convertFp16(dstMat_fp32, dstMat); } } diff --git a/modules/dnn/src/layers/prior_box_layer.cpp b/modules/dnn/src/layers/prior_box_layer.cpp index 6be6efa8a66b..d4ffbbaa9717 100644 --- a/modules/dnn/src/layers/prior_box_layer.cpp +++ b/modules/dnn/src/layers/prior_box_layer.cpp @@ -453,8 +453,8 @@ class PriorBoxLayerImpl CV_FINAL : public PriorBoxLayer outputPtr = outputs[0].ptr(0, 1); if(_variance.size() == 1) { - Mat secondChannel(outputs[0].size[2], outputs[0].size[3], CV_32F, outputPtr); - secondChannel.setTo(Scalar(_variance[0])); + Mat secondChannel(1, outputs[0].size[2], CV_32F, outputPtr); + secondChannel.setTo(Scalar::all(_variance[0])); } else { diff --git a/modules/dnn/src/op_inf_engine.cpp b/modules/dnn/src/op_inf_engine.cpp index f354d6966e61..43d8d1eb2d3d 100644 --- a/modules/dnn/src/op_inf_engine.cpp +++ b/modules/dnn/src/op_inf_engine.cpp @@ -161,6 +161,7 @@ InfEngineBackendNet::InfEngineBackendNet(InferenceEngine::CNNNetwork& net) inputs = net.getInputsInfo(); outputs = net.getOutputsInfo(); layers.resize(net.layerCount()); // A hack to execute InfEngineBackendNet::layerCount correctly. + netOwner = net; } void InfEngineBackendNet::Release() noexcept diff --git a/modules/dnn/src/op_inf_engine.hpp b/modules/dnn/src/op_inf_engine.hpp index 841cb13e1350..f49a8e0445fe 100644 --- a/modules/dnn/src/op_inf_engine.hpp +++ b/modules/dnn/src/op_inf_engine.hpp @@ -131,6 +131,8 @@ class InfEngineBackendNet : public InferenceEngine::ICNNNetwork InferenceEngine::InferencePlugin plugin; InferenceEngine::ExecutableNetwork netExec; InferenceEngine::InferRequest infRequest; + // In case of models from Model Optimizer we need to manage their lifetime. + InferenceEngine::CNNNetwork netOwner; std::string name; diff --git a/modules/dnn/src/tensorflow/tf_graph_simplifier.cpp b/modules/dnn/src/tensorflow/tf_graph_simplifier.cpp index 51a249e73c63..28c0f4de21b7 100644 --- a/modules/dnn/src/tensorflow/tf_graph_simplifier.cpp +++ b/modules/dnn/src/tensorflow/tf_graph_simplifier.cpp @@ -782,6 +782,108 @@ void releaseTensor(tensorflow::TensorProto* tensor) } } +static void permute(google::protobuf::RepeatedPtrField* data, + const std::vector& indices) +{ + const int num = data->size(); + CV_Assert(num == indices.size()); + + std::vector elemIdToPos(num); + std::vector posToElemId(num); + for (int i = 0; i < num; ++i) + { + elemIdToPos[i] = i; + posToElemId[i] = i; + } + for (int i = 0; i < num; ++i) + { + int elemId = indices[i]; + int pos = elemIdToPos[elemId]; + if (pos != i) + { + data->SwapElements(i, pos); + const int swappedElemId = posToElemId[i]; + elemIdToPos[elemId] = i; + elemIdToPos[swappedElemId] = pos; + + posToElemId[i] = elemId; + posToElemId[pos] = swappedElemId; + } + } +} + +// Is based on tensorflow::graph_transforms::SortByExecutionOrder +void sortByExecutionOrder(tensorflow::GraphDef& net) +{ + // Maps node's name to index at net.node() list. + std::map nodesMap; + std::map::iterator nodesMapIt; + for (int i = 0; i < net.node_size(); ++i) + { + const tensorflow::NodeDef& node = net.node(i); + nodesMap.insert(std::make_pair(node.name(), i)); + } + + // Indices of nodes which use specific node as input. + std::vector > edges(nodesMap.size()); + std::vector numRefsToAdd(nodesMap.size(), 0); + std::vector nodesToAdd; + for (int i = 0; i < net.node_size(); ++i) + { + const tensorflow::NodeDef& node = net.node(i); + for (int j = 0; j < node.input_size(); ++j) + { + std::string inpName = node.input(j); + inpName = inpName.substr(0, inpName.rfind(':')); + inpName = inpName.substr(inpName.find('^') + 1); + + nodesMapIt = nodesMap.find(inpName); + CV_Assert(nodesMapIt != nodesMap.end()); + edges[nodesMapIt->second].push_back(i); + } + if (node.input_size() == 0) + nodesToAdd.push_back(i); + else + { + if (node.op() == "Merge" || node.op() == "RefMerge") + { + int numControlEdges = 0; + for (int j = 0; j < node.input_size(); ++j) + numControlEdges += node.input(j)[0] == '^'; + numRefsToAdd[i] = numControlEdges + 1; + } + else + numRefsToAdd[i] = node.input_size(); + } + } + + std::vector permIds; + permIds.reserve(net.node_size()); + while (!nodesToAdd.empty()) + { + int nodeToAdd = nodesToAdd.back(); + nodesToAdd.pop_back(); + + permIds.push_back(nodeToAdd); + // std::cout << net.node(nodeToAdd).name() << '\n'; + + for (int i = 0; i < edges[nodeToAdd].size(); ++i) + { + int consumerId = edges[nodeToAdd][i]; + if (numRefsToAdd[consumerId] > 0) + { + if (numRefsToAdd[consumerId] == 1) + nodesToAdd.push_back(consumerId); + else + CV_Assert(numRefsToAdd[consumerId] >= 0); + numRefsToAdd[consumerId] -= 1; + } + } + } + CV_Assert(permIds.size() == net.node_size()); + permute(net.mutable_node(), permIds); +} + CV__DNN_INLINE_NS_END }} // namespace dnn, namespace cv diff --git a/modules/dnn/src/tensorflow/tf_graph_simplifier.hpp b/modules/dnn/src/tensorflow/tf_graph_simplifier.hpp index 8b7605201460..a9c16c796fe2 100644 --- a/modules/dnn/src/tensorflow/tf_graph_simplifier.hpp +++ b/modules/dnn/src/tensorflow/tf_graph_simplifier.hpp @@ -25,6 +25,8 @@ Mat getTensorContent(const tensorflow::TensorProto &tensor); void releaseTensor(tensorflow::TensorProto* tensor); +void sortByExecutionOrder(tensorflow::GraphDef& net); + CV__DNN_INLINE_NS_END }} // namespace dnn, namespace cv diff --git a/modules/dnn/src/tensorflow/tf_importer.cpp b/modules/dnn/src/tensorflow/tf_importer.cpp index 86596c1b379d..145af366f8f9 100644 --- a/modules/dnn/src/tensorflow/tf_importer.cpp +++ b/modules/dnn/src/tensorflow/tf_importer.cpp @@ -1950,5 +1950,34 @@ Net readNetFromTensorflow(const std::vector& bufferModel, const std::vect bufferConfigPtr, bufferConfig.size()); } +void writeTextGraph(const String& _model, const String& output) +{ + String model = _model; + const std::string modelExt = model.substr(model.rfind('.') + 1); + if (modelExt != "pb") + CV_Error(Error::StsNotImplemented, "Only TensorFlow models support export to text file"); + + tensorflow::GraphDef net; + ReadTFNetParamsFromBinaryFileOrDie(model.c_str(), &net); + + sortByExecutionOrder(net); + + RepeatedPtrField::iterator it; + for (it = net.mutable_node()->begin(); it != net.mutable_node()->end(); ++it) + { + if (it->op() == "Const") + { + it->mutable_attr()->at("value").mutable_tensor()->clear_tensor_content(); + } + } + + std::string content; + google::protobuf::TextFormat::PrintToString(net, &content); + + std::ofstream ofs(output.c_str()); + ofs << content; + ofs.close(); +} + CV__DNN_INLINE_NS_END }} // namespace diff --git a/modules/dnn/test/test_backends.cpp b/modules/dnn/test/test_backends.cpp index 309f0010e4f8..a42cc4c174ec 100644 --- a/modules/dnn/test/test_backends.cpp +++ b/modules/dnn/test/test_backends.cpp @@ -161,7 +161,7 @@ TEST_P(DNNTestNetwork, MobileNet_SSD_v1_TensorFlow) if (backend == DNN_BACKEND_HALIDE) throw SkipTestException(""); Mat sample = imread(findDataFile("dnn/street.png", false)); - Mat inp = blobFromImage(sample, 1.0f / 127.5, Size(300, 300), Scalar(127.5, 127.5, 127.5), false); + Mat inp = blobFromImage(sample, 1.0f, Size(300, 300), Scalar(), false); float l1 = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 0.011 : 0.0; float lInf = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 0.06 : 0.0; processNet("dnn/ssd_mobilenet_v1_coco_2017_11_17.pb", "dnn/ssd_mobilenet_v1_coco_2017_11_17.pbtxt", @@ -173,7 +173,7 @@ TEST_P(DNNTestNetwork, MobileNet_SSD_v2_TensorFlow) if (backend == DNN_BACKEND_HALIDE) throw SkipTestException(""); Mat sample = imread(findDataFile("dnn/street.png", false)); - Mat inp = blobFromImage(sample, 1.0f / 127.5, Size(300, 300), Scalar(127.5, 127.5, 127.5), false); + Mat inp = blobFromImage(sample, 1.0f, Size(300, 300), Scalar(), false); float l1 = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 0.011 : 0.0; float lInf = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 0.062 : 0.0; processNet("dnn/ssd_mobilenet_v2_coco_2018_03_29.pb", "dnn/ssd_mobilenet_v2_coco_2018_03_29.pbtxt", @@ -247,8 +247,8 @@ TEST_P(DNNTestNetwork, Inception_v2_SSD_TensorFlow) if (backend == DNN_BACKEND_HALIDE) throw SkipTestException(""); Mat sample = imread(findDataFile("dnn/street.png", false)); - Mat inp = blobFromImage(sample, 1.0f / 127.5, Size(300, 300), Scalar(127.5, 127.5, 127.5), false); - float l1 = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 0.008 : 0.0; + Mat inp = blobFromImage(sample, 1.0f, Size(300, 300), Scalar(), false); + float l1 = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 0.015 : 0.0; float lInf = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 0.0731 : 0.0; processNet("dnn/ssd_inception_v2_coco_2017_11_17.pb", "dnn/ssd_inception_v2_coco_2017_11_17.pbtxt", inp, "detection_out", "", l1, lInf); @@ -285,21 +285,6 @@ TEST_P(DNNTestNetwork, FastNeuralStyle_eccv16) processNet("dnn/fast_neural_style_eccv16_starry_night.t7", "", inp, "", "", l1, lInf); } -const tuple testCases[] = { -#ifdef HAVE_HALIDE - tuple(DNN_BACKEND_HALIDE, DNN_TARGET_CPU), - tuple(DNN_BACKEND_HALIDE, DNN_TARGET_OPENCL), -#endif -#ifdef HAVE_INF_ENGINE - tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_CPU), - tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL), - tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL_FP16), - tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_MYRIAD), -#endif - tuple(DNN_BACKEND_OPENCV, DNN_TARGET_OPENCL), - tuple(DNN_BACKEND_OPENCV, DNN_TARGET_OPENCL_FP16) -}; - -INSTANTIATE_TEST_CASE_P(/*nothing*/, DNNTestNetwork, testing::ValuesIn(testCases)); +INSTANTIATE_TEST_CASE_P(/*nothing*/, DNNTestNetwork, dnnBackendsAndTargets(true, true, false)); }} // namespace diff --git a/modules/dnn/test/test_caffe_importer.cpp b/modules/dnn/test/test_caffe_importer.cpp index 4491fde5a9d2..33f2fa1f22f7 100644 --- a/modules/dnn/test/test_caffe_importer.cpp +++ b/modules/dnn/test/test_caffe_importer.cpp @@ -417,7 +417,7 @@ TEST_P(Test_Caffe_nets, DenseNet_121) float l1 = default_l1, lInf = default_lInf; if (target == DNN_TARGET_OPENCL_FP16) { - l1 = 0.017; lInf = 0.067; + l1 = 0.017; lInf = 0.0795; } else if (target == DNN_TARGET_MYRIAD) { @@ -490,8 +490,7 @@ INSTANTIATE_TEST_CASE_P(Test_Caffe, opencv_face_detector, TEST_P(Test_Caffe_nets, FasterRCNN_vgg16) { - if ((backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD) || - (backend == DNN_BACKEND_OPENCV && target == DNN_TARGET_OPENCL_FP16)) + if (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD) throw SkipTestException(""); static Mat ref = (Mat_(3, 7) << 0, 2, 0.949398, 99.2454, 210.141, 601.205, 462.849, 0, 7, 0.997022, 481.841, 92.3218, 722.685, 175.953, @@ -502,8 +501,7 @@ TEST_P(Test_Caffe_nets, FasterRCNN_vgg16) TEST_P(Test_Caffe_nets, FasterRCNN_zf) { if ((backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_OPENCL_FP16) || - (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD) || - (backend == DNN_BACKEND_OPENCV && target == DNN_TARGET_OPENCL_FP16)) + (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD)) throw SkipTestException(""); static Mat ref = (Mat_(3, 7) << 0, 2, 0.90121, 120.407, 115.83, 570.586, 528.395, 0, 7, 0.988779, 469.849, 75.1756, 718.64, 186.762, @@ -514,12 +512,13 @@ TEST_P(Test_Caffe_nets, FasterRCNN_zf) TEST_P(Test_Caffe_nets, RFCN) { if ((backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_OPENCL_FP16) || - (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD) || - (backend == DNN_BACKEND_OPENCV && target == DNN_TARGET_OPENCL_FP16)) + (backend == DNN_BACKEND_INFERENCE_ENGINE && target == DNN_TARGET_MYRIAD)) throw SkipTestException(""); + double scoreDiff = (backend == DNN_BACKEND_OPENCV && target == DNN_TARGET_OPENCL_FP16) ? 4e-3 : default_l1; + double iouDiff = (backend == DNN_BACKEND_OPENCV && target == DNN_TARGET_OPENCL_FP16) ? 8e-2 : default_lInf; static Mat ref = (Mat_(2, 7) << 0, 7, 0.991359, 491.822, 81.1668, 702.573, 178.234, 0, 12, 0.94786, 132.093, 223.903, 338.077, 566.16); - testFaster("rfcn_pascal_voc_resnet50.prototxt", "resnet50_rfcn_final.caffemodel", ref); + testFaster("rfcn_pascal_voc_resnet50.prototxt", "resnet50_rfcn_final.caffemodel", ref, scoreDiff, iouDiff); } INSTANTIATE_TEST_CASE_P(/**/, Test_Caffe_nets, dnnBackendsAndTargets()); diff --git a/modules/dnn/test/test_common.hpp b/modules/dnn/test/test_common.hpp index ec43f3e0467b..d3707a256ac9 100644 --- a/modules/dnn/test/test_common.hpp +++ b/modules/dnn/test/test_common.hpp @@ -42,6 +42,47 @@ #ifndef __OPENCV_TEST_COMMON_HPP__ #define __OPENCV_TEST_COMMON_HPP__ +#ifdef HAVE_OPENCL +#include "opencv2/core/ocl.hpp" +#endif + +namespace cv { namespace dnn { +CV__DNN_INLINE_NS_BEGIN +static inline void PrintTo(const cv::dnn::Backend& v, std::ostream* os) +{ + switch (v) { + case DNN_BACKEND_DEFAULT: *os << "DEFAULT"; return; + case DNN_BACKEND_HALIDE: *os << "HALIDE"; return; + case DNN_BACKEND_INFERENCE_ENGINE: *os << "DLIE"; return; + case DNN_BACKEND_OPENCV: *os << "OCV"; return; + } // don't use "default:" to emit compiler warnings + *os << "DNN_BACKEND_UNKNOWN(" << v << ")"; +} + +static inline void PrintTo(const cv::dnn::Target& v, std::ostream* os) +{ + switch (v) { + case DNN_TARGET_CPU: *os << "CPU"; return; + case DNN_TARGET_OPENCL: *os << "OCL"; return; + case DNN_TARGET_OPENCL_FP16: *os << "OCL_FP16"; return; + case DNN_TARGET_MYRIAD: *os << "MYRIAD"; return; + } // don't use "default:" to emit compiler warnings + *os << "DNN_TARGET_UNKNOWN(" << v << ")"; +} + +using opencv_test::tuple; +using opencv_test::get; +static inline void PrintTo(const tuple v, std::ostream* os) +{ + PrintTo(get<0>(v), os); + *os << "/"; + PrintTo(get<1>(v), os); +} + +CV__DNN_INLINE_NS_END +}} // namespace + + static inline const std::string &getOpenCVExtraDir() { return cvtest::TS::ptr()->get_data_path(); @@ -190,4 +231,54 @@ static inline bool readFileInMemory(const std::string& filename, std::string& co return true; } +namespace opencv_test { + +using namespace cv::dnn; + +static testing::internal::ParamGenerator > dnnBackendsAndTargets( + bool withInferenceEngine = true, + bool withHalide = false, + bool withCpuOCV = true +) +{ + std::vector > targets; +#ifdef HAVE_HALIDE + if (withHalide) + { + targets.push_back(make_tuple(DNN_BACKEND_HALIDE, DNN_TARGET_CPU)); +#ifdef HAVE_OPENCL + if (cv::ocl::useOpenCL()) + targets.push_back(make_tuple(DNN_BACKEND_HALIDE, DNN_TARGET_OPENCL)); +#endif + } +#endif +#ifdef HAVE_INF_ENGINE + if (withInferenceEngine) + { + targets.push_back(make_tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_CPU)); +#ifdef HAVE_OPENCL + if (cv::ocl::useOpenCL()) + { + targets.push_back(make_tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL)); + targets.push_back(make_tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL_FP16)); + } +#endif + if (checkMyriadTarget()) + targets.push_back(make_tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_MYRIAD)); + } +#endif + if (withCpuOCV) + targets.push_back(make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_CPU)); +#ifdef HAVE_OPENCL + if (cv::ocl::useOpenCL()) + { + targets.push_back(make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_OPENCL)); + targets.push_back(make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_OPENCL_FP16)); + } +#endif + return testing::ValuesIn(targets); +} + +} // namespace + #endif diff --git a/modules/dnn/test/test_halide_layers.cpp b/modules/dnn/test/test_halide_layers.cpp index 11d059223ce7..445f85b376f7 100644 --- a/modules/dnn/test/test_halide_layers.cpp +++ b/modules/dnn/test/test_halide_layers.cpp @@ -44,23 +44,9 @@ static void test(LayerParams& params, Mat& input, Backend backendId, Target targ test(input, net, backendId, targetId, skipCheck); } -static testing::internal::ParamGenerator > dnnBackendsAndTargetsWithHalide() +static inline testing::internal::ParamGenerator > dnnBackendsAndTargetsWithHalide() { - static const tuple testCases[] = { -#ifdef HAVE_HALIDE - tuple(DNN_BACKEND_HALIDE, DNN_TARGET_CPU), - tuple(DNN_BACKEND_HALIDE, DNN_TARGET_OPENCL), -#endif -#ifdef HAVE_INF_ENGINE - tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_CPU), - tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL), - tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL_FP16), - tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_MYRIAD), -#endif - tuple(DNN_BACKEND_OPENCV, DNN_TARGET_OPENCL), - tuple(DNN_BACKEND_OPENCV, DNN_TARGET_OPENCL_FP16) - }; - return testing::ValuesIn(testCases); + return dnnBackendsAndTargets(true, true, false); // OpenCV/CPU is used as reference } class Test_Halide_layers : public DNNTestLayer {}; diff --git a/modules/dnn/test/test_ie_models.cpp b/modules/dnn/test/test_ie_models.cpp index 9fefe4fd0450..22dc1fe65f8a 100644 --- a/modules/dnn/test/test_ie_models.cpp +++ b/modules/dnn/test/test_ie_models.cpp @@ -177,10 +177,6 @@ TEST_P(DNNTestOpenVINO, models) Target target = (dnn::Target)(int)get<0>(GetParam()); std::string modelName = get<1>(GetParam()); - if ((modelName == "semantic-segmentation-adas-0001" && target == DNN_TARGET_OPENCL_FP16) || - (modelName == "vehicle-license-plate-detection-barrier-0106")) - throw SkipTestException(""); - std::string precision = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? "FP16" : "FP32"; std::string prefix = utils::fs::join("intel_models", utils::fs::join(modelName, diff --git a/modules/dnn/test/test_precomp.hpp b/modules/dnn/test/test_precomp.hpp index d74e0bf9afa1..6c1fbd64b1c4 100644 --- a/modules/dnn/test/test_precomp.hpp +++ b/modules/dnn/test/test_precomp.hpp @@ -49,35 +49,6 @@ #include "opencv2/dnn.hpp" #include "test_common.hpp" -namespace cv { -namespace dnn { -CV__DNN_INLINE_NS_BEGIN - -static inline void PrintTo(const cv::dnn::Backend& v, std::ostream* os) -{ - switch (v) { - case DNN_BACKEND_DEFAULT: *os << "DNN_BACKEND_DEFAULT"; return; - case DNN_BACKEND_HALIDE: *os << "DNN_BACKEND_HALIDE"; return; - case DNN_BACKEND_INFERENCE_ENGINE: *os << "DNN_BACKEND_INFERENCE_ENGINE"; return; - case DNN_BACKEND_OPENCV: *os << "DNN_BACKEND_OPENCV"; return; - } // don't use "default:" to emit compiler warnings - *os << "DNN_BACKEND_UNKNOWN(" << v << ")"; -} - -static inline void PrintTo(const cv::dnn::Target& v, std::ostream* os) -{ - switch (v) { - case DNN_TARGET_CPU: *os << "DNN_TARGET_CPU"; return; - case DNN_TARGET_OPENCL: *os << "DNN_TARGET_OPENCL"; return; - case DNN_TARGET_OPENCL_FP16: *os << "DNN_TARGET_OPENCL_FP16"; return; - case DNN_TARGET_MYRIAD: *os << "DNN_TARGET_MYRIAD"; return; - } // don't use "default:" to emit compiler warnings - *os << "DNN_TARGET_UNKNOWN(" << v << ")"; -} - -CV__DNN_INLINE_NS_END -}} // namespace - namespace opencv_test { using namespace cv::dnn; @@ -95,22 +66,6 @@ static testing::internal::ParamGenerator availableDnnTargets() return testing::ValuesIn(targets); } -static testing::internal::ParamGenerator > dnnBackendsAndTargets() -{ - static const tuple testCases[] = { - #ifdef HAVE_INF_ENGINE - tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_CPU), - tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL), - tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_OPENCL_FP16), - tuple(DNN_BACKEND_INFERENCE_ENGINE, DNN_TARGET_MYRIAD), - #endif - tuple(DNN_BACKEND_OPENCV, DNN_TARGET_CPU), - tuple(DNN_BACKEND_OPENCV, DNN_TARGET_OPENCL), - tuple(DNN_BACKEND_OPENCV, DNN_TARGET_OPENCL_FP16) - }; - return testing::ValuesIn(testCases); -} - class DNNTestLayer : public TestWithParam > { public: diff --git a/modules/dnn/test/test_tf_importer.cpp b/modules/dnn/test/test_tf_importer.cpp index d95f6f5081eb..71aa4e74617b 100644 --- a/modules/dnn/test/test_tf_importer.cpp +++ b/modules/dnn/test/test_tf_importer.cpp @@ -296,7 +296,7 @@ TEST_P(Test_TensorFlow_nets, Inception_v2_SSD) Net net = readNetFromTensorflow(model, proto); Mat img = imread(findDataFile("dnn/street.png", false)); - Mat blob = blobFromImage(img, 1.0f / 127.5, Size(300, 300), Scalar(127.5, 127.5, 127.5), true, false); + Mat blob = blobFromImage(img, 1.0f, Size(300, 300), Scalar(), true, false); net.setPreferableBackend(backend); net.setPreferableTarget(target); @@ -310,32 +310,61 @@ TEST_P(Test_TensorFlow_nets, Inception_v2_SSD) 0, 3, 0.75838411, 0.44668293, 0.45907149, 0.49459291, 0.52197015, 0, 10, 0.95932811, 0.38349164, 0.32528657, 0.40387636, 0.39165527, 0, 10, 0.93973452, 0.66561931, 0.37841269, 0.68074018, 0.42907384); - double scoreDiff = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 5e-3 : default_l1; + double scoreDiff = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 0.0097 : default_l1; double iouDiff = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 0.09 : default_lInf; normAssertDetections(ref, out, "", 0.5, scoreDiff, iouDiff); } -TEST_P(Test_TensorFlow_nets, Inception_v2_Faster_RCNN) +TEST_P(Test_TensorFlow_nets, MobileNet_v1_SSD) { checkBackend(); - if ((backend == DNN_BACKEND_INFERENCE_ENGINE && target != DNN_TARGET_CPU) || - (backend == DNN_BACKEND_OPENCV && target == DNN_TARGET_OPENCL_FP16)) - throw SkipTestException(""); - std::string proto = findDataFile("dnn/faster_rcnn_inception_v2_coco_2018_01_28.pbtxt", false); - std::string model = findDataFile("dnn/faster_rcnn_inception_v2_coco_2018_01_28.pb", false); + std::string model = findDataFile("dnn/ssd_mobilenet_v1_coco_2017_11_17.pb", false); + std::string proto = findDataFile("dnn/ssd_mobilenet_v1_coco_2017_11_17.pbtxt", false); Net net = readNetFromTensorflow(model, proto); + Mat img = imread(findDataFile("dnn/dog416.png", false)); + Mat blob = blobFromImage(img, 1.0f, Size(300, 300), Scalar(), true, false); + net.setPreferableBackend(backend); net.setPreferableTarget(target); - Mat img = imread(findDataFile("dnn/dog416.png", false)); - Mat blob = blobFromImage(img, 1.0f / 127.5, Size(800, 600), Scalar(127.5, 127.5, 127.5), true, false); net.setInput(blob); Mat out = net.forward(); - Mat ref = blobFromNPY(findDataFile("dnn/tensorflow/faster_rcnn_inception_v2_coco_2018_01_28.detection_out.npy")); - normAssertDetections(ref, out, "", 0.3); + Mat ref = blobFromNPY(findDataFile("dnn/tensorflow/ssd_mobilenet_v1_coco_2017_11_17.detection_out.npy")); + float scoreDiff = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 7e-3 : 1e-5; + float iouDiff = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 0.0098 : 1e-3; + normAssertDetections(ref, out, "", 0.3, scoreDiff, iouDiff); +} + +TEST_P(Test_TensorFlow_nets, Faster_RCNN) +{ + static std::string names[] = {"faster_rcnn_inception_v2_coco_2018_01_28", + "faster_rcnn_resnet50_coco_2018_01_28"}; + + checkBackend(); + if ((backend == DNN_BACKEND_INFERENCE_ENGINE && target != DNN_TARGET_CPU) || + (backend == DNN_BACKEND_OPENCV && target == DNN_TARGET_OPENCL_FP16)) + throw SkipTestException(""); + + for (int i = 1; i < 2; ++i) + { + std::string proto = findDataFile("dnn/" + names[i] + ".pbtxt", false); + std::string model = findDataFile("dnn/" + names[i] + ".pb", false); + + Net net = readNetFromTensorflow(model, proto); + net.setPreferableBackend(backend); + net.setPreferableTarget(target); + Mat img = imread(findDataFile("dnn/dog416.png", false)); + Mat blob = blobFromImage(img, 1.0f, Size(800, 600), Scalar(), true, false); + + net.setInput(blob); + Mat out = net.forward(); + + Mat ref = blobFromNPY(findDataFile("dnn/tensorflow/" + names[i] + ".detection_out.npy")); + normAssertDetections(ref, out, names[i].c_str(), 0.3); + } } TEST_P(Test_TensorFlow_nets, MobileNet_v1_SSD_PPN) @@ -347,15 +376,17 @@ TEST_P(Test_TensorFlow_nets, MobileNet_v1_SSD_PPN) Net net = readNetFromTensorflow(model, proto); Mat img = imread(findDataFile("dnn/dog416.png", false)); Mat ref = blobFromNPY(findDataFile("dnn/tensorflow/ssd_mobilenet_v1_ppn_coco.detection_out.npy", false)); - Mat blob = blobFromImage(img, 1.0f / 127.5, Size(300, 300), Scalar(127.5, 127.5, 127.5), true, false); + Mat blob = blobFromImage(img, 1.0f, Size(300, 300), Scalar(), true, false); net.setPreferableBackend(backend); net.setPreferableTarget(target); net.setInput(blob); Mat out = net.forward(); - double scoreDiff = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 0.006 : default_l1; - normAssertDetections(ref, out, "", 0.4, scoreDiff, default_lInf); + + double scoreDiff = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 0.011 : default_l1; + double iouDiff = (target == DNN_TARGET_OPENCL_FP16 || target == DNN_TARGET_MYRIAD) ? 0.021 : default_lInf; + normAssertDetections(ref, out, "", 0.4, scoreDiff, iouDiff); } TEST_P(Test_TensorFlow_nets, opencv_face_detector_uint8) diff --git a/modules/dnn/test/test_torch_importer.cpp b/modules/dnn/test/test_torch_importer.cpp index 13e3ddeacb72..b6583da7ef58 100644 --- a/modules/dnn/test/test_torch_importer.cpp +++ b/modules/dnn/test/test_torch_importer.cpp @@ -301,14 +301,14 @@ TEST_P(Test_Torch_nets, ENet_accuracy) // Due to numerical instability in Pooling-Unpooling layers (indexes jittering) // thresholds for ENet must be changed. Accuracy of results was checked on // Cityscapes dataset and difference in mIOU with Torch is 10E-4% - normAssert(ref, out, "", 0.00044, 0.44); + normAssert(ref, out, "", 0.00044, target == DNN_TARGET_CPU ? 0.453 : 0.44); const int N = 3; for (int i = 0; i < N; i++) { net.setInput(inputBlob, ""); Mat out = net.forward(); - normAssert(ref, out, "", 0.00044, 0.44); + normAssert(ref, out, "", 0.00044, target == DNN_TARGET_CPU ? 0.453 : 0.44); } } diff --git a/modules/imgcodecs/src/grfmt_webp.cpp b/modules/imgcodecs/src/grfmt_webp.cpp index 53dd056f5950..58ddec3665dc 100644 --- a/modules/imgcodecs/src/grfmt_webp.cpp +++ b/modules/imgcodecs/src/grfmt_webp.cpp @@ -54,15 +54,21 @@ #include "opencv2/imgproc.hpp" -const size_t WEBP_HEADER_SIZE = 32; +#include namespace cv { +// 64Mb limit to avoid memory DDOS +static size_t param_maxFileSize = utils::getConfigurationParameterSizeT("OPENCV_IMGCODECS_WEBP_MAX_FILE_SIZE", 64*1024*1024); + +static const size_t WEBP_HEADER_SIZE = 32; + WebPDecoder::WebPDecoder() { m_buf_supported = true; channels = 0; + fs_size = 0; } WebPDecoder::~WebPDecoder() {} @@ -96,48 +102,29 @@ ImageDecoder WebPDecoder::newDecoder() const bool WebPDecoder::readHeader() { + uint8_t header[WEBP_HEADER_SIZE] = { 0 }; if (m_buf.empty()) { - FILE * wfile = NULL; - - wfile = fopen(m_filename.c_str(), "rb"); - - if(wfile == NULL) - { - return false; - } - - fseek(wfile, 0, SEEK_END); - long int wfile_size = ftell(wfile); - fseek(wfile, 0, SEEK_SET); - - if(wfile_size > static_cast(INT_MAX)) - { - fclose(wfile); - return false; - } - - data.create(1, (int)wfile_size, CV_8U); - - size_t data_size = fread(data.ptr(), 1, wfile_size, wfile); - - if(wfile) - { - fclose(wfile); - } - - if(static_cast(data_size) != wfile_size) - { - return false; - } + fs.open(m_filename.c_str(), std::ios::binary); + fs.seekg(0, std::ios::end); + fs_size = safeCastToSizeT(fs.tellg(), "File is too large"); + fs.seekg(0, std::ios::beg); + CV_Assert(fs && "File stream error"); + CV_CheckGE(fs_size, WEBP_HEADER_SIZE, "File is too small"); + CV_CheckLE(fs_size, param_maxFileSize, "File is too large. Increase OPENCV_IMGCODECS_WEBP_MAX_FILE_SIZE parameter if you want to process large files"); + + fs.read((char*)header, sizeof(header)); + CV_Assert(fs && "Can't read WEBP_HEADER_SIZE bytes"); } else { + CV_CheckGE(m_buf.total(), WEBP_HEADER_SIZE, "Buffer is too small"); + memcpy(header, m_buf.ptr(), sizeof(header)); data = m_buf; } WebPBitstreamFeatures features; - if(VP8_STATUS_OK == WebPGetFeatures(data.ptr(), WEBP_HEADER_SIZE, &features)) + if (VP8_STATUS_OK == WebPGetFeatures(header, sizeof(header), &features)) { m_width = features.width; m_height = features.height; @@ -161,41 +148,75 @@ bool WebPDecoder::readHeader() bool WebPDecoder::readData(Mat &img) { - if( m_width > 0 && m_height > 0 ) + CV_CheckGE(m_width, 0, ""); CV_CheckGE(m_height, 0, ""); + + CV_CheckEQ(img.cols, m_width, ""); + CV_CheckEQ(img.rows, m_height, ""); + + if (m_buf.empty()) { - bool convert_grayscale = (img.type() == CV_8UC1); // IMREAD_GRAYSCALE requested + fs.seekg(0, std::ios::beg); CV_Assert(fs && "File stream error"); + data.create(1, validateToInt(fs_size), CV_8UC1); + fs.read((char*)data.ptr(), fs_size); + CV_Assert(fs && "Can't read file data"); + fs.close(); + } + CV_Assert(data.type() == CV_8UC1); CV_Assert(data.rows == 1); - if (img.cols != m_width || img.rows != m_height || img.type() != m_type) + { + Mat read_img; + CV_CheckType(img.type(), img.type() == CV_8UC1 || img.type() == CV_8UC3 || img.type() == CV_8UC4, ""); + if (img.type() != m_type) + { + read_img.create(m_height, m_width, m_type); + } + else { - img.create(m_height, m_width, m_type); + read_img = img; // copy header } - uchar* out_data = img.ptr(); - size_t out_data_size = img.cols * img.rows * img.elemSize(); + uchar* out_data = read_img.ptr(); + size_t out_data_size = read_img.dataend - out_data; - uchar *res_ptr = 0; + uchar *res_ptr = NULL; if (channels == 3) { + CV_CheckTypeEQ(read_img.type(), CV_8UC3, ""); res_ptr = WebPDecodeBGRInto(data.ptr(), data.total(), out_data, - (int)out_data_size, (int)img.step); + (int)out_data_size, (int)read_img.step); } else if (channels == 4) { + CV_CheckTypeEQ(read_img.type(), CV_8UC4, ""); res_ptr = WebPDecodeBGRAInto(data.ptr(), data.total(), out_data, - (int)out_data_size, (int)img.step); + (int)out_data_size, (int)read_img.step); } - if(res_ptr == out_data) + if (res_ptr != out_data) + return false; + + if (read_img.data == img.data && img.type() == m_type) { - if (convert_grayscale) - { - cvtColor(img, img, COLOR_BGR2GRAY); - } - return true; + // nothing + } + else if (img.type() == CV_8UC1) + { + cvtColor(read_img, img, COLOR_BGR2GRAY); + } + else if (img.type() == CV_8UC3 && m_type == CV_8UC4) + { + cvtColor(read_img, img, COLOR_BGRA2BGR); + } + else if (img.type() == CV_8UC3 && m_type == CV_8UC4) + { + cvtColor(read_img, img, COLOR_BGRA2BGR); + } + else + { + CV_Error(Error::StsInternal, ""); } } - - return false; + return true; } WebPEncoder::WebPEncoder() @@ -213,12 +234,9 @@ ImageEncoder WebPEncoder::newEncoder() const bool WebPEncoder::write(const Mat& img, const std::vector& params) { - int channels = img.channels(), depth = img.depth(); - int width = img.cols, height = img.rows; + CV_CheckDepthEQ(img.depth(), CV_8U, "WebP codec supports 8U images only"); - const Mat *image = &img; - Mat temp; - size_t size = 0; + const int width = img.cols, height = img.rows; bool comp_lossless = true; float quality = 100.0f; @@ -240,69 +258,64 @@ bool WebPEncoder::write(const Mat& img, const std::vector& params) } } - uint8_t *out = NULL; + int channels = img.channels(); + CV_Check(channels, channels == 1 || channels == 3 || channels == 4, ""); - if(depth != CV_8U) - { - return false; - } + const Mat *image = &img; + Mat temp; - if(channels == 1) + if (channels == 1) { cvtColor(*image, temp, CV_GRAY2BGR); image = &temp; channels = 3; } - else if (channels == 2) - { - return false; - } + uint8_t *out = NULL; + size_t size = 0; if (comp_lossless) { - if(channels == 3) + if (channels == 3) { size = WebPEncodeLosslessBGR(image->ptr(), width, height, (int)image->step, &out); } - else if(channels == 4) + else if (channels == 4) { size = WebPEncodeLosslessBGRA(image->ptr(), width, height, (int)image->step, &out); } } else { - if(channels == 3) + if (channels == 3) { size = WebPEncodeBGR(image->ptr(), width, height, (int)image->step, quality, &out); } - else if(channels == 4) + else if (channels == 4) { size = WebPEncodeBGRA(image->ptr(), width, height, (int)image->step, quality, &out); } } +#if WEBP_DECODER_ABI_VERSION >= 0x0206 + Ptr out_cleaner(out, WebPFree); +#else + Ptr out_cleaner(out, free); +#endif + + CV_Assert(size > 0); - if(size > 0) + if (m_buf) { - if(m_buf) - { - m_buf->resize(size); - memcpy(&(*m_buf)[0], out, size); - } - else - { - FILE *fd = fopen(m_filename.c_str(), "wb"); - if(fd != NULL) - { - fwrite(out, size, sizeof(uint8_t), fd); - fclose(fd); fd = NULL; - } - } + m_buf->resize(size); + memcpy(&(*m_buf)[0], out, size); } - - if (out != NULL) + else { - free(out); - out = NULL; + FILE *fd = fopen(m_filename.c_str(), "wb"); + if (fd != NULL) + { + fwrite(out, size, sizeof(uint8_t), fd); + fclose(fd); fd = NULL; + } } return size > 0; diff --git a/modules/imgcodecs/src/grfmt_webp.hpp b/modules/imgcodecs/src/grfmt_webp.hpp index 79e041b2129c..6d833e0db6eb 100644 --- a/modules/imgcodecs/src/grfmt_webp.hpp +++ b/modules/imgcodecs/src/grfmt_webp.hpp @@ -47,7 +47,7 @@ #ifdef HAVE_WEBP - +#include namespace cv { @@ -61,7 +61,6 @@ class WebPDecoder CV_FINAL : public BaseImageDecoder bool readData( Mat& img ) CV_OVERRIDE; bool readHeader() CV_OVERRIDE; - void close(); size_t signatureLength() const CV_OVERRIDE; bool checkSignature( const String& signature) const CV_OVERRIDE; @@ -69,6 +68,8 @@ class WebPDecoder CV_FINAL : public BaseImageDecoder ImageDecoder newDecoder() const CV_OVERRIDE; protected: + std::ifstream fs; + size_t fs_size; Mat data; int channels; }; diff --git a/modules/imgcodecs/src/loadsave.cpp b/modules/imgcodecs/src/loadsave.cpp index 204440943520..8d89b412a04a 100644 --- a/modules/imgcodecs/src/loadsave.cpp +++ b/modules/imgcodecs/src/loadsave.cpp @@ -400,6 +400,8 @@ static void ApplyExifOrientation(const Mat& buf, Mat& img) static void* imread_( const String& filename, int flags, int hdrtype, Mat* mat=0 ) { + CV_Assert(mat || hdrtype != LOAD_MAT); // mat is required in LOAD_MAT case + IplImage* image = 0; CvMat *matrix = 0; Mat temp, *data = &temp; @@ -711,11 +713,22 @@ static bool imwrite_( const String& filename, const std::vector& img_vec, encoder->setDestination( filename ); CV_Assert(params.size() <= CV_IO_MAX_IMAGE_PARAMS*2); - bool code; - if (!isMultiImg) - code = encoder->write( write_vec[0], params ); - else - code = encoder->writemulti( write_vec, params ); //to be implemented + bool code = false; + try + { + if (!isMultiImg) + code = encoder->write( write_vec[0], params ); + else + code = encoder->writemulti( write_vec, params ); //to be implemented + } + catch (const cv::Exception& e) + { + std::cerr << "imwrite_('" << filename << "'): can't write data: " << e.what() << std::endl << std::flush; + } + catch (...) + { + std::cerr << "imwrite_('" << filename << "'): can't write data: unknown exception" << std::endl << std::flush; + } // CV_Assert( code ); return code; diff --git a/modules/imgcodecs/src/utils.hpp b/modules/imgcodecs/src/utils.hpp index 7af4c6174eed..6e0ec95826f2 100644 --- a/modules/imgcodecs/src/utils.hpp +++ b/modules/imgcodecs/src/utils.hpp @@ -44,6 +44,15 @@ int validateToInt(size_t step); +template static inline +size_t safeCastToSizeT(const _Tp v_origin, const char* msg) +{ + const size_t value_cast = (size_t)v_origin; + if ((_Tp)value_cast != v_origin) + CV_Error(cv::Error::StsError, msg ? msg : "Can't cast value into size_t"); + return value_cast; +} + struct PaletteEntry { unsigned char b, g, r, a; diff --git a/modules/imgcodecs/test/test_webp.cpp b/modules/imgcodecs/test/test_webp.cpp index e527659aa4fb..1f2cad7d89c1 100644 --- a/modules/imgcodecs/test/test_webp.cpp +++ b/modules/imgcodecs/test/test_webp.cpp @@ -96,12 +96,17 @@ TEST(Imgcodecs_WebP, encode_decode_with_alpha_webp) string output = cv::tempfile(".webp"); EXPECT_NO_THROW(cv::imwrite(output, img)); - cv::Mat img_webp = cv::imread(output); + cv::Mat img_webp = cv::imread(output, IMREAD_UNCHANGED); + cv::Mat img_webp_bgr = cv::imread(output); // IMREAD_COLOR by default EXPECT_EQ(0, remove(output.c_str())); EXPECT_FALSE(img_webp.empty()); EXPECT_EQ(4, img_webp.channels()); EXPECT_EQ(512, img_webp.cols); EXPECT_EQ(512, img_webp.rows); + EXPECT_FALSE(img_webp_bgr.empty()); + EXPECT_EQ(3, img_webp_bgr.channels()); + EXPECT_EQ(512, img_webp_bgr.cols); + EXPECT_EQ(512, img_webp_bgr.rows); } #endif // HAVE_WEBP diff --git a/modules/imgproc/misc/java/test/Subdiv2DTest.java b/modules/imgproc/misc/java/test/Subdiv2DTest.java index 630d31737877..1f27bc641c9c 100644 --- a/modules/imgproc/misc/java/test/Subdiv2DTest.java +++ b/modules/imgproc/misc/java/test/Subdiv2DTest.java @@ -52,7 +52,7 @@ public void testGetTriangleList() { s2d.insert( new Point(10, 20) ); MatOfFloat6 triangles = new MatOfFloat6(); s2d.getTriangleList(triangles); - assertEquals(10, triangles.rows()); + assertEquals(2, triangles.rows()); /* int cnt = triangles.rows(); float buff[] = new float[cnt*6]; diff --git a/modules/imgproc/src/accum.cpp b/modules/imgproc/src/accum.cpp index fece3139e704..793e362bdd8f 100644 --- a/modules/imgproc/src/accum.cpp +++ b/modules/imgproc/src/accum.cpp @@ -332,7 +332,7 @@ void cv::accumulate( InputArray _src, InputOutputArray _dst, InputArray _mask ) CV_Assert( func != 0 ); const Mat* arrays[] = {&src, &dst, &mask, 0}; - uchar* ptrs[3]{}; + uchar* ptrs[3] = {}; NAryMatIterator it(arrays, ptrs); int len = (int)it.size; @@ -430,7 +430,7 @@ void cv::accumulateSquare( InputArray _src, InputOutputArray _dst, InputArray _m CV_Assert( func != 0 ); const Mat* arrays[] = {&src, &dst, &mask, 0}; - uchar* ptrs[3]{}; + uchar* ptrs[3] = {}; NAryMatIterator it(arrays, ptrs); int len = (int)it.size; @@ -533,7 +533,7 @@ void cv::accumulateProduct( InputArray _src1, InputArray _src2, CV_Assert( func != 0 ); const Mat* arrays[] = {&src1, &src2, &dst, &mask, 0}; - uchar* ptrs[4]{}; + uchar* ptrs[4] = {}; NAryMatIterator it(arrays, ptrs); int len = (int)it.size; @@ -635,7 +635,7 @@ void cv::accumulateWeighted( InputArray _src, InputOutputArray _dst, CV_Assert( func != 0 ); const Mat* arrays[] = {&src, &dst, &mask, 0}; - uchar* ptrs[3]{}; + uchar* ptrs[3] = {}; NAryMatIterator it(arrays, ptrs); int len = (int)it.size; diff --git a/modules/imgproc/src/contours.cpp b/modules/imgproc/src/contours.cpp index eb47816c86db..456b3cc2bb05 100644 --- a/modules/imgproc/src/contours.cpp +++ b/modules/imgproc/src/contours.cpp @@ -1123,7 +1123,6 @@ cvFindNextContour( CvContourScanner scanner ) #endif { _CvContourInfo *par_info = 0; - _CvContourInfo *l_cinfo = 0; CvSeq *seq = 0; int is_hole = 0; CvPoint origin; @@ -1215,6 +1214,7 @@ cvFindNextContour( CvContourScanner scanner ) seq->flags |= is_hole ? CV_SEQ_FLAG_HOLE : 0; /* initialize header */ + _CvContourInfo *l_cinfo = 0; if( mode <= 1 ) { l_cinfo = &(scanner->cinfo_temp); @@ -1225,10 +1225,8 @@ cvFindNextContour( CvContourScanner scanner ) } else { - union { _CvContourInfo* ci; CvSetElem* se; } v; - v.ci = l_cinfo; - cvSetAdd( scanner->cinfo_set, 0, &v.se ); - l_cinfo = v.ci; + cvSetAdd(scanner->cinfo_set, 0, (CvSetElem**)&l_cinfo); + CV_Assert(l_cinfo); int lval; if( img_i ) @@ -1298,16 +1296,16 @@ cvFindNextContour( CvContourScanner scanner ) scanner->img = (schar *) img; scanner->nbd = nbd; return l_cinfo->contour; - - resume_scan: - + } + resume_scan: + { prev = p; /* update lnbd */ if( prev & -2 ) { lnbd.x = x; } - } /* end of prev != p */ + } } /* end of loop on x */ lnbd.x = 0; diff --git a/modules/imgproc/src/distransform.cpp b/modules/imgproc/src/distransform.cpp index b91f9b88ff0c..173e79ed857e 100644 --- a/modules/imgproc/src/distransform.cpp +++ b/modules/imgproc/src/distransform.cpp @@ -45,7 +45,8 @@ namespace cv { static const int DIST_SHIFT = 16; -static const int INIT_DIST0 = (INT_MAX >> 2); +static const int INIT_DIST0 = INT_MAX; +static const int DIST_MAX = (INT_MAX >> 2); #define CV_FLT_TO_FIX(x,n) cvRound((x)*(1<<(n))) static void @@ -71,8 +72,8 @@ distanceTransform_3x3( const Mat& _src, Mat& _temp, Mat& _dist, const float* met { const int BORDER = 1; int i, j; - const int HV_DIST = CV_FLT_TO_FIX( metrics[0], DIST_SHIFT ); - const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], DIST_SHIFT ); + const unsigned int HV_DIST = CV_FLT_TO_FIX( metrics[0], DIST_SHIFT ); + const unsigned int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], DIST_SHIFT ); const float scale = 1.f/(1 << DIST_SHIFT); const uchar* src = _src.ptr(); @@ -89,7 +90,7 @@ distanceTransform_3x3( const Mat& _src, Mat& _temp, Mat& _dist, const float* met for( i = 0; i < size.height; i++ ) { const uchar* s = src + i*srcstep; - int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; + unsigned int* tmp = (unsigned int*)(temp + (i+BORDER)*step) + BORDER; for( j = 0; j < BORDER; j++ ) tmp[-j-1] = tmp[size.width + j] = INIT_DIST0; @@ -100,8 +101,8 @@ distanceTransform_3x3( const Mat& _src, Mat& _temp, Mat& _dist, const float* met tmp[j] = 0; else { - int t0 = tmp[j-step-1] + DIAG_DIST; - int t = tmp[j-step] + HV_DIST; + unsigned int t0 = tmp[j-step-1] + DIAG_DIST; + unsigned int t = tmp[j-step] + HV_DIST; if( t0 > t ) t0 = t; t = tmp[j-step+1] + DIAG_DIST; if( t0 > t ) t0 = t; @@ -116,14 +117,14 @@ distanceTransform_3x3( const Mat& _src, Mat& _temp, Mat& _dist, const float* met for( i = size.height - 1; i >= 0; i-- ) { float* d = (float*)(dist + i*dststep); - int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; + unsigned int* tmp = (unsigned int*)(temp + (i+BORDER)*step) + BORDER; for( j = size.width - 1; j >= 0; j-- ) { - int t0 = tmp[j]; + unsigned int t0 = tmp[j]; if( t0 > HV_DIST ) { - int t = tmp[j+step+1] + DIAG_DIST; + unsigned int t = tmp[j+step+1] + DIAG_DIST; if( t0 > t ) t0 = t; t = tmp[j+step] + HV_DIST; if( t0 > t ) t0 = t; @@ -133,6 +134,7 @@ distanceTransform_3x3( const Mat& _src, Mat& _temp, Mat& _dist, const float* met if( t0 > t ) t0 = t; tmp[j] = t0; } + t0 = (t0 > DIST_MAX) ? DIST_MAX : t0; d[j] = (float)(t0 * scale); } } @@ -144,9 +146,9 @@ distanceTransform_5x5( const Mat& _src, Mat& _temp, Mat& _dist, const float* met { const int BORDER = 2; int i, j; - const int HV_DIST = CV_FLT_TO_FIX( metrics[0], DIST_SHIFT ); - const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], DIST_SHIFT ); - const int LONG_DIST = CV_FLT_TO_FIX( metrics[2], DIST_SHIFT ); + const unsigned int HV_DIST = CV_FLT_TO_FIX( metrics[0], DIST_SHIFT ); + const unsigned int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], DIST_SHIFT ); + const unsigned int LONG_DIST = CV_FLT_TO_FIX( metrics[2], DIST_SHIFT ); const float scale = 1.f/(1 << DIST_SHIFT); const uchar* src = _src.ptr(); @@ -163,7 +165,7 @@ distanceTransform_5x5( const Mat& _src, Mat& _temp, Mat& _dist, const float* met for( i = 0; i < size.height; i++ ) { const uchar* s = src + i*srcstep; - int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; + unsigned int* tmp = (unsigned int*)(temp + (i+BORDER)*step) + BORDER; for( j = 0; j < BORDER; j++ ) tmp[-j-1] = tmp[size.width + j] = INIT_DIST0; @@ -174,8 +176,8 @@ distanceTransform_5x5( const Mat& _src, Mat& _temp, Mat& _dist, const float* met tmp[j] = 0; else { - int t0 = tmp[j-step*2-1] + LONG_DIST; - int t = tmp[j-step*2+1] + LONG_DIST; + unsigned int t0 = tmp[j-step*2-1] + LONG_DIST; + unsigned int t = tmp[j-step*2+1] + LONG_DIST; if( t0 > t ) t0 = t; t = tmp[j-step-2] + LONG_DIST; if( t0 > t ) t0 = t; @@ -198,14 +200,14 @@ distanceTransform_5x5( const Mat& _src, Mat& _temp, Mat& _dist, const float* met for( i = size.height - 1; i >= 0; i-- ) { float* d = (float*)(dist + i*dststep); - int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; + unsigned int* tmp = (unsigned int*)(temp + (i+BORDER)*step) + BORDER; for( j = size.width - 1; j >= 0; j-- ) { - int t0 = tmp[j]; + unsigned int t0 = tmp[j]; if( t0 > HV_DIST ) { - int t = tmp[j+step*2+1] + LONG_DIST; + unsigned int t = tmp[j+step*2+1] + LONG_DIST; if( t0 > t ) t0 = t; t = tmp[j+step*2-1] + LONG_DIST; if( t0 > t ) t0 = t; @@ -223,6 +225,7 @@ distanceTransform_5x5( const Mat& _src, Mat& _temp, Mat& _dist, const float* met if( t0 > t ) t0 = t; tmp[j] = t0; } + t0 = (t0 > DIST_MAX) ? DIST_MAX : t0; d[j] = (float)(t0 * scale); } } @@ -235,9 +238,9 @@ distanceTransformEx_5x5( const Mat& _src, Mat& _temp, Mat& _dist, Mat& _labels, const int BORDER = 2; int i, j; - const int HV_DIST = CV_FLT_TO_FIX( metrics[0], DIST_SHIFT ); - const int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], DIST_SHIFT ); - const int LONG_DIST = CV_FLT_TO_FIX( metrics[2], DIST_SHIFT ); + const unsigned int HV_DIST = CV_FLT_TO_FIX( metrics[0], DIST_SHIFT ); + const unsigned int DIAG_DIST = CV_FLT_TO_FIX( metrics[1], DIST_SHIFT ); + const unsigned int LONG_DIST = CV_FLT_TO_FIX( metrics[2], DIST_SHIFT ); const float scale = 1.f/(1 << DIST_SHIFT); const uchar* src = _src.ptr(); @@ -247,7 +250,7 @@ distanceTransformEx_5x5( const Mat& _src, Mat& _temp, Mat& _dist, Mat& _labels, int srcstep = (int)(_src.step/sizeof(src[0])); int step = (int)(_temp.step/sizeof(temp[0])); int dststep = (int)(_dist.step/sizeof(dist[0])); - int lstep = (int)(_labels.step/sizeof(dist[0])); + int lstep = (int)(_labels.step/sizeof(labels[0])); Size size = _src.size(); initTopBottom( _temp, BORDER ); @@ -256,7 +259,7 @@ distanceTransformEx_5x5( const Mat& _src, Mat& _temp, Mat& _dist, Mat& _labels, for( i = 0; i < size.height; i++ ) { const uchar* s = src + i*srcstep; - int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; + unsigned int* tmp = (unsigned int*)(temp + (i+BORDER)*step) + BORDER; int* lls = (int*)(labels + i*lstep); for( j = 0; j < BORDER; j++ ) @@ -271,7 +274,7 @@ distanceTransformEx_5x5( const Mat& _src, Mat& _temp, Mat& _dist, Mat& _labels, } else { - int t0 = INIT_DIST0, t; + unsigned int t0 = INIT_DIST0, t; int l0 = 0; t = tmp[j-step*2-1] + LONG_DIST; @@ -333,16 +336,16 @@ distanceTransformEx_5x5( const Mat& _src, Mat& _temp, Mat& _dist, Mat& _labels, for( i = size.height - 1; i >= 0; i-- ) { float* d = (float*)(dist + i*dststep); - int* tmp = (int*)(temp + (i+BORDER)*step) + BORDER; + unsigned int* tmp = (unsigned int*)(temp + (i+BORDER)*step) + BORDER; int* lls = (int*)(labels + i*lstep); for( j = size.width - 1; j >= 0; j-- ) { - int t0 = tmp[j]; + unsigned int t0 = tmp[j]; int l0 = lls[j]; if( t0 > HV_DIST ) { - int t = tmp[j+step*2+1] + LONG_DIST; + unsigned int t = tmp[j+step*2+1] + LONG_DIST; if( t0 > t ) { t0 = t; @@ -393,6 +396,7 @@ distanceTransformEx_5x5( const Mat& _src, Mat& _temp, Mat& _dist, Mat& _labels, tmp[j] = t0; lls[j] = l0; } + t0 = (t0 > DIST_MAX) ? DIST_MAX : t0; d[j] = (float)(t0 * scale); } } diff --git a/modules/imgproc/src/resize.cpp b/modules/imgproc/src/resize.cpp index 016fff03d9d1..6b80415999ff 100644 --- a/modules/imgproc/src/resize.cpp +++ b/modules/imgproc/src/resize.cpp @@ -340,51 +340,199 @@ static void hlineResizeCn(ET* src, int cn, int *ofst, FT* m, FT* dst, int dst_mi hline::ResizeCn(src, cn, ofst, m, dst, dst_min, dst_max, dst_width); }; +#if CV_SIMD512 +inline void v_load_indexed1(uint8_t* src, int *ofst, v_uint16 &v_src0, v_uint16 &v_src1) +{ + v_expand(v_reinterpret_as_u8(v_uint16( + *((uint16_t*)(src + ofst[ 0])), *((uint16_t*)(src + ofst[ 1])), *((uint16_t*)(src + ofst[ 2])), *((uint16_t*)(src + ofst[ 3])), + *((uint16_t*)(src + ofst[ 4])), *((uint16_t*)(src + ofst[ 5])), *((uint16_t*)(src + ofst[ 6])), *((uint16_t*)(src + ofst[ 7])), + *((uint16_t*)(src + ofst[ 8])), *((uint16_t*)(src + ofst[ 9])), *((uint16_t*)(src + ofst[10])), *((uint16_t*)(src + ofst[11])), + *((uint16_t*)(src + ofst[12])), *((uint16_t*)(src + ofst[13])), *((uint16_t*)(src + ofst[14])), *((uint16_t*)(src + ofst[15])), + *((uint16_t*)(src + ofst[16])), *((uint16_t*)(src + ofst[17])), *((uint16_t*)(src + ofst[14])), *((uint16_t*)(src + ofst[15])), + *((uint16_t*)(src + ofst[20])), *((uint16_t*)(src + ofst[21])), *((uint16_t*)(src + ofst[14])), *((uint16_t*)(src + ofst[15])), + *((uint16_t*)(src + ofst[24])), *((uint16_t*)(src + ofst[25])), *((uint16_t*)(src + ofst[14])), *((uint16_t*)(src + ofst[15])), + *((uint16_t*)(src + ofst[28])), *((uint16_t*)(src + ofst[29])), *((uint16_t*)(src + ofst[14])), *((uint16_t*)(src + ofst[15])))), + v_src0, v_src1); +} +inline void v_load_indexed2(uint8_t* src, int *ofst, v_uint16 &v_src0, v_uint16 &v_src1) +{ + v_expand(v_reinterpret_as_u8(v_uint32( + *((uint32_t*)(src + 2 * ofst[ 0])), *((uint32_t*)(src + 2 * ofst[ 1])), *((uint32_t*)(src + 2 * ofst[ 2])), *((uint32_t*)(src + 2 * ofst[ 3])), + *((uint32_t*)(src + 2 * ofst[ 4])), *((uint32_t*)(src + 2 * ofst[ 5])), *((uint32_t*)(src + 2 * ofst[ 6])), *((uint32_t*)(src + 2 * ofst[ 7])), + *((uint32_t*)(src + 2 * ofst[ 8])), *((uint32_t*)(src + 2 * ofst[ 9])), *((uint32_t*)(src + 2 * ofst[10])), *((uint32_t*)(src + 2 * ofst[11])), + *((uint32_t*)(src + 2 * ofst[12])), *((uint32_t*)(src + 2 * ofst[13])), *((uint32_t*)(src + 2 * ofst[14])), *((uint32_t*)(src + 2 * ofst[15])))), + v_src0, v_src1); + v_uint32 v_tmp0, v_tmp1, v_tmp2, v_tmp3; + v_zip(v_reinterpret_as_u32(v_src0), v_reinterpret_as_u32(v_src1), v_tmp2, v_tmp3); + v_zip(v_tmp2, v_tmp3, v_tmp0, v_tmp1); + v_zip(v_tmp0, v_tmp1, v_tmp2, v_tmp3); + v_zip(v_tmp2, v_tmp3, v_tmp0, v_tmp1); + v_zip(v_reinterpret_as_u16(v_tmp0), v_reinterpret_as_u16(v_tmp1), v_src0, v_src1); +} +inline void v_load_indexed4(uint8_t* src, int *ofst, v_uint16 &v_src0, v_uint16 &v_src1) +{ + v_expand(v_reinterpret_as_u8(v_uint64( + *((uint64_t*)(src + 4 * ofst[0])), *((uint64_t*)(src + 4 * ofst[1])), *((uint64_t*)(src + 4 * ofst[2])), *((uint64_t*)(src + 4 * ofst[3])), + *((uint64_t*)(src + 4 * ofst[4])), *((uint64_t*)(src + 4 * ofst[5])), *((uint64_t*)(src + 4 * ofst[6])), *((uint64_t*)(src + 4 * ofst[7])))), + v_src0, v_src1); + v_uint64 v_tmp0, v_tmp1, v_tmp2, v_tmp3; + v_zip(v_reinterpret_as_u64(v_src0), v_reinterpret_as_u64(v_src1), v_tmp2, v_tmp3); + v_zip(v_tmp2, v_tmp3, v_tmp0, v_tmp1); + v_zip(v_tmp0, v_tmp1, v_tmp2, v_tmp3); + v_zip(v_reinterpret_as_u16(v_tmp2), v_reinterpret_as_u16(v_tmp3), v_src0, v_src1); +} +inline void v_load_indexed_deinterleave(uint16_t* src, int *ofst, v_uint32 &v_src0, v_uint32 &v_src1) +{ + v_expand(v_reinterpret_as_u16(v_uint32( + *((uint32_t*)(src + ofst[ 0])), *((uint32_t*)(src + ofst[ 1])), *((uint32_t*)(src + ofst[ 2])), *((uint32_t*)(src + ofst[ 3])), + *((uint32_t*)(src + ofst[ 4])), *((uint32_t*)(src + ofst[ 5])), *((uint32_t*)(src + ofst[ 6])), *((uint32_t*)(src + ofst[ 7])), + *((uint32_t*)(src + ofst[ 8])), *((uint32_t*)(src + ofst[ 9])), *((uint32_t*)(src + ofst[10])), *((uint32_t*)(src + ofst[11])), + *((uint32_t*)(src + ofst[12])), *((uint32_t*)(src + ofst[13])), *((uint32_t*)(src + ofst[14])), *((uint32_t*)(src + ofst[15])))), + v_src0, v_src1); + v_uint32 v_tmp0, v_tmp1; + v_zip(v_src0, v_src1, v_tmp0, v_tmp1); + v_zip(v_tmp0, v_tmp1, v_src0, v_src1); + v_zip(v_src0, v_src1, v_tmp0, v_tmp1); + v_zip(v_tmp0, v_tmp1, v_src0, v_src1); +} +#elif CV_SIMD256 +inline void v_load_indexed1(uint8_t* src, int *ofst, v_uint16 &v_src0, v_uint16 &v_src1) +{ + v_expand(v_reinterpret_as_u8(v_uint16( + *((uint16_t*)(src + ofst[ 0])), *((uint16_t*)(src + ofst[ 1])), *((uint16_t*)(src + ofst[ 2])), *((uint16_t*)(src + ofst[ 3])), + *((uint16_t*)(src + ofst[ 4])), *((uint16_t*)(src + ofst[ 5])), *((uint16_t*)(src + ofst[ 6])), *((uint16_t*)(src + ofst[ 7])), + *((uint16_t*)(src + ofst[ 8])), *((uint16_t*)(src + ofst[ 9])), *((uint16_t*)(src + ofst[10])), *((uint16_t*)(src + ofst[11])), + *((uint16_t*)(src + ofst[12])), *((uint16_t*)(src + ofst[13])), *((uint16_t*)(src + ofst[14])), *((uint16_t*)(src + ofst[15])))), + v_src0, v_src1); +} +inline void v_load_indexed2(uint8_t* src, int *ofst, v_uint16 &v_src0, v_uint16 &v_src1) +{ + v_expand(v_reinterpret_as_u8(v_uint32( + *((uint32_t*)(src + 2 * ofst[0])), *((uint32_t*)(src + 2 * ofst[1])), *((uint32_t*)(src + 2 * ofst[2])), *((uint32_t*)(src + 2 * ofst[3])), + *((uint32_t*)(src + 2 * ofst[4])), *((uint32_t*)(src + 2 * ofst[5])), *((uint32_t*)(src + 2 * ofst[6])), *((uint32_t*)(src + 2 * ofst[7])))), + v_src0, v_src1); + v_uint32 v_tmp0, v_tmp1, v_tmp2, v_tmp3; + v_zip(v_reinterpret_as_u32(v_src0), v_reinterpret_as_u32(v_src1), v_tmp2, v_tmp3); + v_zip(v_tmp2, v_tmp3, v_tmp0, v_tmp1); + v_zip(v_tmp0, v_tmp1, v_tmp2, v_tmp3); + v_zip(v_reinterpret_as_u16(v_tmp2), v_reinterpret_as_u16(v_tmp3), v_src0, v_src1); +} +inline void v_load_indexed4(uint8_t* src, int *ofst, v_uint16 &v_src0, v_uint16 &v_src1) +{ + v_expand(v_reinterpret_as_u8(v_uint64( + *((uint64_t*)(src + 4 * ofst[0])), *((uint64_t*)(src + 4 * ofst[1])), *((uint64_t*)(src + 4 * ofst[2])), *((uint64_t*)(src + 4 * ofst[3])))), + v_src0, v_src1); + v_uint64 v_tmp0, v_tmp1, v_tmp2, v_tmp3; + v_zip(v_reinterpret_as_u64(v_src0), v_reinterpret_as_u64(v_src1), v_tmp2, v_tmp3); + v_zip(v_tmp2, v_tmp3, v_tmp0, v_tmp1); + v_zip(v_reinterpret_as_u16(v_tmp0), v_reinterpret_as_u16(v_tmp1), v_src0, v_src1); +} +inline void v_load_indexed_deinterleave(uint16_t* src, int *ofst, v_uint32 &v_src0, v_uint32 &v_src1) +{ + v_uint32 v_tmp0, v_tmp1; + v_expand(v_reinterpret_as_u16(v_uint32( + *((uint32_t*)(src + ofst[0])), *((uint32_t*)(src + ofst[1])), *((uint32_t*)(src + ofst[2])), *((uint32_t*)(src + ofst[3])), + *((uint32_t*)(src + ofst[4])), *((uint32_t*)(src + ofst[5])), *((uint32_t*)(src + ofst[6])), *((uint32_t*)(src + ofst[7])))), + v_tmp0, v_tmp1); + v_zip(v_tmp0, v_tmp1, v_src0, v_src1); + v_zip(v_src0, v_src1, v_tmp0, v_tmp1); + v_zip(v_tmp0, v_tmp1, v_src0, v_src1); +} +#elif CV_SIMD128 +inline void v_load_indexed1(uint8_t* src, int *ofst, v_uint16 &v_src0, v_uint16 &v_src1) +{ + uint16_t buf[8]; + buf[0] = *((uint16_t*)(src + ofst[0])); + buf[1] = *((uint16_t*)(src + ofst[1])); + buf[2] = *((uint16_t*)(src + ofst[2])); + buf[3] = *((uint16_t*)(src + ofst[3])); + buf[4] = *((uint16_t*)(src + ofst[4])); + buf[5] = *((uint16_t*)(src + ofst[5])); + buf[6] = *((uint16_t*)(src + ofst[6])); + buf[7] = *((uint16_t*)(src + ofst[7])); + v_src0 = vx_load_expand((uint8_t*)buf); + v_src1 = vx_load_expand((uint8_t*)buf + 8); +} +inline void v_load_indexed2(uint8_t* src, int *ofst, v_uint16 &v_src0, v_uint16 &v_src1) +{ + uint32_t buf[4]; + buf[0] = *((uint32_t*)(src + 2 * ofst[0])); + buf[1] = *((uint32_t*)(src + 2 * ofst[1])); + buf[2] = *((uint32_t*)(src + 2 * ofst[2])); + buf[3] = *((uint32_t*)(src + 2 * ofst[3])); + v_uint32 v_tmp0, v_tmp1, v_tmp2, v_tmp3; + v_tmp0 = v_reinterpret_as_u32(vx_load_expand((uint8_t*)buf)); + v_tmp1 = v_reinterpret_as_u32(vx_load_expand((uint8_t*)buf + 8)); + v_zip(v_tmp0, v_tmp1, v_tmp2, v_tmp3); + v_zip(v_tmp2, v_tmp3, v_tmp0, v_tmp1); + v_zip(v_reinterpret_as_u16(v_tmp0), v_reinterpret_as_u16(v_tmp1), v_src0, v_src1); +} +inline void v_load_indexed4(uint8_t* src, int *ofst, v_uint16 &v_src0, v_uint16 &v_src1) +{ + v_uint16 v_tmp0, v_tmp1; + v_src0 = vx_load_expand(src + 4 * ofst[0]); + v_src1 = vx_load_expand(src + 4 * ofst[1]); + v_recombine(v_src0, v_src1, v_tmp0, v_tmp1); + v_zip(v_tmp0, v_tmp1, v_src0, v_src1); +} +inline void v_load_indexed_deinterleave(uint16_t* src, int *ofst, v_uint32 &v_src0, v_uint32 &v_src1) +{ + uint32_t buf[4]; + buf[0] = *((uint32_t*)(src + ofst[0])); + buf[1] = *((uint32_t*)(src + ofst[1])); + buf[2] = *((uint32_t*)(src + ofst[2])); + buf[3] = *((uint32_t*)(src + ofst[3])); + v_src0 = vx_load_expand((uint16_t*)buf); + v_src1 = vx_load_expand((uint16_t*)buf + 4); + v_uint32 v_tmp0, v_tmp1; + v_zip(v_src0, v_src1, v_tmp0, v_tmp1); + v_zip(v_tmp0, v_tmp1, v_src0, v_src1); +} +#endif template <> void hlineResizeCn(uint8_t* src, int, int *ofst, ufixedpoint16* m, ufixedpoint16* dst, int dst_min, int dst_max, int dst_width) { int i = 0; ufixedpoint16 src_0(src[0]); - v_uint16x8 v_src_0 = v_setall_u16(*((uint16_t*)&src_0)); - for (; i < dst_min - 7; i += 8, m += 16, dst += 8) // Points that fall left from src image so became equal to leftmost src point +#if CV_SIMD + const int VECSZ = v_uint16::nlanes; + v_uint16 v_src_0 = vx_setall_u16(*((uint16_t*)&src_0)); + for (; i <= dst_min - VECSZ; i += VECSZ, m += 2*VECSZ, dst += VECSZ) // Points that fall left from src image so became equal to leftmost src point { v_store((uint16_t*)dst, v_src_0); } +#endif for (; i < dst_min; i++, m += 2) { *(dst++) = src_0; } - for (; i < dst_max - 7 && ofst[i + 7] + 15 <= ofst[dst_width - 1]; i += 8, m += 16, dst += 8) +#if CV_SIMD + for (; i <= dst_max - VECSZ; i += VECSZ, m += 2*VECSZ, dst += VECSZ) { - v_uint32x4 v_src01 = v_combine_low(v_reinterpret_as_u32(v_load_expand(src + ofst[i ])), v_reinterpret_as_u32(v_load_expand(src + ofst[i + 1]))); - v_uint32x4 v_src23 = v_combine_low(v_reinterpret_as_u32(v_load_expand(src + ofst[i + 2])), v_reinterpret_as_u32(v_load_expand(src + ofst[i + 3]))); - v_uint32x4 v_src45 = v_combine_low(v_reinterpret_as_u32(v_load_expand(src + ofst[i + 4])), v_reinterpret_as_u32(v_load_expand(src + ofst[i + 5]))); - v_uint32x4 v_src67 = v_combine_low(v_reinterpret_as_u32(v_load_expand(src + ofst[i + 6])), v_reinterpret_as_u32(v_load_expand(src + ofst[i + 7]))); - - v_uint32x4 v_zip02, v_zip13, v_zip46, v_zip57; - v_zip(v_src01, v_src23, v_zip02, v_zip13); - v_zip(v_src45, v_src67, v_zip46, v_zip57); + v_uint16 v_src0, v_src1; + v_load_indexed1(src, ofst + i, v_src0, v_src1); - v_uint32x4 v_src0, v_src1; - v_zip(v_combine_low(v_zip02, v_zip46), v_combine_low(v_zip13, v_zip57), v_src0, v_src1); - - v_int16x8 v_mul0 = v_load((int16_t*)m); - v_int16x8 v_mul1 = v_load((int16_t*)m + 8); - v_uint32x4 v_res0 = v_reinterpret_as_u32(v_dotprod(v_reinterpret_as_s16(v_src0), v_mul0)); - v_uint32x4 v_res1 = v_reinterpret_as_u32(v_dotprod(v_reinterpret_as_s16(v_src1), v_mul1)); + v_int16 v_mul0 = vx_load((int16_t*)m); + v_int16 v_mul1 = vx_load((int16_t*)m + VECSZ); + v_uint32 v_res0 = v_reinterpret_as_u32(v_dotprod(v_reinterpret_as_s16(v_src0), v_mul0)); + v_uint32 v_res1 = v_reinterpret_as_u32(v_dotprod(v_reinterpret_as_s16(v_src1), v_mul1)); v_store((uint16_t*)dst, v_pack(v_res0, v_res1)); } +#endif for (; i < dst_max; i += 1, m += 2) { uint8_t* px = src + ofst[i]; *(dst++) = m[0] * px[0] + m[1] * px[1]; } src_0 = (src + ofst[dst_width - 1])[0]; - v_src_0 = v_setall_u16(*((uint16_t*)&src_0)); - for (; i < dst_width - 7; i += 8, dst += 8) // Points that fall left from src image so became equal to leftmost src point +#if CV_SIMD + v_src_0 = vx_setall_u16(*((uint16_t*)&src_0)); + for (; i <= dst_width - VECSZ; i += VECSZ, dst += VECSZ) // Points that fall left from src image so became equal to leftmost src point { v_store((uint16_t*)dst, v_src_0); } + vx_cleanup(); +#endif for (; i < dst_width; i++) { *(dst++) = src_0; @@ -394,87 +542,109 @@ template <> void hlineResizeCn(uint8_t* src, int, int *ofst, ufixedpoint16* m, ufixedpoint16* dst, int dst_min, int dst_max, int dst_width) { int i = 0; - ufixedpoint16 srccn[8] = { src[0], src[1], src[0], src[1], src[0], src[1], src[0], src[1] }; - v_uint16x8 v_srccn = v_load((uint16_t*)srccn); - for (; i < dst_min - 3; i += 4, m += 8, dst += 8) // Points that fall left from src image so became equal to leftmost src point + union { + uint32_t d; + uint16_t w[2]; + } srccn; + ((ufixedpoint16*)(srccn.w))[0] = src[0]; + ((ufixedpoint16*)(srccn.w))[1] = src[1]; +#if CV_SIMD + const int VECSZ = v_uint16::nlanes; + v_uint16 v_srccn = v_reinterpret_as_u16(vx_setall_u32(srccn.d)); + for (; i <= dst_min - VECSZ/2; i += VECSZ/2, m += VECSZ, dst += VECSZ) // Points that fall left from src image so became equal to leftmost src point { v_store((uint16_t*)dst, v_srccn); } +#endif for (; i < dst_min; i++, m += 2) { - *(dst++) = srccn[0]; - *(dst++) = srccn[1]; + *(dst++) = ((ufixedpoint16*)(srccn.w))[0]; + *(dst++) = ((ufixedpoint16*)(srccn.w))[1]; } - for (; i < dst_max - 3 && ofst[i + 3] + 7 <= ofst[dst_width - 1]; i += 4, m += 8, dst += 8) +#if CV_SIMD + for (; i <= dst_max - VECSZ/2; i += VECSZ/2, m += VECSZ, dst += VECSZ) { - v_uint32x4 v_src0 = v_combine_low(v_reinterpret_as_u32(v_load_expand(src + 2 * ofst[i ])), v_reinterpret_as_u32(v_load_expand(src + 2 * ofst[i + 1]))); - v_uint32x4 v_src1 = v_combine_low(v_reinterpret_as_u32(v_load_expand(src + 2 * ofst[i + 2])), v_reinterpret_as_u32(v_load_expand(src + 2 * ofst[i + 3]))); - - v_uint32x4 v_zip0, v_zip1; - v_zip(v_src0, v_src1, v_zip0, v_zip1); - v_zip(v_zip0, v_zip1, v_src0, v_src1); + v_uint16 v_src0, v_src1; + v_load_indexed2(src, ofst + i, v_src0, v_src1); - v_int16x8 v_src0123, v_src4567; - v_zip(v_reinterpret_as_s16(v_src0), v_reinterpret_as_s16(v_src1), v_src0123, v_src4567); - - v_uint32x4 v_mul = v_load((uint32_t*)m);//AaBbCcDd + v_uint32 v_mul = vx_load((uint32_t*)m);//AaBbCcDd + v_uint32 v_zip0, v_zip1; v_zip(v_mul, v_mul, v_zip0, v_zip1);//AaAaBbBb CcCcDdDd - v_uint32x4 v_res0 = v_reinterpret_as_u32(v_dotprod(v_src0123, v_reinterpret_as_s16(v_zip0))); - v_uint32x4 v_res1 = v_reinterpret_as_u32(v_dotprod(v_src4567, v_reinterpret_as_s16(v_zip1))); + v_uint32 v_res0 = v_reinterpret_as_u32(v_dotprod(v_reinterpret_as_s16(v_src0), v_reinterpret_as_s16(v_zip0))); + v_uint32 v_res1 = v_reinterpret_as_u32(v_dotprod(v_reinterpret_as_s16(v_src1), v_reinterpret_as_s16(v_zip1))); v_store((uint16_t*)dst, v_pack(v_res0, v_res1));//AB1AB2CD1CD2 } +#endif for (; i < dst_max; i += 1, m += 2) { uint8_t* px = src + 2 * ofst[i]; *(dst++) = m[0] * px[0] + m[1] * px[2]; *(dst++) = m[0] * px[1] + m[1] * px[3]; } - srccn[0] = (src + 2 * ofst[dst_width - 1])[0]; srccn[1] = (src + 2 * ofst[dst_width - 1])[1]; srccn[2] = (src + 2 * ofst[dst_width - 1])[0]; srccn[3] = (src + 2 * ofst[dst_width - 1])[1]; - srccn[4] = (src + 2 * ofst[dst_width - 1])[0]; srccn[5] = (src + 2 * ofst[dst_width - 1])[1]; srccn[6] = (src + 2 * ofst[dst_width - 1])[0]; srccn[7] = (src + 2 * ofst[dst_width - 1])[1]; - v_srccn = v_load((uint16_t*)srccn); - for (; i < dst_width - 3; i += 4, dst += 8) // Points that fall left from src image so became equal to leftmost src point + ((ufixedpoint16*)(srccn.w))[0] = (src + 2 * ofst[dst_width - 1])[0]; ((ufixedpoint16*)(srccn.w))[1] = (src + 2 * ofst[dst_width - 1])[1]; +#if CV_SIMD + v_srccn = v_reinterpret_as_u16(vx_setall_u32(srccn.d)); + for (; i <= dst_width - VECSZ/2; i += VECSZ/2, dst += VECSZ) // Points that fall left from src image so became equal to leftmost src point { v_store((uint16_t*)dst, v_srccn); } + vx_cleanup(); +#endif for (; i < dst_width; i++) { - *(dst++) = srccn[0]; - *(dst++) = srccn[1]; + *(dst++) = ((ufixedpoint16*)(srccn.w))[0]; + *(dst++) = ((ufixedpoint16*)(srccn.w))[1]; } } template <> void hlineResizeCn(uint8_t* src, int, int *ofst, ufixedpoint16* m, ufixedpoint16* dst, int dst_min, int dst_max, int dst_width) { int i = 0; - ufixedpoint16 srccn[8] = { src[0], src[1], src[2], src[3], src[0], src[1], src[2], src[3] }; - v_uint16x8 v_srccn = v_load((uint16_t*)srccn); - for (; i < dst_min - 1; i += 2, m += 4, dst += 8) // Points that fall left from src image so became equal to leftmost src point + union { + uint64_t q; + uint16_t w[4]; + } srccn; + ((ufixedpoint16*)(srccn.w))[0] = src[0]; + ((ufixedpoint16*)(srccn.w))[1] = src[1]; + ((ufixedpoint16*)(srccn.w))[2] = src[2]; + ((ufixedpoint16*)(srccn.w))[3] = src[3]; +#if CV_SIMD + const int VECSZ = v_uint16::nlanes; + v_uint16 v_srccn = v_reinterpret_as_u16(vx_setall_u64(srccn.q)); + for (; i <= dst_min - VECSZ/4; i += VECSZ/4, m += VECSZ/2, dst += VECSZ) // Points that fall left from src image so became equal to leftmost src point { v_store((uint16_t*)dst, v_srccn); } +#endif if (i < dst_min) // Points that fall left from src image so became equal to leftmost src point { - *(dst++) = srccn[0]; - *(dst++) = srccn[1]; - *(dst++) = srccn[2]; - *(dst++) = srccn[3]; + *(dst++) = ((ufixedpoint16*)(srccn.w))[0]; + *(dst++) = ((ufixedpoint16*)(srccn.w))[1]; + *(dst++) = ((ufixedpoint16*)(srccn.w))[2]; + *(dst++) = ((ufixedpoint16*)(srccn.w))[3]; i++; m += 2; } - for (; i < dst_max - 1 && ofst[i + 1] + 3 <= ofst[dst_width - 1]; i += 2, m += 4, dst += 8) - { - v_int16x8 v_src01 = v_reinterpret_as_s16(v_load_expand(src + 4 * ofst[i ])); - v_int16x8 v_src23 = v_reinterpret_as_s16(v_load_expand(src + 4 * ofst[i + 1])); - - v_int16x8 v_tmp0, v_tmp1; - v_recombine(v_src01, v_src23, v_tmp0, v_tmp1); - v_zip(v_tmp0, v_tmp1, v_src01, v_src23); - - v_int16x8 v_mul01 = v_reinterpret_as_s16(v_setall_u32(((uint32_t*)m)[0]));//AaAaAaAa - v_int16x8 v_mul23 = v_reinterpret_as_s16(v_setall_u32(((uint32_t*)m)[1]));//BbBbBbBb - v_uint32x4 v_res0 = v_reinterpret_as_u32(v_dotprod(v_src01, v_mul01)); - v_uint32x4 v_res1 = v_reinterpret_as_u32(v_dotprod(v_src23, v_mul23)); - v_store((uint16_t*)dst, v_pack(v_res0, v_res1));//AB1AB2CD1CD2 +#if CV_SIMD + for (; i <= dst_max - VECSZ/2; i += VECSZ/2, m += VECSZ, dst += 2*VECSZ) + { + v_uint16 v_src0, v_src1, v_src2, v_src3; + v_load_indexed4(src, ofst + i, v_src0, v_src1); + v_load_indexed4(src, ofst + i + VECSZ/4, v_src2, v_src3); + + v_uint32 v_mul0, v_mul1, v_mul2, v_mul3, v_tmp; + v_mul0 = vx_load((uint32_t*)m);//AaBbCcDd + v_zip(v_mul0, v_mul0, v_mul3, v_tmp );//AaAaBbBb CcCcDdDd + v_zip(v_mul3, v_mul3, v_mul0, v_mul1);//AaAaAaAa BbBbBbBb + v_zip(v_tmp , v_tmp , v_mul2, v_mul3);//CcCcCcCc DdDdDdDd + + v_uint32 v_res0 = v_reinterpret_as_u32(v_dotprod(v_reinterpret_as_s16(v_src0), v_reinterpret_as_s16(v_mul0))); + v_uint32 v_res1 = v_reinterpret_as_u32(v_dotprod(v_reinterpret_as_s16(v_src1), v_reinterpret_as_s16(v_mul1))); + v_uint32 v_res2 = v_reinterpret_as_u32(v_dotprod(v_reinterpret_as_s16(v_src2), v_reinterpret_as_s16(v_mul2))); + v_uint32 v_res3 = v_reinterpret_as_u32(v_dotprod(v_reinterpret_as_s16(v_src3), v_reinterpret_as_s16(v_mul3))); + v_store((uint16_t*)dst , v_pack(v_res0, v_res1)); + v_store((uint16_t*)dst + VECSZ, v_pack(v_res2, v_res3)); } +#endif for (; i < dst_max; i += 1, m += 2) { uint8_t* px = src + 4 * ofst[i]; @@ -483,19 +653,22 @@ void hlineResizeCn(uint8_t* src, int, int *o *(dst++) = m[0] * px[2] + m[1] * px[6]; *(dst++) = m[0] * px[3] + m[1] * px[7]; } - srccn[0] = (src + 4 * ofst[dst_width - 1])[0]; srccn[1] = (src + 4 * ofst[dst_width - 1])[1]; srccn[2] = (src + 4 * ofst[dst_width - 1])[2]; srccn[3] = (src + 4 * ofst[dst_width - 1])[3]; - srccn[4] = (src + 4 * ofst[dst_width - 1])[0]; srccn[5] = (src + 4 * ofst[dst_width - 1])[1]; srccn[6] = (src + 4 * ofst[dst_width - 1])[2]; srccn[7] = (src + 4 * ofst[dst_width - 1])[3]; - v_srccn = v_load((uint16_t*)srccn); - for (; i < dst_width - 1; i += 2, dst += 8) // Points that fall right from src image so became equal to rightmost src point + ((ufixedpoint16*)(srccn.w))[0] = (src + 4 * ofst[dst_width - 1])[0]; ((ufixedpoint16*)(srccn.w))[1] = (src + 4 * ofst[dst_width - 1])[1]; + ((ufixedpoint16*)(srccn.w))[2] = (src + 4 * ofst[dst_width - 1])[2]; ((ufixedpoint16*)(srccn.w))[3] = (src + 4 * ofst[dst_width - 1])[3]; +#if CV_SIMD + v_srccn = v_reinterpret_as_u16(vx_setall_u64(srccn.q)); + for (; i <= dst_width - VECSZ/4; i += VECSZ/4, dst += VECSZ) // Points that fall right from src image so became equal to rightmost src point { v_store((uint16_t*)dst, v_srccn); } + vx_cleanup(); +#endif if (i < dst_width) { - *(dst++) = srccn[0]; - *(dst++) = srccn[1]; - *(dst++) = srccn[2]; - *(dst++) = srccn[3]; + *(dst++) = ((ufixedpoint16*)(srccn.w))[0]; + *(dst++) = ((ufixedpoint16*)(srccn.w))[1]; + *(dst++) = ((ufixedpoint16*)(srccn.w))[2]; + *(dst++) = ((ufixedpoint16*)(srccn.w))[3]; } } template <> @@ -503,40 +676,42 @@ void hlineResizeCn(uint16_t* src, int, int { int i = 0; ufixedpoint32 src_0(src[0]); - v_uint32x4 v_src_0 = v_setall_u32(*((uint32_t*)&src_0)); - for (; i < dst_min - 3; i += 4, m += 8, dst += 4) // Points that fall left from src image so became equal to leftmost src point +#if CV_SIMD + const int VECSZ = v_uint32::nlanes; + v_uint32 v_src_0 = vx_setall_u32(*((uint32_t*)&src_0)); + for (; i <= dst_min - VECSZ; i += VECSZ, m += 2*VECSZ, dst += VECSZ) // Points that fall left from src image so became equal to leftmost src point { v_store((uint32_t*)dst, v_src_0); } +#endif for (; i < dst_min; i++, m += 2) { *(dst++) = src_0; } - for (; i < dst_max - 3 && ofst[i + 3] + 8 <= ofst[dst_width - 1]; i += 4, m += 8, dst += 4) - { - v_uint32x4 v_src0 = v_combine_low(v_load_expand(src + ofst[i]), v_load_expand(src + ofst[i + 1])); - v_uint32x4 v_mul0 = v_load((uint32_t*)m); - v_uint32x4 v_src1 = v_combine_low(v_load_expand(src + ofst[i + 2]), v_load_expand(src + ofst[i + 3])); - v_uint32x4 v_mul1 = v_load((uint32_t*)m + 4); - v_uint32x4 v_res0 = v_src0 * v_mul0;//a1a2b1b2 - v_uint32x4 v_res1 = v_src1 * v_mul1;//c1c2d1d2 - v_uint32x4 v_tmp0, v_tmp1; - v_recombine(v_res0, v_res1, v_tmp0, v_tmp1);//a1a2c1c2 b1b2d1d2 - v_zip(v_tmp0, v_tmp1, v_res0, v_res1);//a1b1a2b2 c1d1c2d2 - v_recombine(v_res0, v_res1, v_tmp0, v_tmp1);//a1b1c1d1 a2b2c2d2 - v_store((uint32_t*)dst, v_tmp0 + v_tmp1);//abcd +#if CV_SIMD + for (; i <= dst_max - VECSZ; i += VECSZ, m += 2*VECSZ, dst += VECSZ) + { + v_uint32 v_src0, v_src1; + v_load_indexed_deinterleave(src, ofst + i, v_src0, v_src1); + v_uint32 v_mul0, v_mul1; + v_load_deinterleave((uint32_t*)m, v_mul0, v_mul1); + v_store((uint32_t*)dst, v_src0 * v_mul0 + v_src1 * v_mul1);//abcd } +#endif for (; i < dst_max; i += 1, m += 2) { uint16_t* px = src + ofst[i]; *(dst++) = m[0] * px[0] + m[1] * px[1]; } src_0 = (src + ofst[dst_width - 1])[0]; - v_src_0 = v_setall_u32(*((uint32_t*)&src_0)); - for (; i < dst_width - 3; i += 4, dst += 4) +#if CV_SIMD + v_src_0 = vx_setall_u32(*((uint32_t*)&src_0)); + for (; i <= dst_width - VECSZ; i += VECSZ, dst += VECSZ) { v_store((uint32_t*)dst, v_src_0); } + vx_cleanup(); +#endif for (; i < dst_width; i++) { *(dst++) = src_0; @@ -552,18 +727,22 @@ void vlineSet(FT* src, ET* dst, int dst_width) template <> void vlineSet(ufixedpoint16* src, uint8_t* dst, int dst_width) { - static const v_uint16x8 v_fixedRound = v_setall_u16((uint16_t)((1U << 8) >> 1)); int i = 0; - for (; i < dst_width - 15; i += 16, src += 16, dst += 16) +#if CV_SIMD + const int VECSZ = v_uint8::nlanes; + static const v_uint16 v_fixedRound = vx_setall_u16((uint16_t)((1U << 8) >> 1)); + for (; i <= dst_width - VECSZ; i += VECSZ, src += VECSZ, dst += VECSZ) { - v_uint16x8 v_src0 = v_load((uint16_t*)src); - v_uint16x8 v_src1 = v_load((uint16_t*)src + 8); + v_uint16 v_src0 = vx_load((uint16_t*)src); + v_uint16 v_src1 = vx_load((uint16_t*)src + VECSZ/2); - v_uint16x8 v_res0 = (v_src0 + v_fixedRound) >> 8; - v_uint16x8 v_res1 = (v_src1 + v_fixedRound) >> 8; + v_uint16 v_res0 = (v_src0 + v_fixedRound) >> 8; + v_uint16 v_res1 = (v_src1 + v_fixedRound) >> 8; v_store(dst, v_pack(v_res0, v_res1)); } + vx_cleanup(); +#endif for (; i < dst_width; i++) *(dst++) = *(src++); } @@ -582,36 +761,40 @@ void vlineResize(FT* src, size_t src_step, FT* m, ET* dst, int dst_width) template <> void vlineResize(ufixedpoint16* src, size_t src_step, ufixedpoint16* m, uint8_t* dst, int dst_width) { - static const v_int32x4 v_fixedRound = v_setall_s32((int32_t)((1 << 16) >> 1)); - static const v_int16x8 v_128 = v_reinterpret_as_s16(v_setall_u16((uint16_t)1<<15)); - static const v_int8x16 v_128_16 = v_reinterpret_as_s8 (v_setall_u8 ((uint8_t) 1<<7)); - int i = 0; ufixedpoint16* src1 = src + src_step; - v_int16x8 v_mul = v_reinterpret_as_s16(v_setall_u32(((uint32_t*)m)[0])); - for (; i < dst_width - 15; i += 16, src += 16, src1 += 16, dst += 16) - { - v_int16x8 v_src00 = v_load((int16_t*)src); - v_int16x8 v_src10 = v_load((int16_t*)src1); - v_int16x8 v_tmp0, v_tmp1; +#if CV_SIMD + const int VECSZ = v_uint8::nlanes; + static const v_int32 v_fixedRound = vx_setall_s32((int32_t)((1 << 16) >> 1)); + static const v_int16 v_128 = v_reinterpret_as_s16(vx_setall_u16((uint16_t)1<<15)); + static const v_int8 v_128_16 = v_reinterpret_as_s8 (vx_setall_u8 ((uint8_t) 1<<7)); + + v_int16 v_mul = v_reinterpret_as_s16(vx_setall_u32(((uint32_t*)m)[0])); + for (; i <= dst_width - VECSZ; i += VECSZ, src += VECSZ, src1 += VECSZ, dst += VECSZ) + { + v_int16 v_src00 = vx_load((int16_t*)src); + v_int16 v_src10 = vx_load((int16_t*)src1); + v_int16 v_tmp0, v_tmp1; v_zip(v_add_wrap(v_src00,v_128), v_add_wrap(v_src10,v_128), v_tmp0, v_tmp1); - v_int32x4 v_res0 = v_dotprod(v_tmp0, v_mul); - v_int32x4 v_res1 = v_dotprod(v_tmp1, v_mul); + v_int32 v_res0 = v_dotprod(v_tmp0, v_mul); + v_int32 v_res1 = v_dotprod(v_tmp1, v_mul); - v_int16x8 v_src01 = v_load((int16_t*)src + 8); - v_int16x8 v_src11 = v_load((int16_t*)src1 + 8); + v_int16 v_src01 = vx_load((int16_t*)src + VECSZ/2); + v_int16 v_src11 = vx_load((int16_t*)src1 + VECSZ/2); v_zip(v_add_wrap(v_src01,v_128), v_add_wrap(v_src11,v_128), v_tmp0, v_tmp1); - v_int32x4 v_res2 = v_dotprod(v_tmp0, v_mul); - v_int32x4 v_res3 = v_dotprod(v_tmp1, v_mul); + v_int32 v_res2 = v_dotprod(v_tmp0, v_mul); + v_int32 v_res3 = v_dotprod(v_tmp1, v_mul); - v_int8x16 v_res = v_pack(v_pack((v_res0 + v_fixedRound) >> 16, - (v_res1 + v_fixedRound) >> 16), - v_pack((v_res2 + v_fixedRound) >> 16, - (v_res3 + v_fixedRound) >> 16)); + v_int8 v_res = v_pack(v_pack((v_res0 + v_fixedRound) >> 16, + (v_res1 + v_fixedRound) >> 16), + v_pack((v_res2 + v_fixedRound) >> 16, + (v_res3 + v_fixedRound) >> 16)); v_store(dst, v_reinterpret_as_u8(v_sub_wrap(v_res, v_128_16))); } + vx_cleanup(); +#endif for (; i < dst_width; i++) { *(dst++) = (uint8_t)(*(src++) * m[0] + *(src1++) * m[1]); diff --git a/modules/imgproc/src/segmentation.cpp b/modules/imgproc/src/segmentation.cpp index b803770f12a8..b08d1b3ac0e5 100644 --- a/modules/imgproc/src/segmentation.cpp +++ b/modules/imgproc/src/segmentation.cpp @@ -407,27 +407,25 @@ void cv::pyrMeanShiftFiltering( InputArray _src, OutputArray _dst, cv::Size size = src.size(); const uchar* sptr = src.ptr(); int sstep = (int)src.step; - uchar* mask = 0; - int mstep = 0; uchar* dptr; int dstep; float sp = (float)(sp0 / (1 << level)); sp = MAX( sp, 1 ); + cv::Mat m; if( level < max_level ) { cv::Size size1 = dst_pyramid[level+1].size(); - cv::Mat m( size.height, size.width, CV_8UC1, mask0.ptr() ); + m = cv::Mat(size.height, size.width, CV_8UC1, mask0.ptr()); dstep = (int)dst_pyramid[level+1].step; dptr = dst_pyramid[level+1].ptr() + dstep + cn; - mstep = (int)m.step; - mask = m.ptr() + mstep; //cvResize( dst_pyramid[level+1], dst_pyramid[level], CV_INTER_CUBIC ); cv::pyrUp( dst_pyramid[level+1], dst_pyramid[level], dst_pyramid[level].size() ); m.setTo(cv::Scalar::all(0)); - for( i = 1; i < size1.height-1; i++, dptr += dstep - (size1.width-2)*3, mask += mstep*2 ) + for( i = 1; i < size1.height-1; i++, dptr += dstep - (size1.width-2)*3) { + uchar* mask = m.ptr(1 + i * 2); for( j = 1; j < size1.width-1; j++, dptr += cn ) { int c0 = dptr[0], c1 = dptr[1], c2 = dptr[2]; @@ -437,16 +435,16 @@ void cv::pyrMeanShiftFiltering( InputArray _src, OutputArray _dst, } cv::dilate( m, m, cv::Mat() ); - mask = m.ptr(); } dptr = dst_pyramid[level].ptr(); dstep = (int)dst_pyramid[level].step; for( i = 0; i < size.height; i++, sptr += sstep - size.width*3, - dptr += dstep - size.width*3, - mask += mstep ) + dptr += dstep - size.width*3 + ) { + uchar* mask = m.empty() ? NULL : m.ptr(i); for( j = 0; j < size.width; j++, sptr += 3, dptr += 3 ) { int x0 = j, y0 = i, x1, y1, iter; diff --git a/modules/imgproc/src/smooth.cpp b/modules/imgproc/src/smooth.cpp index f4077521e157..fa4ee326533e 100644 --- a/modules/imgproc/src/smooth.cpp +++ b/modules/imgproc/src/smooth.cpp @@ -1820,22 +1820,13 @@ template <> void hlineSmooth1N(const uint8_t* src, int cn, const ufixedpoint16* m, int, ufixedpoint16* dst, int len, int) { int lencn = len*cn; - v_uint16x8 v_mul = v_setall_u16(*((uint16_t*)m)); int i = 0; - for (; i <= lencn - 16; i += 16) - { - v_uint8x16 v_src = v_load(src + i); - v_uint16x8 v_tmp0, v_tmp1; - v_expand(v_src, v_tmp0, v_tmp1); - v_store((uint16_t*)dst + i, v_mul*v_tmp0); - v_store((uint16_t*)dst + i + 8, v_mul*v_tmp1); - } - if (i <= lencn - 8) - { - v_uint16x8 v_src = v_load_expand(src + i); - v_store((uint16_t*)dst + i, v_mul*v_src); - i += 8; - } +#if CV_SIMD + const int VECSZ = v_uint16::nlanes; + v_uint16 v_mul = vx_setall_u16(*((uint16_t*)m)); + for (; i <= lencn - VECSZ; i += VECSZ) + v_store((uint16_t*)dst + i, v_mul*vx_load_expand(src + i)); +#endif for (; i < lencn; i++) dst[i] = m[0] * src[i]; } @@ -1850,20 +1841,11 @@ void hlineSmooth1N1(const uint8_t* src, int cn, const uf { int lencn = len*cn; int i = 0; - for (; i <= lencn - 16; i += 16) - { - v_uint8x16 v_src = v_load(src + i); - v_uint16x8 v_tmp0, v_tmp1; - v_expand(v_src, v_tmp0, v_tmp1); - v_store((uint16_t*)dst + i, v_shl<8>(v_tmp0)); - v_store((uint16_t*)dst + i + 8, v_shl<8>(v_tmp1)); - } - if (i <= lencn - 8) - { - v_uint16x8 v_src = v_load_expand(src + i); - v_store((uint16_t*)dst + i, v_shl<8>(v_src)); - i += 8; - } +#if CV_SIMD + const int VECSZ = v_uint16::nlanes; + for (; i <= lencn - VECSZ; i += VECSZ) + v_store((uint16_t*)dst + i, v_shl<8>(vx_load_expand(src + i))); +#endif for (; i < lencn; i++) dst[i] = src[i]; } @@ -1926,18 +1908,15 @@ void hlineSmooth3N(const uint8_t* src, int cn, const ufi src += cn; dst += cn; int i = cn, lencn = (len - 1)*cn; - v_uint16x8 v_mul0 = v_setall_u16(*((uint16_t*)m)); - v_uint16x8 v_mul1 = v_setall_u16(*((uint16_t*)(m + 1))); - v_uint16x8 v_mul2 = v_setall_u16(*((uint16_t*)(m + 2))); - for (; i <= lencn - 16; i += 16, src += 16, dst += 16) - { - v_uint16x8 v_src00, v_src01, v_src10, v_src11, v_src20, v_src21; - v_expand(v_load(src - cn), v_src00, v_src01); - v_expand(v_load(src), v_src10, v_src11); - v_expand(v_load(src + cn), v_src20, v_src21); - v_store((uint16_t*)dst, v_src00 * v_mul0 + v_src10 * v_mul1 + v_src20 * v_mul2); - v_store((uint16_t*)dst + 8, v_src01 * v_mul0 + v_src11 * v_mul1 + v_src21 * v_mul2); - } +#if CV_SIMD + const uint16_t* _m = (const uint16_t*)m; + const int VECSZ = v_uint16::nlanes; + v_uint16 v_mul0 = vx_setall_u16(_m[0]); + v_uint16 v_mul1 = vx_setall_u16(_m[1]); + v_uint16 v_mul2 = vx_setall_u16(_m[2]); + for (; i <= lencn - VECSZ; i += VECSZ, src += VECSZ, dst += VECSZ) + v_store((uint16_t*)dst, vx_load_expand(src - cn) * v_mul0 + vx_load_expand(src) * v_mul1 + vx_load_expand(src + cn) * v_mul2); +#endif for (; i < lencn; i++, src++, dst++) *dst = m[0] * src[-cn] + m[1] * src[0] + m[2] * src[cn]; @@ -2017,15 +1996,11 @@ void hlineSmooth3N121(const uint8_t* src, int cn, const src += cn; dst += cn; int i = cn, lencn = (len - 1)*cn; - for (; i <= lencn - 16; i += 16, src += 16, dst += 16) - { - v_uint16x8 v_src00, v_src01, v_src10, v_src11, v_src20, v_src21; - v_expand(v_load(src - cn), v_src00, v_src01); - v_expand(v_load(src), v_src10, v_src11); - v_expand(v_load(src + cn), v_src20, v_src21); - v_store((uint16_t*)dst, (v_src00 + v_src20 + (v_src10 << 1)) << 6); - v_store((uint16_t*)dst + 8, (v_src01 + v_src21 + (v_src11 << 1)) << 6); - } +#if CV_SIMD + const int VECSZ = v_uint16::nlanes; + for (; i <= lencn - VECSZ; i += VECSZ, src += VECSZ, dst += VECSZ) + v_store((uint16_t*)dst, (vx_load_expand(src - cn) + vx_load_expand(src + cn) + (vx_load_expand(src) << 1)) << 6); +#endif for (; i < lencn; i++, src++, dst++) *((uint16_t*)dst) = (uint16_t(src[-cn]) + uint16_t(src[cn]) + (uint16_t(src[0]) << 1)) << 6; @@ -2108,17 +2083,14 @@ void hlineSmooth3Naba(const uint8_t* src, int cn, const src += cn; dst += cn; int i = cn, lencn = (len - 1)*cn; - v_uint16x8 v_mul0 = v_setall_u16(*((uint16_t*)m)); - v_uint16x8 v_mul1 = v_setall_u16(*((uint16_t*)m+1)); - for (; i <= lencn - 16; i += 16, src += 16, dst += 16) - { - v_uint16x8 v_src00, v_src01, v_src10, v_src11, v_src20, v_src21; - v_expand(v_load(src - cn), v_src00, v_src01); - v_expand(v_load(src), v_src10, v_src11); - v_expand(v_load(src + cn), v_src20, v_src21); - v_store((uint16_t*)dst, (v_src00 + v_src20) * v_mul0 + v_src10 * v_mul1); - v_store((uint16_t*)dst + 8, (v_src01 + v_src21) * v_mul0 + v_src11 * v_mul1); - } +#if CV_SIMD + const uint16_t* _m = (const uint16_t*)m; + const int VECSZ = v_uint16::nlanes; + v_uint16 v_mul0 = vx_setall_u16(_m[0]); + v_uint16 v_mul1 = vx_setall_u16(_m[1]); + for (; i <= lencn - VECSZ; i += VECSZ, src += VECSZ, dst += VECSZ) + v_store((uint16_t*)dst, (vx_load_expand(src - cn) + vx_load_expand(src + cn)) * v_mul0 + vx_load_expand(src) * v_mul1); +#endif for (; i < lencn; i++, src++, dst++) *((uint16_t*)dst) = ((uint16_t*)m)[1] * src[0] + ((uint16_t*)m)[0] * ((uint16_t)(src[-cn]) + (uint16_t)(src[cn])); @@ -2304,22 +2276,17 @@ void hlineSmooth5N(const uint8_t* src, int cn, const ufi src += 2 * cn; dst += 2 * cn; int i = 2*cn, lencn = (len - 2)*cn; - v_uint16x8 v_mul0 = v_setall_u16(*((uint16_t*)m)); - v_uint16x8 v_mul1 = v_setall_u16(*((uint16_t*)(m + 1))); - v_uint16x8 v_mul2 = v_setall_u16(*((uint16_t*)(m + 2))); - v_uint16x8 v_mul3 = v_setall_u16(*((uint16_t*)(m + 3))); - v_uint16x8 v_mul4 = v_setall_u16(*((uint16_t*)(m + 4))); - for (; i <= lencn - 16; i += 16, src += 16, dst += 16) - { - v_uint16x8 v_src00, v_src01, v_src10, v_src11, v_src20, v_src21, v_src30, v_src31, v_src40, v_src41; - v_expand(v_load(src - 2*cn), v_src00, v_src01); - v_expand(v_load(src - cn), v_src10, v_src11); - v_expand(v_load(src), v_src20, v_src21); - v_expand(v_load(src + cn), v_src30, v_src31); - v_expand(v_load(src + 2*cn), v_src40, v_src41); - v_store((uint16_t*)dst, v_src00 * v_mul0 + v_src10 * v_mul1 + v_src20 * v_mul2 + v_src30 * v_mul3 + v_src40 * v_mul4); - v_store((uint16_t*)dst + 8, v_src01 * v_mul0 + v_src11 * v_mul1 + v_src21 * v_mul2 + v_src31 * v_mul3 + v_src41 * v_mul4); - } +#if CV_SIMD + const uint16_t* _m = (const uint16_t*)m; + const int VECSZ = v_uint16::nlanes; + v_uint16 v_mul0 = vx_setall_u16(_m[0]); + v_uint16 v_mul1 = vx_setall_u16(_m[1]); + v_uint16 v_mul2 = vx_setall_u16(_m[2]); + v_uint16 v_mul3 = vx_setall_u16(_m[3]); + v_uint16 v_mul4 = vx_setall_u16(_m[4]); + for (; i <= lencn - VECSZ; i += VECSZ, src += VECSZ, dst += VECSZ) + v_store((uint16_t*)dst, vx_load_expand(src - 2 * cn) * v_mul0 + vx_load_expand(src - cn) * v_mul1 + vx_load_expand(src) * v_mul2 + vx_load_expand(src + cn) * v_mul3 + vx_load_expand(src + 2 * cn) * v_mul4); +#endif for (; i < lencn; i++, src++, dst++) *dst = m[0] * src[-2*cn] + m[1] * src[-cn] + m[2] * src[0] + m[3] * src[cn] + m[4] * src[2*cn]; @@ -2517,18 +2484,12 @@ void hlineSmooth5N14641(const uint8_t* src, int cn, cons src += 2 * cn; dst += 2 * cn; int i = 2 * cn, lencn = (len - 2)*cn; - v_uint16x8 v_6 = v_setall_u16(6); - for (; i <= lencn - 16; i += 16, src += 16, dst += 16) - { - v_uint16x8 v_src00, v_src01, v_src10, v_src11, v_src20, v_src21, v_src30, v_src31, v_src40, v_src41; - v_expand(v_load(src - 2*cn), v_src00, v_src01); - v_expand(v_load(src - cn), v_src10, v_src11); - v_expand(v_load(src), v_src20, v_src21); - v_expand(v_load(src + cn), v_src30, v_src31); - v_expand(v_load(src + 2*cn), v_src40, v_src41); - v_store((uint16_t*)dst, (v_src20 * v_6 + ((v_src10 + v_src30) << 2) + v_src00 + v_src40) << 4); - v_store((uint16_t*)dst + 8, (v_src21 * v_6 + ((v_src11 + v_src31) << 2) + v_src01 + v_src41) << 4); - } +#if CV_SIMD + const int VECSZ = v_uint16::nlanes; + v_uint16 v_6 = vx_setall_u16(6); + for (; i <= lencn - VECSZ; i += VECSZ, src += VECSZ, dst += VECSZ) + v_store((uint16_t*)dst, (vx_load_expand(src) * v_6 + ((vx_load_expand(src - cn) + vx_load_expand(src + cn)) << 2) + vx_load_expand(src - 2 * cn) + vx_load_expand(src + 2 * cn)) << 4); +#endif for (; i < lencn; i++, src++, dst++) *((uint16_t*)dst) = (uint16_t(src[0]) * 6 + ((uint16_t(src[-cn]) + uint16_t(src[cn])) << 2) + uint16_t(src[-2 * cn]) + uint16_t(src[2 * cn])) << 4; @@ -2721,20 +2682,15 @@ void hlineSmooth5Nabcba(const uint8_t* src, int cn, cons src += 2 * cn; dst += 2 * cn; int i = 2 * cn, lencn = (len - 2)*cn; - v_uint16x8 v_mul0 = v_setall_u16(*((uint16_t*)m)); - v_uint16x8 v_mul1 = v_setall_u16(*((uint16_t*)(m + 1))); - v_uint16x8 v_mul2 = v_setall_u16(*((uint16_t*)(m + 2))); - for (; i <= lencn - 16; i += 16, src += 16, dst += 16) - { - v_uint16x8 v_src00, v_src01, v_src10, v_src11, v_src20, v_src21, v_src30, v_src31, v_src40, v_src41; - v_expand(v_load(src - 2 * cn), v_src00, v_src01); - v_expand(v_load(src - cn), v_src10, v_src11); - v_expand(v_load(src), v_src20, v_src21); - v_expand(v_load(src + cn), v_src30, v_src31); - v_expand(v_load(src + 2 * cn), v_src40, v_src41); - v_store((uint16_t*)dst, (v_src00 + v_src40) * v_mul0 + (v_src10 + v_src30)* v_mul1 + v_src20 * v_mul2); - v_store((uint16_t*)dst + 8, (v_src01 + v_src41) * v_mul0 + (v_src11 + v_src31) * v_mul1 + v_src21 * v_mul2); - } +#if CV_SIMD + const uint16_t* _m = (const uint16_t*)m; + const int VECSZ = v_uint16::nlanes; + v_uint16 v_mul0 = vx_setall_u16(_m[0]); + v_uint16 v_mul1 = vx_setall_u16(_m[1]); + v_uint16 v_mul2 = vx_setall_u16(_m[2]); + for (; i <= lencn - VECSZ; i += VECSZ, src += VECSZ, dst += VECSZ) + v_store((uint16_t*)dst, (vx_load_expand(src - 2 * cn) + vx_load_expand(src + 2 * cn)) * v_mul0 + (vx_load_expand(src - cn) + vx_load_expand(src + cn))* v_mul1 + vx_load_expand(src) * v_mul2); +#endif for (; i < lencn; i++, src++, dst++) *((uint16_t*)dst) = ((uint16_t*)m)[0] * ((uint16_t)(src[-2 * cn]) + (uint16_t)(src[2 * cn])) + ((uint16_t*)m)[1] * ((uint16_t)(src[-cn]) + (uint16_t)(src[cn])) + ((uint16_t*)m)[2] * src[0]; @@ -2844,23 +2800,16 @@ void hlineSmooth(const uint8_t* src, int cn, const ufixe } i *= cn; int lencn = (len - post_shift + 1)*cn; - for (; i <= lencn - 16; i+=16, src+=16, dst+=16) +#if CV_SIMD + const int VECSZ = v_uint16::nlanes; + for (; i <= lencn - VECSZ; i+=VECSZ, src+=VECSZ, dst+=VECSZ) { - v_uint16x8 v_src0, v_src1; - v_uint16x8 v_mul = v_setall_u16(*((uint16_t*)m)); - v_expand(v_load(src), v_src0, v_src1); - v_uint16x8 v_res0 = v_src0 * v_mul; - v_uint16x8 v_res1 = v_src1 * v_mul; + v_uint16 v_res0 = vx_load_expand(src) * vx_setall_u16(*((uint16_t*)m)); for (int j = 1; j < n; j++) - { - v_mul = v_setall_u16(*((uint16_t*)(m + j))); - v_expand(v_load(src + j * cn), v_src0, v_src1); - v_res0 += v_src0 * v_mul; - v_res1 += v_src1 * v_mul; - } + v_res0 += vx_load_expand(src + j * cn) * vx_setall_u16(*((uint16_t*)(m + j))); v_store((uint16_t*)dst, v_res0); - v_store((uint16_t*)dst+8, v_res1); } +#endif for (; i < lencn; i++, src++, dst++) { *dst = m[0] * src[0]; @@ -2970,26 +2919,16 @@ void hlineSmoothONa_yzy_a(const uint8_t* src, int cn, co } i *= cn; int lencn = (len - post_shift + 1)*cn; - for (; i <= lencn - 16; i += 16, src += 16, dst += 16) +#if CV_SIMD + const int VECSZ = v_uint16::nlanes; + for (; i <= lencn - VECSZ; i += VECSZ, src += VECSZ, dst += VECSZ) { - v_uint16x8 v_src00, v_src01, v_srcN00, v_srcN01; - - v_uint16x8 v_mul = v_setall_u16(*((uint16_t*)(m + pre_shift))); - v_expand(v_load(src + pre_shift * cn), v_src00, v_src01); - v_uint16x8 v_res0 = v_src00 * v_mul; - v_uint16x8 v_res1 = v_src01 * v_mul; + v_uint16 v_res0 = vx_load_expand(src + pre_shift * cn) * vx_setall_u16(*((uint16_t*)(m + pre_shift))); for (int j = 0; j < pre_shift; j ++) - { - v_mul = v_setall_u16(*((uint16_t*)(m + j))); - v_expand(v_load(src + j * cn), v_src00, v_src01); - v_expand(v_load(src + (n - 1 - j)*cn), v_srcN00, v_srcN01); - v_res0 += (v_src00 + v_srcN00) * v_mul; - v_res1 += (v_src01 + v_srcN01) * v_mul; - } - + v_res0 += (vx_load_expand(src + j * cn) + vx_load_expand(src + (n - 1 - j)*cn)) * vx_setall_u16(*((uint16_t*)(m + j))); v_store((uint16_t*)dst, v_res0); - v_store((uint16_t*)dst + 8, v_res1); } +#endif for (; i < lencn; i++, src++, dst++) { *dst = m[pre_shift] * src[pre_shift*cn]; @@ -3025,28 +2964,13 @@ template <> void vlineSmooth1N(const ufixedpoint16* const * src, const ufixedpoint16* m, int, uint8_t* dst, int len) { const ufixedpoint16* src0 = src[0]; - v_uint16x8 v_mul = v_setall_u16(*((uint16_t*)m)); -#if CV_SSE2 - v_uint16x8 v_1 = v_setall_u16(1); - v_mul += v_mul; -#endif int i = 0; - for (; i <= len - 16; i += 16) - { - v_uint16x8 v_src0 = v_load((uint16_t*)src0 + i); - v_uint16x8 v_src1 = v_load((uint16_t*)src0 + i + 8); - v_uint8x16 v_res; -#if CV_SSE2 - v_res.val = _mm_packus_epi16(_mm_srli_epi16(_mm_add_epi16(v_1.val, _mm_mulhi_epu16(v_src0.val, v_mul.val)),1), - _mm_srli_epi16(_mm_add_epi16(v_1.val, _mm_mulhi_epu16(v_src1.val, v_mul.val)),1)); -#else - v_uint32x4 v_res0, v_res1, v_res2, v_res3; - v_mul_expand(v_src0, v_mul, v_res0, v_res1); - v_mul_expand(v_src1, v_mul, v_res2, v_res3); - v_res = v_pack(v_rshr_pack<16>(v_res0, v_res1), v_rshr_pack<16>(v_res2, v_res3)); +#if CV_SIMD + const int VECSZ = v_uint16::nlanes; + v_uint16 v_mul = vx_setall_u16(*((uint16_t*)m)<<1); + for (; i <= len - VECSZ; i += VECSZ) + v_rshr_pack_store<1>(dst + i, v_mul_hi(vx_load((uint16_t*)src0 + i), v_mul)); #endif - v_store(dst + i, v_res); - } for (; i < len; i++) dst[i] = m[0] * src0[i]; } @@ -3062,8 +2986,11 @@ void vlineSmooth1N1(const ufixedpoint16* const * src, co { const ufixedpoint16* src0 = src[0]; int i = 0; - for (; i <= len - 8; i += 8) - v_rshr_pack_store<8>(dst + i, v_load((uint16_t*)(src0 + i))); +#if CV_SIMD + const int VECSZ = v_uint16::nlanes; + for (; i <= len - VECSZ; i += VECSZ) + v_rshr_pack_store<8>(dst + i, vx_load((uint16_t*)(src0 + i))); +#endif for (; i < len; i++) dst[i] = src0[i]; } @@ -3077,46 +3004,51 @@ template <> void vlineSmooth3N(const ufixedpoint16* const * src, const ufixedpoint16* m, int, uint8_t* dst, int len) { int i = 0; - static const v_int16x8 v_128 = v_reinterpret_as_s16(v_setall_u16((uint16_t)1 << 15)); - v_int32x4 v_128_4 = v_setall_s32(128 << 16); - if (len > 7) +#if CV_SIMD + static const v_int16 v_128 = v_reinterpret_as_s16(vx_setall_u16((uint16_t)1 << 15)); + v_int32 v_128_4 = vx_setall_s32(128 << 16); + const int VECSZ = v_uint16::nlanes; + if (len >= VECSZ) { ufixedpoint32 val[] = { (m[0] + m[1] + m[2]) * ufixedpoint16((uint8_t)128) }; - v_128_4 = v_setall_s32(*((int32_t*)val)); - } - v_int16x8 v_mul01 = v_reinterpret_as_s16(v_setall_u32(*((uint32_t*)m))); - v_int16x8 v_mul2 = v_reinterpret_as_s16(v_setall_u16(*((uint16_t*)(m + 2)))); - for (; i <= len - 32; i += 32) - { - v_int16x8 v_src00, v_src10, v_src01, v_src11, v_src02, v_src12, v_src03, v_src13; - v_int16x8 v_tmp0, v_tmp1; - - v_src00 = v_load((int16_t*)(src[0]) + i); - v_src01 = v_load((int16_t*)(src[0]) + i + 8); - v_src02 = v_load((int16_t*)(src[0]) + i + 16); - v_src03 = v_load((int16_t*)(src[0]) + i + 24); - v_src10 = v_load((int16_t*)(src[1]) + i); - v_src11 = v_load((int16_t*)(src[1]) + i + 8); - v_src12 = v_load((int16_t*)(src[1]) + i + 16); - v_src13 = v_load((int16_t*)(src[1]) + i + 24); + v_128_4 = vx_setall_s32(*((int32_t*)val)); + } + v_int16 v_mul01 = v_reinterpret_as_s16(vx_setall_u32(*((uint32_t*)m))); + v_int16 v_mul2 = v_reinterpret_as_s16(vx_setall_u16(*((uint16_t*)(m + 2)))); + for (; i <= len - 4*VECSZ; i += 4*VECSZ) + { + v_int16 v_src00, v_src10, v_src01, v_src11, v_src02, v_src12, v_src03, v_src13; + v_int16 v_tmp0, v_tmp1; + + const int16_t* src0 = (const int16_t*)src[0] + i; + const int16_t* src1 = (const int16_t*)src[1] + i; + v_src00 = vx_load(src0); + v_src01 = vx_load(src0 + VECSZ); + v_src02 = vx_load(src0 + 2*VECSZ); + v_src03 = vx_load(src0 + 3*VECSZ); + v_src10 = vx_load(src1); + v_src11 = vx_load(src1 + VECSZ); + v_src12 = vx_load(src1 + 2*VECSZ); + v_src13 = vx_load(src1 + 3*VECSZ); v_zip(v_add_wrap(v_src00, v_128), v_add_wrap(v_src10, v_128), v_tmp0, v_tmp1); - v_int32x4 v_res0 = v_dotprod(v_tmp0, v_mul01); - v_int32x4 v_res1 = v_dotprod(v_tmp1, v_mul01); + v_int32 v_res0 = v_dotprod(v_tmp0, v_mul01); + v_int32 v_res1 = v_dotprod(v_tmp1, v_mul01); v_zip(v_add_wrap(v_src01, v_128), v_add_wrap(v_src11, v_128), v_tmp0, v_tmp1); - v_int32x4 v_res2 = v_dotprod(v_tmp0, v_mul01); - v_int32x4 v_res3 = v_dotprod(v_tmp1, v_mul01); + v_int32 v_res2 = v_dotprod(v_tmp0, v_mul01); + v_int32 v_res3 = v_dotprod(v_tmp1, v_mul01); v_zip(v_add_wrap(v_src02, v_128), v_add_wrap(v_src12, v_128), v_tmp0, v_tmp1); - v_int32x4 v_res4 = v_dotprod(v_tmp0, v_mul01); - v_int32x4 v_res5 = v_dotprod(v_tmp1, v_mul01); + v_int32 v_res4 = v_dotprod(v_tmp0, v_mul01); + v_int32 v_res5 = v_dotprod(v_tmp1, v_mul01); v_zip(v_add_wrap(v_src03, v_128), v_add_wrap(v_src13, v_128), v_tmp0, v_tmp1); - v_int32x4 v_res6 = v_dotprod(v_tmp0, v_mul01); - v_int32x4 v_res7 = v_dotprod(v_tmp1, v_mul01); - - v_int32x4 v_resj0, v_resj1; - v_src00 = v_load((int16_t*)(src[2]) + i); - v_src01 = v_load((int16_t*)(src[2]) + i + 8); - v_src02 = v_load((int16_t*)(src[2]) + i + 16); - v_src03 = v_load((int16_t*)(src[2]) + i + 24); + v_int32 v_res6 = v_dotprod(v_tmp0, v_mul01); + v_int32 v_res7 = v_dotprod(v_tmp1, v_mul01); + + v_int32 v_resj0, v_resj1; + const int16_t* src2 = (const int16_t*)src[2] + i; + v_src00 = vx_load(src2); + v_src01 = vx_load(src2 + VECSZ); + v_src02 = vx_load(src2 + 2*VECSZ); + v_src03 = vx_load(src2 + 3*VECSZ); v_mul_expand(v_add_wrap(v_src00, v_128), v_mul2, v_resj0, v_resj1); v_res0 += v_resj0; v_res1 += v_resj1; @@ -3139,11 +3071,12 @@ void vlineSmooth3N(const ufixedpoint16* const * src, con v_res6 += v_128_4; v_res7 += v_128_4; - v_store(dst + i , v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res0, v_res1)), - v_reinterpret_as_u16(v_rshr_pack<16>(v_res2, v_res3)))); - v_store(dst + i + 16, v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res4, v_res5)), - v_reinterpret_as_u16(v_rshr_pack<16>(v_res6, v_res7)))); + v_store(dst + i , v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res0, v_res1)), + v_reinterpret_as_u16(v_rshr_pack<16>(v_res2, v_res3)))); + v_store(dst + i + 2*VECSZ, v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res4, v_res5)), + v_reinterpret_as_u16(v_rshr_pack<16>(v_res6, v_res7)))); } +#endif for (; i < len; i++) dst[i] = m[0] * src[0][i] + m[1] * src[1][i] + m[2] * src[2][i]; } @@ -3157,18 +3090,21 @@ template <> void vlineSmooth3N121(const ufixedpoint16* const * src, const ufixedpoint16*, int, uint8_t* dst, int len) { int i = 0; - for (; i <= len - 16; i += 16) - { - v_uint32x4 v_src00, v_src01, v_src02, v_src03, v_src10, v_src11, v_src12, v_src13, v_src20, v_src21, v_src22, v_src23; - v_expand(v_load((uint16_t*)(src[0]) + i), v_src00, v_src01); - v_expand(v_load((uint16_t*)(src[0]) + i + 8), v_src02, v_src03); - v_expand(v_load((uint16_t*)(src[1]) + i), v_src10, v_src11); - v_expand(v_load((uint16_t*)(src[1]) + i + 8), v_src12, v_src13); - v_expand(v_load((uint16_t*)(src[2]) + i), v_src20, v_src21); - v_expand(v_load((uint16_t*)(src[2]) + i + 8), v_src22, v_src23); +#if CV_SIMD + const int VECSZ = v_uint16::nlanes; + for (; i <= len - 2*VECSZ; i += 2*VECSZ) + { + v_uint32 v_src00, v_src01, v_src02, v_src03, v_src10, v_src11, v_src12, v_src13, v_src20, v_src21, v_src22, v_src23; + v_expand(vx_load((uint16_t*)(src[0]) + i), v_src00, v_src01); + v_expand(vx_load((uint16_t*)(src[0]) + i + VECSZ), v_src02, v_src03); + v_expand(vx_load((uint16_t*)(src[1]) + i), v_src10, v_src11); + v_expand(vx_load((uint16_t*)(src[1]) + i + VECSZ), v_src12, v_src13); + v_expand(vx_load((uint16_t*)(src[2]) + i), v_src20, v_src21); + v_expand(vx_load((uint16_t*)(src[2]) + i + VECSZ), v_src22, v_src23); v_store(dst + i, v_pack(v_rshr_pack<10>(v_src00 + v_src20 + (v_src10 + v_src10), v_src01 + v_src21 + (v_src11 + v_src11)), v_rshr_pack<10>(v_src02 + v_src22 + (v_src12 + v_src12), v_src03 + v_src23 + (v_src13 + v_src13)))); } +#endif for (; i < len; i++) dst[i] = (((uint32_t)(((uint16_t*)(src[0]))[i]) + (uint32_t)(((uint16_t*)(src[2]))[i]) + ((uint32_t)(((uint16_t*)(src[1]))[i]) << 1)) + (1 << 9)) >> 10; } @@ -3182,95 +3118,102 @@ template <> void vlineSmooth5N(const ufixedpoint16* const * src, const ufixedpoint16* m, int, uint8_t* dst, int len) { int i = 0; - static const v_int16x8 v_128 = v_reinterpret_as_s16(v_setall_u16((uint16_t)1 << 15)); - v_int32x4 v_128_4 = v_setall_s32(128 << 16); - if (len > 7) +#if CV_SIMD + const int VECSZ = v_uint16::nlanes; + if (len >= 4 * VECSZ) { ufixedpoint32 val[] = { (m[0] + m[1] + m[2] + m[3] + m[4]) * ufixedpoint16((uint8_t)128) }; - v_128_4 = v_setall_s32(*((int32_t*)val)); - } - v_int16x8 v_mul01 = v_reinterpret_as_s16(v_setall_u32(*((uint32_t*)m))); - v_int16x8 v_mul23 = v_reinterpret_as_s16(v_setall_u32(*((uint32_t*)(m + 2)))); - v_int16x8 v_mul4 = v_reinterpret_as_s16(v_setall_u16(*((uint16_t*)(m + 4)))); - for (; i <= len - 32; i += 32) - { - v_int16x8 v_src00, v_src10, v_src01, v_src11, v_src02, v_src12, v_src03, v_src13; - v_int16x8 v_tmp0, v_tmp1; - - v_src00 = v_load((int16_t*)(src[0]) + i); - v_src01 = v_load((int16_t*)(src[0]) + i + 8); - v_src02 = v_load((int16_t*)(src[0]) + i + 16); - v_src03 = v_load((int16_t*)(src[0]) + i + 24); - v_src10 = v_load((int16_t*)(src[1]) + i); - v_src11 = v_load((int16_t*)(src[1]) + i + 8); - v_src12 = v_load((int16_t*)(src[1]) + i + 16); - v_src13 = v_load((int16_t*)(src[1]) + i + 24); - v_zip(v_add_wrap(v_src00, v_128), v_add_wrap(v_src10, v_128), v_tmp0, v_tmp1); - v_int32x4 v_res0 = v_dotprod(v_tmp0, v_mul01); - v_int32x4 v_res1 = v_dotprod(v_tmp1, v_mul01); - v_zip(v_add_wrap(v_src01, v_128), v_add_wrap(v_src11, v_128), v_tmp0, v_tmp1); - v_int32x4 v_res2 = v_dotprod(v_tmp0, v_mul01); - v_int32x4 v_res3 = v_dotprod(v_tmp1, v_mul01); - v_zip(v_add_wrap(v_src02, v_128), v_add_wrap(v_src12, v_128), v_tmp0, v_tmp1); - v_int32x4 v_res4 = v_dotprod(v_tmp0, v_mul01); - v_int32x4 v_res5 = v_dotprod(v_tmp1, v_mul01); - v_zip(v_add_wrap(v_src03, v_128), v_add_wrap(v_src13, v_128), v_tmp0, v_tmp1); - v_int32x4 v_res6 = v_dotprod(v_tmp0, v_mul01); - v_int32x4 v_res7 = v_dotprod(v_tmp1, v_mul01); - - v_src00 = v_load((int16_t*)(src[2]) + i); - v_src01 = v_load((int16_t*)(src[2]) + i + 8); - v_src02 = v_load((int16_t*)(src[2]) + i + 16); - v_src03 = v_load((int16_t*)(src[2]) + i + 24); - v_src10 = v_load((int16_t*)(src[3]) + i); - v_src11 = v_load((int16_t*)(src[3]) + i + 8); - v_src12 = v_load((int16_t*)(src[3]) + i + 16); - v_src13 = v_load((int16_t*)(src[3]) + i + 24); - v_zip(v_add_wrap(v_src00, v_128), v_add_wrap(v_src10, v_128), v_tmp0, v_tmp1); - v_res0 += v_dotprod(v_tmp0, v_mul23); - v_res1 += v_dotprod(v_tmp1, v_mul23); - v_zip(v_add_wrap(v_src01, v_128), v_add_wrap(v_src11, v_128), v_tmp0, v_tmp1); - v_res2 += v_dotprod(v_tmp0, v_mul23); - v_res3 += v_dotprod(v_tmp1, v_mul23); - v_zip(v_add_wrap(v_src02, v_128), v_add_wrap(v_src12, v_128), v_tmp0, v_tmp1); - v_res4 += v_dotprod(v_tmp0, v_mul23); - v_res5 += v_dotprod(v_tmp1, v_mul23); - v_zip(v_add_wrap(v_src03, v_128), v_add_wrap(v_src13, v_128), v_tmp0, v_tmp1); - v_res6 += v_dotprod(v_tmp0, v_mul23); - v_res7 += v_dotprod(v_tmp1, v_mul23); - - v_int32x4 v_resj0, v_resj1; - v_src00 = v_load((int16_t*)(src[4]) + i); - v_src01 = v_load((int16_t*)(src[4]) + i + 8); - v_src02 = v_load((int16_t*)(src[4]) + i + 16); - v_src03 = v_load((int16_t*)(src[4]) + i + 24); - v_mul_expand(v_add_wrap(v_src00, v_128), v_mul4, v_resj0, v_resj1); - v_res0 += v_resj0; - v_res1 += v_resj1; - v_mul_expand(v_add_wrap(v_src01, v_128), v_mul4, v_resj0, v_resj1); - v_res2 += v_resj0; - v_res3 += v_resj1; - v_mul_expand(v_add_wrap(v_src02, v_128), v_mul4, v_resj0, v_resj1); - v_res4 += v_resj0; - v_res5 += v_resj1; - v_mul_expand(v_add_wrap(v_src03, v_128), v_mul4, v_resj0, v_resj1); - v_res6 += v_resj0; - v_res7 += v_resj1; + v_int32 v_128_4 = vx_setall_s32(*((int32_t*)val)); + static const v_int16 v_128 = v_reinterpret_as_s16(vx_setall_u16((uint16_t)1 << 15)); + v_int16 v_mul01 = v_reinterpret_as_s16(vx_setall_u32(*((uint32_t*)m))); + v_int16 v_mul23 = v_reinterpret_as_s16(vx_setall_u32(*((uint32_t*)(m + 2)))); + v_int16 v_mul4 = v_reinterpret_as_s16(vx_setall_u16(*((uint16_t*)(m + 4)))); + for (; i <= len - 4*VECSZ; i += 4*VECSZ) + { + v_int16 v_src00, v_src10, v_src01, v_src11, v_src02, v_src12, v_src03, v_src13; + v_int16 v_tmp0, v_tmp1; + + const int16_t* src0 = (const int16_t*)src[0] + i; + const int16_t* src1 = (const int16_t*)src[1] + i; + v_src00 = vx_load(src0); + v_src01 = vx_load(src0 + VECSZ); + v_src02 = vx_load(src0 + 2*VECSZ); + v_src03 = vx_load(src0 + 3*VECSZ); + v_src10 = vx_load(src1); + v_src11 = vx_load(src1 + VECSZ); + v_src12 = vx_load(src1 + 2*VECSZ); + v_src13 = vx_load(src1 + 3*VECSZ); + v_zip(v_add_wrap(v_src00, v_128), v_add_wrap(v_src10, v_128), v_tmp0, v_tmp1); + v_int32 v_res0 = v_dotprod(v_tmp0, v_mul01); + v_int32 v_res1 = v_dotprod(v_tmp1, v_mul01); + v_zip(v_add_wrap(v_src01, v_128), v_add_wrap(v_src11, v_128), v_tmp0, v_tmp1); + v_int32 v_res2 = v_dotprod(v_tmp0, v_mul01); + v_int32 v_res3 = v_dotprod(v_tmp1, v_mul01); + v_zip(v_add_wrap(v_src02, v_128), v_add_wrap(v_src12, v_128), v_tmp0, v_tmp1); + v_int32 v_res4 = v_dotprod(v_tmp0, v_mul01); + v_int32 v_res5 = v_dotprod(v_tmp1, v_mul01); + v_zip(v_add_wrap(v_src03, v_128), v_add_wrap(v_src13, v_128), v_tmp0, v_tmp1); + v_int32 v_res6 = v_dotprod(v_tmp0, v_mul01); + v_int32 v_res7 = v_dotprod(v_tmp1, v_mul01); + + const int16_t* src2 = (const int16_t*)src[2] + i; + const int16_t* src3 = (const int16_t*)src[3] + i; + v_src00 = vx_load(src2); + v_src01 = vx_load(src2 + VECSZ); + v_src02 = vx_load(src2 + 2*VECSZ); + v_src03 = vx_load(src2 + 3*VECSZ); + v_src10 = vx_load(src3); + v_src11 = vx_load(src3 + VECSZ); + v_src12 = vx_load(src3 + 2*VECSZ); + v_src13 = vx_load(src3 + 3*VECSZ); + v_zip(v_add_wrap(v_src00, v_128), v_add_wrap(v_src10, v_128), v_tmp0, v_tmp1); + v_res0 += v_dotprod(v_tmp0, v_mul23); + v_res1 += v_dotprod(v_tmp1, v_mul23); + v_zip(v_add_wrap(v_src01, v_128), v_add_wrap(v_src11, v_128), v_tmp0, v_tmp1); + v_res2 += v_dotprod(v_tmp0, v_mul23); + v_res3 += v_dotprod(v_tmp1, v_mul23); + v_zip(v_add_wrap(v_src02, v_128), v_add_wrap(v_src12, v_128), v_tmp0, v_tmp1); + v_res4 += v_dotprod(v_tmp0, v_mul23); + v_res5 += v_dotprod(v_tmp1, v_mul23); + v_zip(v_add_wrap(v_src03, v_128), v_add_wrap(v_src13, v_128), v_tmp0, v_tmp1); + v_res6 += v_dotprod(v_tmp0, v_mul23); + v_res7 += v_dotprod(v_tmp1, v_mul23); + + v_int32 v_resj0, v_resj1; + const int16_t* src4 = (const int16_t*)src[4] + i; + v_src00 = vx_load(src4); + v_src01 = vx_load(src4 + VECSZ); + v_src02 = vx_load(src4 + 2*VECSZ); + v_src03 = vx_load(src4 + 3*VECSZ); + v_mul_expand(v_add_wrap(v_src00, v_128), v_mul4, v_resj0, v_resj1); + v_res0 += v_resj0; + v_res1 += v_resj1; + v_mul_expand(v_add_wrap(v_src01, v_128), v_mul4, v_resj0, v_resj1); + v_res2 += v_resj0; + v_res3 += v_resj1; + v_mul_expand(v_add_wrap(v_src02, v_128), v_mul4, v_resj0, v_resj1); + v_res4 += v_resj0; + v_res5 += v_resj1; + v_mul_expand(v_add_wrap(v_src03, v_128), v_mul4, v_resj0, v_resj1); + v_res6 += v_resj0; + v_res7 += v_resj1; - v_res0 += v_128_4; - v_res1 += v_128_4; - v_res2 += v_128_4; - v_res3 += v_128_4; - v_res4 += v_128_4; - v_res5 += v_128_4; - v_res6 += v_128_4; - v_res7 += v_128_4; + v_res0 += v_128_4; + v_res1 += v_128_4; + v_res2 += v_128_4; + v_res3 += v_128_4; + v_res4 += v_128_4; + v_res5 += v_128_4; + v_res6 += v_128_4; + v_res7 += v_128_4; - v_store(dst + i , v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res0, v_res1)), - v_reinterpret_as_u16(v_rshr_pack<16>(v_res2, v_res3)))); - v_store(dst + i + 16, v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res4, v_res5)), - v_reinterpret_as_u16(v_rshr_pack<16>(v_res6, v_res7)))); + v_store(dst + i , v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res0, v_res1)), + v_reinterpret_as_u16(v_rshr_pack<16>(v_res2, v_res3)))); + v_store(dst + i + 2*VECSZ, v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res4, v_res5)), + v_reinterpret_as_u16(v_rshr_pack<16>(v_res6, v_res7)))); + } } +#endif for (; i < len; i++) dst[i] = m[0] * src[0][i] + m[1] * src[1][i] + m[2] * src[2][i] + m[3] * src[3][i] + m[4] * src[4][i]; } @@ -3284,28 +3227,31 @@ template <> void vlineSmooth5N14641(const ufixedpoint16* const * src, const ufixedpoint16*, int, uint8_t* dst, int len) { int i = 0; - v_uint32x4 v_6 = v_setall_u32(6); - for (; i <= len - 16; i += 16) - { - v_uint32x4 v_src00, v_src10, v_src20, v_src30, v_src40; - v_uint32x4 v_src01, v_src11, v_src21, v_src31, v_src41; - v_uint32x4 v_src02, v_src12, v_src22, v_src32, v_src42; - v_uint32x4 v_src03, v_src13, v_src23, v_src33, v_src43; - v_expand(v_load((uint16_t*)(src[0]) + i), v_src00, v_src01); - v_expand(v_load((uint16_t*)(src[0]) + i + 8), v_src02, v_src03); - v_expand(v_load((uint16_t*)(src[1]) + i), v_src10, v_src11); - v_expand(v_load((uint16_t*)(src[1]) + i + 8), v_src12, v_src13); - v_expand(v_load((uint16_t*)(src[2]) + i), v_src20, v_src21); - v_expand(v_load((uint16_t*)(src[2]) + i + 8), v_src22, v_src23); - v_expand(v_load((uint16_t*)(src[3]) + i), v_src30, v_src31); - v_expand(v_load((uint16_t*)(src[3]) + i + 8), v_src32, v_src33); - v_expand(v_load((uint16_t*)(src[4]) + i), v_src40, v_src41); - v_expand(v_load((uint16_t*)(src[4]) + i + 8), v_src42, v_src43); +#if CV_SIMD + v_uint32 v_6 = vx_setall_u32(6); + const int VECSZ = v_uint16::nlanes; + for (; i <= len - 2*VECSZ; i += 2*VECSZ) + { + v_uint32 v_src00, v_src10, v_src20, v_src30, v_src40; + v_uint32 v_src01, v_src11, v_src21, v_src31, v_src41; + v_uint32 v_src02, v_src12, v_src22, v_src32, v_src42; + v_uint32 v_src03, v_src13, v_src23, v_src33, v_src43; + v_expand(vx_load((uint16_t*)(src[0]) + i), v_src00, v_src01); + v_expand(vx_load((uint16_t*)(src[0]) + i + VECSZ), v_src02, v_src03); + v_expand(vx_load((uint16_t*)(src[1]) + i), v_src10, v_src11); + v_expand(vx_load((uint16_t*)(src[1]) + i + VECSZ), v_src12, v_src13); + v_expand(vx_load((uint16_t*)(src[2]) + i), v_src20, v_src21); + v_expand(vx_load((uint16_t*)(src[2]) + i + VECSZ), v_src22, v_src23); + v_expand(vx_load((uint16_t*)(src[3]) + i), v_src30, v_src31); + v_expand(vx_load((uint16_t*)(src[3]) + i + VECSZ), v_src32, v_src33); + v_expand(vx_load((uint16_t*)(src[4]) + i), v_src40, v_src41); + v_expand(vx_load((uint16_t*)(src[4]) + i + VECSZ), v_src42, v_src43); v_store(dst + i, v_pack(v_rshr_pack<12>(v_src20*v_6 + ((v_src10 + v_src30) << 2) + v_src00 + v_src40, v_src21*v_6 + ((v_src11 + v_src31) << 2) + v_src01 + v_src41), v_rshr_pack<12>(v_src22*v_6 + ((v_src12 + v_src32) << 2) + v_src02 + v_src42, v_src23*v_6 + ((v_src13 + v_src33) << 2) + v_src03 + v_src43))); } +#endif for (; i < len; i++) dst[i] = ((uint32_t)(((uint16_t*)(src[2]))[i]) * 6 + (((uint32_t)(((uint16_t*)(src[1]))[i]) + (uint32_t)(((uint16_t*)(src[3]))[i])) << 2) + @@ -3326,57 +3272,63 @@ template <> void vlineSmooth(const ufixedpoint16* const * src, const ufixedpoint16* m, int n, uint8_t* dst, int len) { int i = 0; - static const v_int16x8 v_128 = v_reinterpret_as_s16(v_setall_u16((uint16_t)1 << 15)); - v_int32x4 v_128_4 = v_setall_s32(128 << 16); - if (len > 7) +#if CV_SIMD + static const v_int16 v_128 = v_reinterpret_as_s16(vx_setall_u16((uint16_t)1 << 15)); + v_int32 v_128_4 = vx_setall_s32(128 << 16); + const int VECSZ = v_uint16::nlanes; + if (len >= VECSZ) { ufixedpoint16 msum = m[0] + m[1]; for (int j = 2; j < n; j++) msum = msum + m[j]; ufixedpoint32 val[] = { msum * ufixedpoint16((uint8_t)128) }; - v_128_4 = v_setall_s32(*((int32_t*)val)); + v_128_4 = vx_setall_s32(*((int32_t*)val)); } - for (; i <= len - 32; i += 32) + for (; i <= len - 4*VECSZ; i += 4*VECSZ) { - v_int16x8 v_src00, v_src10, v_src01, v_src11, v_src02, v_src12, v_src03, v_src13; - v_int16x8 v_tmp0, v_tmp1; + v_int16 v_src00, v_src10, v_src01, v_src11, v_src02, v_src12, v_src03, v_src13; + v_int16 v_tmp0, v_tmp1; - v_int16x8 v_mul = v_reinterpret_as_s16(v_setall_u32(*((uint32_t*)m))); + v_int16 v_mul = v_reinterpret_as_s16(vx_setall_u32(*((uint32_t*)m))); - v_src00 = v_load((int16_t*)(src[0]) + i); - v_src01 = v_load((int16_t*)(src[0]) + i + 8); - v_src02 = v_load((int16_t*)(src[0]) + i + 16); - v_src03 = v_load((int16_t*)(src[0]) + i + 24); - v_src10 = v_load((int16_t*)(src[1]) + i); - v_src11 = v_load((int16_t*)(src[1]) + i + 8); - v_src12 = v_load((int16_t*)(src[1]) + i + 16); - v_src13 = v_load((int16_t*)(src[1]) + i + 24); + const int16_t* src0 = (const int16_t*)src[0] + i; + const int16_t* src1 = (const int16_t*)src[1] + i; + v_src00 = vx_load(src0); + v_src01 = vx_load(src0 + VECSZ); + v_src02 = vx_load(src0 + 2*VECSZ); + v_src03 = vx_load(src0 + 3*VECSZ); + v_src10 = vx_load(src1); + v_src11 = vx_load(src1 + VECSZ); + v_src12 = vx_load(src1 + 2*VECSZ); + v_src13 = vx_load(src1 + 3*VECSZ); v_zip(v_add_wrap(v_src00, v_128), v_add_wrap(v_src10, v_128), v_tmp0, v_tmp1); - v_int32x4 v_res0 = v_dotprod(v_tmp0, v_mul); - v_int32x4 v_res1 = v_dotprod(v_tmp1, v_mul); + v_int32 v_res0 = v_dotprod(v_tmp0, v_mul); + v_int32 v_res1 = v_dotprod(v_tmp1, v_mul); v_zip(v_add_wrap(v_src01, v_128), v_add_wrap(v_src11, v_128), v_tmp0, v_tmp1); - v_int32x4 v_res2 = v_dotprod(v_tmp0, v_mul); - v_int32x4 v_res3 = v_dotprod(v_tmp1, v_mul); + v_int32 v_res2 = v_dotprod(v_tmp0, v_mul); + v_int32 v_res3 = v_dotprod(v_tmp1, v_mul); v_zip(v_add_wrap(v_src02, v_128), v_add_wrap(v_src12, v_128), v_tmp0, v_tmp1); - v_int32x4 v_res4 = v_dotprod(v_tmp0, v_mul); - v_int32x4 v_res5 = v_dotprod(v_tmp1, v_mul); + v_int32 v_res4 = v_dotprod(v_tmp0, v_mul); + v_int32 v_res5 = v_dotprod(v_tmp1, v_mul); v_zip(v_add_wrap(v_src03, v_128), v_add_wrap(v_src13, v_128), v_tmp0, v_tmp1); - v_int32x4 v_res6 = v_dotprod(v_tmp0, v_mul); - v_int32x4 v_res7 = v_dotprod(v_tmp1, v_mul); + v_int32 v_res6 = v_dotprod(v_tmp0, v_mul); + v_int32 v_res7 = v_dotprod(v_tmp1, v_mul); int j = 2; for (; j < n - 1; j+=2) { - v_mul = v_reinterpret_as_s16(v_setall_u32(*((uint32_t*)(m+j)))); - - v_src00 = v_load((int16_t*)(src[j]) + i); - v_src01 = v_load((int16_t*)(src[j]) + i + 8); - v_src02 = v_load((int16_t*)(src[j]) + i + 16); - v_src03 = v_load((int16_t*)(src[j]) + i + 24); - v_src10 = v_load((int16_t*)(src[j+1]) + i); - v_src11 = v_load((int16_t*)(src[j+1]) + i + 8); - v_src12 = v_load((int16_t*)(src[j+1]) + i + 16); - v_src13 = v_load((int16_t*)(src[j+1]) + i + 24); + v_mul = v_reinterpret_as_s16(vx_setall_u32(*((uint32_t*)(m+j)))); + + const int16_t* srcj0 = (const int16_t*)src[j] + i; + const int16_t* srcj1 = (const int16_t*)src[j + 1] + i; + v_src00 = vx_load(srcj0); + v_src01 = vx_load(srcj0 + VECSZ); + v_src02 = vx_load(srcj0 + 2*VECSZ); + v_src03 = vx_load(srcj0 + 3*VECSZ); + v_src10 = vx_load(srcj1); + v_src11 = vx_load(srcj1 + VECSZ); + v_src12 = vx_load(srcj1 + 2*VECSZ); + v_src13 = vx_load(srcj1 + 3*VECSZ); v_zip(v_add_wrap(v_src00, v_128), v_add_wrap(v_src10, v_128), v_tmp0, v_tmp1); v_res0 += v_dotprod(v_tmp0, v_mul); v_res1 += v_dotprod(v_tmp1, v_mul); @@ -3392,12 +3344,13 @@ void vlineSmooth(const ufixedpoint16* const * src, const } if(j < n) { - v_int32x4 v_resj0, v_resj1; - v_mul = v_reinterpret_as_s16(v_setall_u16(*((uint16_t*)(m + j)))); - v_src00 = v_load((int16_t*)(src[j]) + i); - v_src01 = v_load((int16_t*)(src[j]) + i + 8); - v_src02 = v_load((int16_t*)(src[j]) + i + 16); - v_src03 = v_load((int16_t*)(src[j]) + i + 24); + v_int32 v_resj0, v_resj1; + v_mul = v_reinterpret_as_s16(vx_setall_u16(*((uint16_t*)(m + j)))); + const int16_t* srcj = (const int16_t*)src[j] + i; + v_src00 = vx_load(srcj); + v_src01 = vx_load(srcj + VECSZ); + v_src02 = vx_load(srcj + 2*VECSZ); + v_src03 = vx_load(srcj + 3*VECSZ); v_mul_expand(v_add_wrap(v_src00, v_128), v_mul, v_resj0, v_resj1); v_res0 += v_resj0; v_res1 += v_resj1; @@ -3420,11 +3373,12 @@ void vlineSmooth(const ufixedpoint16* const * src, const v_res6 += v_128_4; v_res7 += v_128_4; - v_store(dst + i , v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res0, v_res1)), - v_reinterpret_as_u16(v_rshr_pack<16>(v_res2, v_res3)))); - v_store(dst + i + 16, v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res4, v_res5)), - v_reinterpret_as_u16(v_rshr_pack<16>(v_res6, v_res7)))); + v_store(dst + i , v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res0, v_res1)), + v_reinterpret_as_u16(v_rshr_pack<16>(v_res2, v_res3)))); + v_store(dst + i + 2*VECSZ, v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res4, v_res5)), + v_reinterpret_as_u16(v_rshr_pack<16>(v_res6, v_res7)))); } +#endif for (; i < len; i++) { ufixedpoint32 val = m[0] * src[0][i]; @@ -3450,29 +3404,32 @@ void vlineSmoothONa_yzy_a(const FT* const * src, const FT* m, int n, ET* dst, in template <> void vlineSmoothONa_yzy_a(const ufixedpoint16* const * src, const ufixedpoint16* m, int n, uint8_t* dst, int len) { - int pre_shift = n / 2; int i = 0; - static const v_int16x8 v_128 = v_reinterpret_as_s16(v_setall_u16((uint16_t)1 << 15)); - v_int32x4 v_128_4 = v_setall_s32(128 << 16); - if (len > 7) +#if CV_SIMD + int pre_shift = n / 2; + static const v_int16 v_128 = v_reinterpret_as_s16(vx_setall_u16((uint16_t)1 << 15)); + v_int32 v_128_4 = vx_setall_s32(128 << 16); + const int VECSZ = v_uint16::nlanes; + if (len >= VECSZ) { ufixedpoint16 msum = m[0] + m[pre_shift] + m[n - 1]; for (int j = 1; j < pre_shift; j++) msum = msum + m[j] + m[n - 1 - j]; ufixedpoint32 val[] = { msum * ufixedpoint16((uint8_t)128) }; - v_128_4 = v_setall_s32(*((int32_t*)val)); + v_128_4 = vx_setall_s32(*((int32_t*)val)); } - for (; i <= len - 32; i += 32) + for (; i <= len - 4*VECSZ; i += 4*VECSZ) { - v_int16x8 v_src00, v_src10, v_src20, v_src30, v_src01, v_src11, v_src21, v_src31; - v_int32x4 v_res0, v_res1, v_res2, v_res3, v_res4, v_res5, v_res6, v_res7; - v_int16x8 v_tmp0, v_tmp1, v_tmp2, v_tmp3, v_tmp4, v_tmp5, v_tmp6, v_tmp7; + v_int16 v_src00, v_src10, v_src20, v_src30, v_src01, v_src11, v_src21, v_src31; + v_int32 v_res0, v_res1, v_res2, v_res3, v_res4, v_res5, v_res6, v_res7; + v_int16 v_tmp0, v_tmp1, v_tmp2, v_tmp3, v_tmp4, v_tmp5, v_tmp6, v_tmp7; - v_int16x8 v_mul = v_reinterpret_as_s16(v_setall_u16(*((uint16_t*)(m + pre_shift)))); - v_src00 = v_load((int16_t*)(src[pre_shift]) + i); - v_src10 = v_load((int16_t*)(src[pre_shift]) + i + 8); - v_src20 = v_load((int16_t*)(src[pre_shift]) + i + 16); - v_src30 = v_load((int16_t*)(src[pre_shift]) + i + 24); + v_int16 v_mul = v_reinterpret_as_s16(vx_setall_u16(*((uint16_t*)(m + pre_shift)))); + const int16_t* srcp = (const int16_t*)src[pre_shift] + i; + v_src00 = vx_load(srcp); + v_src10 = vx_load(srcp + VECSZ); + v_src20 = vx_load(srcp + 2*VECSZ); + v_src30 = vx_load(srcp + 3*VECSZ); v_mul_expand(v_add_wrap(v_src00, v_128), v_mul, v_res0, v_res1); v_mul_expand(v_add_wrap(v_src10, v_128), v_mul, v_res2, v_res3); v_mul_expand(v_add_wrap(v_src20, v_128), v_mul, v_res4, v_res5); @@ -3481,16 +3438,18 @@ void vlineSmoothONa_yzy_a(const ufixedpoint16* const * s int j = 0; for (; j < pre_shift; j++) { - v_mul = v_reinterpret_as_s16(v_setall_u16(*((uint16_t*)(m + j)))); - - v_src00 = v_load((int16_t*)(src[j]) + i); - v_src10 = v_load((int16_t*)(src[j]) + i + 8); - v_src20 = v_load((int16_t*)(src[j]) + i + 16); - v_src30 = v_load((int16_t*)(src[j]) + i + 24); - v_src01 = v_load((int16_t*)(src[n - 1 - j]) + i); - v_src11 = v_load((int16_t*)(src[n - 1 - j]) + i + 8); - v_src21 = v_load((int16_t*)(src[n - 1 - j]) + i + 16); - v_src31 = v_load((int16_t*)(src[n - 1 - j]) + i + 24); + v_mul = v_reinterpret_as_s16(vx_setall_u16(*((uint16_t*)(m + j)))); + + const int16_t* srcj0 = (const int16_t*)src[j] + i; + const int16_t* srcj1 = (const int16_t*)src[n - 1 - j] + i; + v_src00 = vx_load(srcj0); + v_src10 = vx_load(srcj0 + VECSZ); + v_src20 = vx_load(srcj0 + 2*VECSZ); + v_src30 = vx_load(srcj0 + 3*VECSZ); + v_src01 = vx_load(srcj1); + v_src11 = vx_load(srcj1 + VECSZ); + v_src21 = vx_load(srcj1 + 2*VECSZ); + v_src31 = vx_load(srcj1 + 3*VECSZ); v_zip(v_add_wrap(v_src00, v_128), v_add_wrap(v_src01, v_128), v_tmp0, v_tmp1); v_res0 += v_dotprod(v_tmp0, v_mul); v_res1 += v_dotprod(v_tmp1, v_mul); @@ -3514,11 +3473,12 @@ void vlineSmoothONa_yzy_a(const ufixedpoint16* const * s v_res6 += v_128_4; v_res7 += v_128_4; - v_store(dst + i , v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res0, v_res1)), - v_reinterpret_as_u16(v_rshr_pack<16>(v_res2, v_res3)))); - v_store(dst + i + 16, v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res4, v_res5)), - v_reinterpret_as_u16(v_rshr_pack<16>(v_res6, v_res7)))); + v_store(dst + i , v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res0, v_res1)), + v_reinterpret_as_u16(v_rshr_pack<16>(v_res2, v_res3)))); + v_store(dst + i + 2*VECSZ, v_pack(v_reinterpret_as_u16(v_rshr_pack<16>(v_res4, v_res5)), + v_reinterpret_as_u16(v_rshr_pack<16>(v_res6, v_res7)))); } +#endif for (; i < len; i++) { ufixedpoint32 val = m[0] * src[0][i]; @@ -3816,8 +3776,8 @@ static void createGaussianKernels( T & kx, T & ky, int type, Size &ksize, if( ksize.height <= 0 && sigma2 > 0 ) ksize.height = cvRound(sigma2*(depth == CV_8U ? 3 : 4)*2 + 1)|1; - CV_Assert( ksize.width > 0 && ksize.width % 2 == 1 && - ksize.height > 0 && ksize.height % 2 == 1 ); + CV_Assert( ksize.width > 0 && ksize.width % 2 == 1 && + ksize.height > 0 && ksize.height % 2 == 1 ); sigma1 = std::max( sigma1, 0. ); sigma2 = std::max( sigma2, 0. ); @@ -4146,20 +4106,6 @@ void cv::GaussianBlur( InputArray _src, OutputArray _dst, Size ksize, int sdepth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type); - if(sdepth == CV_8U && ((borderType & BORDER_ISOLATED) || !_src.getMat().isSubmatrix())) - { - std::vector fkx, fky; - createGaussianKernels(fkx, fky, type, ksize, sigma1, sigma2); - Mat src = _src.getMat(); - Mat dst = _dst.getMat(); - if (src.data == dst.data) - src = src.clone(); - fixedSmoothInvoker invoker(src.ptr(), src.step1(), dst.ptr(), dst.step1(), dst.cols, dst.rows, dst.channels(), &fkx[0], (int)fkx.size(), &fky[0], (int)fky.size(), borderType & ~BORDER_ISOLATED); - parallel_for_(Range(0, dst.rows), invoker, std::max(1, std::min(getNumThreads(), getNumberOfCPUs()))); - return; - } - - Mat kx, ky; createGaussianKernels(kx, ky, type, ksize, sigma1, sigma2); @@ -4185,6 +4131,17 @@ void cv::GaussianBlur( InputArray _src, OutputArray _dst, Size ksize, CV_IPP_RUN_FAST(ipp_GaussianBlur(src, dst, ksize, sigma1, sigma2, borderType)); + if(sdepth == CV_8U && ((borderType & BORDER_ISOLATED) || !_src.getMat().isSubmatrix())) + { + std::vector fkx, fky; + createGaussianKernels(fkx, fky, type, ksize, sigma1, sigma2); + if (src.data == dst.data) + src = src.clone(); + fixedSmoothInvoker invoker(src.ptr(), src.step1(), dst.ptr(), dst.step1(), dst.cols, dst.rows, dst.channels(), &fkx[0], (int)fkx.size(), &fky[0], (int)fky.size(), borderType & ~BORDER_ISOLATED); + parallel_for_(Range(0, dst.rows), invoker, std::max(1, std::min(getNumThreads(), getNumberOfCPUs()))); + return; + } + sepFilter2D(src, dst, sdepth, kx, ky, Point(-1, -1), 0, borderType); } diff --git a/modules/imgproc/src/subdivision2d.cpp b/modules/imgproc/src/subdivision2d.cpp index 93c8b4c91b9c..596806c3ea3e 100644 --- a/modules/imgproc/src/subdivision2d.cpp +++ b/modules/imgproc/src/subdivision2d.cpp @@ -758,6 +758,7 @@ void Subdiv2D::getTriangleList(std::vector& triangleList) const triangleList.clear(); int i, total = (int)(qedges.size()*4); std::vector edgemask(total, false); + Rect2f rect(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y); for( i = 4; i < total; i += 2 ) { @@ -773,7 +774,8 @@ void Subdiv2D::getTriangleList(std::vector& triangleList) const edge = getEdge(edge, NEXT_AROUND_LEFT); edgeOrg(edge, &c); edgemask[edge] = true; - triangleList.push_back(Vec6f(a.x, a.y, b.x, b.y, c.x, c.y)); + if( rect.contains(a) && rect.contains(b) && rect.contains(c) ) + triangleList.push_back(Vec6f(a.x, a.y, b.x, b.y, c.x, c.y)); } } diff --git a/modules/imgproc/test/test_distancetransform.cpp b/modules/imgproc/test/test_distancetransform.cpp index de99a0851781..75ec5ec8fa19 100644 --- a/modules/imgproc/test/test_distancetransform.cpp +++ b/modules/imgproc/test/test_distancetransform.cpp @@ -283,4 +283,23 @@ void CV_DisTransTest::prepare_to_validation( int /*test_case_idx*/ ) TEST(Imgproc_DistanceTransform, accuracy) { CV_DisTransTest test; test.safe_run(); } +BIGDATA_TEST(Imgproc_DistanceTransform, large_image_12218) +{ + const int lls_maxcnt = 79992000; // labels's maximum count + const int lls_mincnt = 1; // labels's minimum count + int i, j, nz; + Mat src(8000, 20000, CV_8UC1), dst, labels; + for( i = 0; i < src.rows; i++ ) + for( j = 0; j < src.cols; j++ ) + src.at(i, j) = (j > (src.cols / 2)) ? 0 : 255; + + distanceTransform(src, dst, labels, cv::DIST_L2, cv::DIST_MASK_3, DIST_LABEL_PIXEL); + + double scale = (double)lls_mincnt / (double)lls_maxcnt; + labels.convertTo(labels, CV_32SC1, scale); + Size size = labels.size(); + nz = cv::countNonZero(labels); + EXPECT_EQ(nz, (size.height*size.width / 2)); +} + }} // namespace diff --git a/modules/imgproc/test/test_subdivision2d.cpp b/modules/imgproc/test/test_subdivision2d.cpp new file mode 100644 index 000000000000..0a366206b365 --- /dev/null +++ b/modules/imgproc/test/test_subdivision2d.cpp @@ -0,0 +1,53 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +//M*/ +#include "test_precomp.hpp" + +namespace opencv_test { namespace { +TEST(Imgproc_Subdiv2D_getTriangleList, regression_5788) +{ + const float points[65][2] = { + { 390, 802}, { 397, 883}, { 414, 963 }, { 439, 1042 }, { 472, 1113}, + { 521, 1181}, { 591, 1238}, { 678, 1284 }, { 771, 1292 }, { 853, 1281}, + { 921, 1243}, { 982, 1191}, {1030, 1121 }, {1059, 1038 }, {1072, 945}, + {1081, 849}, {1082, 749}, { 459, 734 }, { 502, 704 }, { 554, 696}, + { 609, 698}, { 660, 707}, { 818, 688 }, { 874, 661 }, { 929, 646}, + { 982, 653}, {1026, 682}, { 740, 771 }, { 748, 834 }, { 756, 897}, + { 762, 960}, { 700, 998}, { 733, 1006 }, { 766, 1011 }, { 797, 999}, + { 825, 987}, { 528, 796}, { 566, 766 }, { 617, 763 }, { 659, 794}, + { 619, 808}, { 569, 812}, { 834, 777 }, { 870, 735 }, { 918, 729}, + { 958, 750}, { 929, 773}, { 882, 780 }, { 652, 1102 }, { 701, 1079}, + { 743, 1063}, { 774, 1068}, { 807, 1057 }, { 852, 1065 }, { 896, 1077}, + { 860, 1117}, { 820, 1135}, { 783, 1141 }, { 751, 1140 }, { 706, 1130}, + { 675, 1102}, { 743, 1094}, { 774, 1094 }, { 809, 1088 }, { 878, 1082} + }; + std::vector pts; + cv::Rect rect(0, 0, 1500, 2000); + cv::Subdiv2D subdiv(rect); + for( int i = 0; i < 65; i++ ) + { + cv::Point2f pt(points[i][0], points[i][1]); + pts.push_back(pt); + } + + subdiv.insert(pts); + + std::vector triangles; + subdiv.getTriangleList(triangles); + + int trig_cnt = 0; + for( std::vector::const_iterator it = triangles.begin(); it != triangles.end(); it++, trig_cnt++ ) + { + EXPECT_TRUE( (0 <= triangles.at(trig_cnt).val[0] && triangles.at(trig_cnt).val[0] < 1500) && + (0 <= triangles.at(trig_cnt).val[1] && triangles.at(trig_cnt).val[1] < 2000) && + (0 <= triangles.at(trig_cnt).val[2] && triangles.at(trig_cnt).val[2] < 1500) && + (0 <= triangles.at(trig_cnt).val[3] && triangles.at(trig_cnt).val[3] < 2000) && + (0 <= triangles.at(trig_cnt).val[4] && triangles.at(trig_cnt).val[4] < 1500) && + (0 <= triangles.at(trig_cnt).val[5] && triangles.at(trig_cnt).val[5] < 2000) ); + } + EXPECT_EQ(trig_cnt, 105); +} + +}}; diff --git a/modules/java/generator/src/cpp/opencv_java.hpp b/modules/java/generator/src/cpp/opencv_java.hpp index e5cd622e31e5..fb8625bea912 100644 --- a/modules/java/generator/src/cpp/opencv_java.hpp +++ b/modules/java/generator/src/cpp/opencv_java.hpp @@ -29,7 +29,7 @@ #define ARRAYLIST(ENV) static_cast(ENV->NewGlobalRef(ENV->FindClass("java/util/ArrayList"))) #define LIST_ADD(ENV, LIST) ENV->GetMethodID(LIST, "add", "(Ljava/lang/Object;)Z") -#define LIST_GET(ENV, LIST) ENV->GetMethodID(LIST, "get", "((I)Ljava/lang/Object;") +#define LIST_GET(ENV, LIST) ENV->GetMethodID(LIST, "get", "(I)Ljava/lang/Object;") #define LIST_SIZE(ENV, LIST) ENV->GetMethodID(LIST, "size", "()I") #define LIST_CLEAR(ENV, LIST) ENV->GetMethodID(LIST, "clear", "()V") diff --git a/modules/js/CMakeLists.txt b/modules/js/CMakeLists.txt index 7db438b8a915..6d713d4bd92a 100644 --- a/modules/js/CMakeLists.txt +++ b/modules/js/CMakeLists.txt @@ -56,7 +56,7 @@ add_custom_command( DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/embindgen.py DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/templates.py DEPENDS ${scripts_hdr_parser} - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/headers.txt + #(not needed - generated by CMake) DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/headers.txt DEPENDS ${opencv_hdrs} DEPENDS ${JS_HELPER}) diff --git a/modules/js/src/core_bindings.cpp b/modules/js/src/core_bindings.cpp index 18427d18fec3..e8f0ee7f856a 100644 --- a/modules/js/src/core_bindings.cpp +++ b/modules/js/src/core_bindings.cpp @@ -68,15 +68,10 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //M*/ -#include "opencv2/core.hpp" -#include "opencv2/imgproc.hpp" -#include "opencv2/video/tracking.hpp" -#include "opencv2/video/background_segm.hpp" -#include "opencv2/objdetect.hpp" -#include "opencv2/dnn.hpp" - #include +@INCLUDES@ + using namespace emscripten; using namespace cv; using namespace dnn; diff --git a/modules/js/src/embindgen.py b/modules/js/src/embindgen.py index a35671fbf5ce..5e0344cb55ae 100644 --- a/modules/js/src/embindgen.py +++ b/modules/js/src/embindgen.py @@ -733,12 +733,14 @@ def print_decls(self, decls): def gen(self, dst_file, src_files, core_bindings): # step 1: scan the headers and extract classes, enums and functions + headers = [] for hdr in src_files: decls = self.parser.parse(hdr) # print(hdr); # self.print_decls(decls); if len(decls) == 0: continue + headers.append(hdr[hdr.rindex('opencv2/'):]) for decl in decls: name = decl[0] type = name[:name.find(" ")] @@ -890,6 +892,9 @@ def gen(self, dst_file, src_files, core_bindings): with open(core_bindings) as f: ret = f.read() + header_includes = '\n'.join(['#include "{}"'.format(hdr) for hdr in headers]) + ret = ret.replace('@INCLUDES@', header_includes) + defis = '\n'.join(self.wrapper_funcs) ret += wrapper_codes_template.substitute(ns=wrapper_namespace, defs=defis) ret += emscripten_binding_template.substitute(binding_name='testBinding', bindings=''.join(self.bindings)) diff --git a/modules/ml/src/knearest.cpp b/modules/ml/src/knearest.cpp index d608012dfb12..df48b00f24f2 100644 --- a/modules/ml/src/knearest.cpp +++ b/modules/ml/src/knearest.cpp @@ -140,13 +140,12 @@ class BruteForceImpl CV_FINAL : public Impl String getModelName() const CV_OVERRIDE { return NAME_BRUTE_FORCE; } int getType() const CV_OVERRIDE { return ml::KNearest::BRUTE_FORCE; } - void findNearestCore( const Mat& _samples, int k0, const Range& range, + void findNearestCore( const Mat& _samples, int k, const Range& range, Mat* results, Mat* neighbor_responses, Mat* dists, float* presult ) const { int testidx, baseidx, i, j, d = samples.cols, nsamples = samples.rows; int testcount = range.end - range.start; - int k = std::min(k0, nsamples); AutoBuffer buf(testcount*k*2); float* dbuf = buf.data(); @@ -215,7 +214,7 @@ class BruteForceImpl CV_FINAL : public Impl float* nr = neighbor_responses->ptr(testidx + range.start); for( j = 0; j < k; j++ ) nr[j] = rbuf[testidx*k + j]; - for( ; j < k0; j++ ) + for( ; j < k; j++ ) nr[j] = 0.f; } @@ -224,7 +223,7 @@ class BruteForceImpl CV_FINAL : public Impl float* dptr = dists->ptr(testidx + range.start); for( j = 0; j < k; j++ ) dptr[j] = dbuf[testidx*k + j]; - for( ; j < k0; j++ ) + for( ; j < k; j++ ) dptr[j] = 0.f; } @@ -307,6 +306,7 @@ class BruteForceImpl CV_FINAL : public Impl { float result = 0.f; CV_Assert( 0 < k ); + k = std::min(k, samples.rows); Mat test_samples = _samples.getMat(); CV_Assert( test_samples.type() == CV_32F && test_samples.cols == samples.cols ); @@ -363,6 +363,7 @@ class KDTreeImpl CV_FINAL : public Impl { float result = 0.f; CV_Assert( 0 < k ); + k = std::min(k, samples.rows); Mat test_samples = _samples.getMat(); CV_Assert( test_samples.type() == CV_32F && test_samples.cols == samples.cols ); diff --git a/modules/ml/test/test_emknearestkmeans.cpp b/modules/ml/test/test_emknearestkmeans.cpp index 6755c2e9e4f0..691815c52a0a 100644 --- a/modules/ml/test/test_emknearestkmeans.cpp +++ b/modules/ml/test/test_emknearestkmeans.cpp @@ -702,4 +702,26 @@ TEST(ML_EM, accuracy) { CV_EMTest test; test.safe_run(); } TEST(ML_EM, save_load) { CV_EMTest_SaveLoad test; test.safe_run(); } TEST(ML_EM, classification) { CV_EMTest_Classification test; test.safe_run(); } +TEST(ML_KNearest, regression_12347) +{ + Mat xTrainData = (Mat_(5,2) << 1, 1.1, 1.1, 1, 2, 2, 2.1, 2, 2.1, 2.1); + Mat yTrainLabels = (Mat_(5,1) << 1, 1, 2, 2, 2); + Ptr knn = KNearest::create(); + knn->train(xTrainData, ml::ROW_SAMPLE, yTrainLabels); + + Mat xTestData = (Mat_(2,2) << 1.1, 1.1, 2, 2.2); + Mat zBestLabels, neighbours, dist; + // check output shapes: + int K = 16, Kexp = std::min(K, xTrainData.rows); + knn->findNearest(xTestData, K, zBestLabels, neighbours, dist); + EXPECT_EQ(xTestData.rows, zBestLabels.rows); + EXPECT_EQ(neighbours.cols, Kexp); + EXPECT_EQ(dist.cols, Kexp); + // see if the result is still correct: + K = 2; + knn->findNearest(xTestData, K, zBestLabels, neighbours, dist); + EXPECT_EQ(1, zBestLabels.at(0,0)); + EXPECT_EQ(2, zBestLabels.at(1,0)); +} + }} // namespace diff --git a/modules/ts/include/opencv2/ts/ts_gtest.h b/modules/ts/include/opencv2/ts/ts_gtest.h index b687a5722e28..9771c51d7f69 100644 --- a/modules/ts/include/opencv2/ts/ts_gtest.h +++ b/modules/ts/include/opencv2/ts/ts_gtest.h @@ -26,10 +26,9 @@ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + // -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines the public API for Google Test. It should be // included by any test program that uses Google Test. @@ -48,6 +47,8 @@ // registration from Barthelemy Dagenais' (barthelemy@prologique.com) // easyUnit framework. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_GTEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_H_ @@ -84,13 +85,13 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file declares functions and macros used internally by // Google Test. They are subject to change without notice. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ @@ -123,8 +124,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: wan@google.com (Zhanyong Wan) -// // Low-level types and utilities for porting Google Test to various // platforms. All macros ending with _ and symbols defined in an // internal namespace are subject to change without notice. Code @@ -136,6 +135,8 @@ // files are expected to #include this. Therefore, it cannot #include // any other Google Test header. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ @@ -169,11 +170,9 @@ // GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions // are enabled. // GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string -// is/isn't available (some systems define -// ::string, which is different to std::string). -// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string -// is/isn't available (some systems define -// ::wstring, which is different to std::wstring). +// is/isn't available +// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::wstring +// is/isn't available // GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular // expressions are/aren't available. // GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that @@ -205,6 +204,12 @@ // GTEST_CREATE_SHARED_LIBRARY // - Define to 1 when compiling Google Test itself // as a shared library. +// GTEST_DEFAULT_DEATH_TEST_STYLE +// - The default value of --gtest_death_test_style. +// The legacy default has been "fast" in the open +// source version since 2008. The recommended value +// is "threadsafe", and can be set in +// custom/gtest-port.h. // Platform-indicating macros // -------------------------- @@ -218,12 +223,14 @@ // GTEST_OS_AIX - IBM AIX // GTEST_OS_CYGWIN - Cygwin // GTEST_OS_FREEBSD - FreeBSD +// GTEST_OS_FUCHSIA - Fuchsia // GTEST_OS_HPUX - HP-UX // GTEST_OS_LINUX - Linux // GTEST_OS_LINUX_ANDROID - Google Android // GTEST_OS_MAC - Mac OS X // GTEST_OS_IOS - iOS // GTEST_OS_NACL - Google Native Client (NaCl) +// GTEST_OS_NETBSD - NetBSD // GTEST_OS_OPENBSD - OpenBSD // GTEST_OS_QNX - QNX // GTEST_OS_SOLARIS - Sun Solaris @@ -265,15 +272,15 @@ // GTEST_HAS_COMBINE - the Combine() function (for value-parameterized // tests) // GTEST_HAS_DEATH_TEST - death tests -// GTEST_HAS_PARAM_TEST - value-parameterized tests // GTEST_HAS_TYPED_TEST - typed tests // GTEST_HAS_TYPED_TEST_P - type-parameterized tests // GTEST_IS_THREADSAFE - Google Test is thread-safe. +// GOOGLETEST_CM0007 DO NOT DELETE // GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with // GTEST_HAS_POSIX_RE (see above) which users can // define themselves. // GTEST_USES_SIMPLE_RE - our own simple regex is used; -// the above two are mutually exclusive. +// the above RE\b(s) are mutually exclusive. // GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ(). // Misc public macros @@ -302,6 +309,7 @@ // // C++11 feature wrappers: // +// testing::internal::forward - portability wrapper for std::forward. // testing::internal::move - portability wrapper for std::move. // // Synchronization: @@ -318,10 +326,10 @@ // // Regular expressions: // RE - a simple regular expression class using the POSIX -// Extended Regular Expression syntax on UNIX-like -// platforms, or a reduced regular exception syntax on -// other platforms, including Windows. -// +// Extended Regular Expression syntax on UNIX-like platforms +// GOOGLETEST_CM0008 DO NOT DELETE +// or a reduced regular exception syntax on other +// platforms, including Windows. // Logging: // GTEST_LOG_() - logs messages at the specified severity level. // LogToStderr() - directs all log messages to stderr. @@ -367,10 +375,12 @@ # include #endif +// Brings in the definition of HAS_GLOBAL_STRING. This must be done +// BEFORE we test HAS_GLOBAL_STRING. +#include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT -#include // NOLINT #include #include // NOLINT @@ -403,7 +413,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines the GTEST_OS_* macro. // It is separate from gtest-port.h so that custom/gtest-port.h can include it. @@ -419,6 +429,7 @@ #define GTEST_OS_WINDOWS_MINGW 0 #define GTEST_OS_WINDOWS_DESKTOP 0 #define GTEST_OS_WINDOWS_PHONE 0 +#define GTEST_OS_WINDOWS_TV_TITLE 0 #define GTEST_OS_WINDOWS_RT 0 #define GTEST_OS_MAC 0 #define GTEST_OS_LINUX 0 @@ -433,6 +444,8 @@ #define GTEST_OS_IOS 0 #define GTEST_OS_IOS_SIMULATOR 0 #define GTEST_OS_FREEBSD 0 +#define GTEST_OS_NETBSD 0 +#define GTEST_OS_FUCHSIA 0 #ifdef __CYGWIN__ # undef GTEST_OS_CYGWIN @@ -460,6 +473,11 @@ # elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) # undef GTEST_OS_WINDOWS_RT # define GTEST_OS_WINDOWS_RT 1 +# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE) +# undef GTEST_OS_WINDOWS_PHONE +# undef GTEST_OS_WINDOWS_TV_TITLE +# define GTEST_OS_WINDOWS_PHONE 1 +# define GTEST_OS_WINDOWS_TV_TITLE 1 # else // WINAPI_FAMILY defined but no known partition matched. // Default to desktop. @@ -484,6 +502,9 @@ #elif defined __FreeBSD__ # undef GTEST_OS_FREEBSD # define GTEST_OS_FREEBSD 1 +#elif defined __Fuchsia__ +# undef GTEST_OS_FUCHSIA +# define GTEST_OS_FUCHSIA 1 #elif defined __linux__ # undef GTEST_OS_LINUX # define GTEST_OS_LINUX 1 @@ -506,6 +527,9 @@ #elif defined __native_client__ # undef GTEST_OS_NACL # define GTEST_OS_NACL 1 +#elif defined __NetBSD__ +# undef GTEST_OS_NETBSD +# define GTEST_OS_NETBSD 1 #elif defined __OpenBSD__ # undef GTEST_OS_OPENBSD # define GTEST_OS_OPENBSD 1 @@ -544,39 +568,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Injection point for custom user configurations. -// The following macros can be defined: -// -// Flag related macros: -// GTEST_FLAG(flag_name) -// GTEST_USE_OWN_FLAGFILE_FLAG_ - Define to 0 when the system provides its -// own flagfile flag parsing. -// GTEST_DECLARE_bool_(name) -// GTEST_DECLARE_int32_(name) -// GTEST_DECLARE_string_(name) -// GTEST_DEFINE_bool_(name, default_val, doc) -// GTEST_DEFINE_int32_(name, default_val, doc) -// GTEST_DEFINE_string_(name, default_val, doc) -// -// Test filtering: -// GTEST_TEST_FILTER_ENV_VAR_ - The name of an environment variable that -// will be used if --GTEST_FLAG(test_filter) -// is not provided. -// -// Logging: -// GTEST_LOG_(severity) -// GTEST_CHECK_(condition) -// Functions LogToStderr() and FlushInfoLog() have to be provided too. -// -// Threading: -// GTEST_HAS_NOTIFICATION_ - Enabled if Notification is already provided. -// GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ - Enabled if Mutex and ThreadLocal are -// already provided. -// Must also provide GTEST_DECLARE_STATIC_MUTEX_(mutex) and -// GTEST_DEFINE_STATIC_MUTEX_(mutex) -// -// GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks) -// GTEST_LOCK_EXCLUDED_(locks) +// Injection point for custom user configurations. See README for details // // ** Custom implementation starts here ** @@ -617,7 +609,7 @@ // GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 4385) // /* code that triggers warnings C4800 and C4385 */ // GTEST_DISABLE_MSC_WARNINGS_POP_() -#if defined(_MSC_VER) && _MSC_VER >= 1500 +#if defined(_MSC_VER) && _MSC_VER >= 1400 # define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) \ __pragma(warning(push)) \ __pragma(warning(disable: warnings)) @@ -629,12 +621,28 @@ # define GTEST_DISABLE_MSC_WARNINGS_POP_() #endif +// Clang on Windows does not understand MSVC's pragma warning. +// We need clang-specific way to disable function deprecation warning. +#ifdef __clang__ +# define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-implementations\"") +#define GTEST_DISABLE_MSC_DEPRECATED_POP_() \ + _Pragma("clang diagnostic pop") +#else +# define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \ + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) +# define GTEST_DISABLE_MSC_DEPRECATED_POP_() \ + GTEST_DISABLE_MSC_WARNINGS_POP_() +#endif + #ifndef GTEST_LANG_CXX11 // gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when // -std={c,gnu}++{0x,11} is passed. The C++11 standard specifies a // value for __cplusplus, and recent versions of clang, gcc, and // probably other compilers set that too in C++11 mode. -# if defined __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L +# if defined __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900) // Compiling in at least C++11 mode. # define GTEST_LANG_CXX11 1 # else @@ -668,12 +676,16 @@ #if GTEST_STDLIB_CXX11 # define GTEST_HAS_STD_BEGIN_AND_END_ 1 # define GTEST_HAS_STD_FORWARD_LIST_ 1 -# define GTEST_HAS_STD_FUNCTION_ 1 +# if !defined(_MSC_VER) || (_MSC_FULL_VER >= 190023824) +// works only with VS2015U2 and better +# define GTEST_HAS_STD_FUNCTION_ 1 +# endif # define GTEST_HAS_STD_INITIALIZER_LIST_ 1 # define GTEST_HAS_STD_MOVE_ 1 -# define GTEST_HAS_STD_SHARED_PTR_ 1 -# define GTEST_HAS_STD_TYPE_TRAITS_ 1 # define GTEST_HAS_STD_UNIQUE_PTR_ 1 +# define GTEST_HAS_STD_SHARED_PTR_ 1 +# define GTEST_HAS_UNORDERED_MAP_ 1 +# define GTEST_HAS_UNORDERED_SET_ 1 #else # define GTEST_HAS_STD_BEGIN_AND_END_ 0 # define GTEST_HAS_STD_FORWARD_LIST_ 0 @@ -683,6 +695,9 @@ # define GTEST_HAS_STD_SHARED_PTR_ 0 # define GTEST_HAS_STD_TYPE_TRAITS_ 0 # define GTEST_HAS_STD_UNIQUE_PTR_ 0 +# define GTEST_HAS_STD_SHARED_PTR_ 0 +# define GTEST_HAS_UNORDERED_MAP_ 0 +# define GTEST_HAS_UNORDERED_SET_ 0 #endif // C++11 specifies that provides std::tuple. @@ -690,7 +705,8 @@ #if GTEST_LANG_CXX11 # define GTEST_HAS_STD_TUPLE_ 1 # if defined(__clang__) -// Inspired by http://clang.llvm.org/docs/LanguageExtensions.html#__has_include +// Inspired by +// https://clang.llvm.org/docs/LanguageExtensions.html#include-file-checking-macros # if defined(__has_include) && !__has_include() # undef GTEST_HAS_STD_TUPLE_ # endif @@ -702,7 +718,7 @@ # elif defined(__GLIBCXX__) // Inspired by boost/config/stdlib/libstdcpp3.hpp, // http://gcc.gnu.org/gcc-4.2/changes.html and -// http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt01ch01.html#manual.intro.status.standard.200x +// https://web.archive.org/web/20140227044429/gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt01ch01.html#manual.intro.status.standard.200x # if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2) # undef GTEST_HAS_STD_TUPLE_ # endif @@ -721,15 +737,15 @@ # endif // In order to avoid having to include , use forward declaration #if GTEST_OS_WINDOWS_MINGW && !defined(__MINGW64_VERSION_MAJOR) - // MinGW defined _CRITICAL_SECTION and _RTL_CRITICAL_SECTION as two - // separate (equivalent) structs, instead of using typedef - typedef struct _CRITICAL_SECTION GTEST_CRITICAL_SECTION; -# else - // assuming CRITICAL_SECTION is a typedef of _RTL_CRITICAL_SECTION. - // This assumption is verified by - // WindowsTypesTest.CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION. - typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; -# endif +// MinGW defined _CRITICAL_SECTION and _RTL_CRITICAL_SECTION as two +// separate (equivalent) structs, instead of using typedef +typedef struct _CRITICAL_SECTION GTEST_CRITICAL_SECTION; +#else +// Assume CRITICAL_SECTION is a typedef of _RTL_CRITICAL_SECTION. +// This assumption is verified by +// WindowsTypesTest.CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION. +typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; +#endif #else // This assumes that non-Windows OSes provide unistd.h. For OSes where this // is not the case, we need to include headers that provide the functions @@ -746,14 +762,18 @@ // Defines this to true iff Google Test can use POSIX regular expressions. #ifndef GTEST_HAS_POSIX_RE # if GTEST_OS_LINUX_ANDROID -// On Android, is only available starting with Froyo. -# define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 8) +// On Android, is only available starting with Gingerbread. +# define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9) # else -# define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS) +# define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS) +# endif #endif + +#ifndef GTEST_USES_PCRE +#define GTEST_USES_PCRE 0 #endif -#if defined(GTEST_USES_PCRE) && GTEST_USES_PCRE +#if GTEST_USES_PCRE // The appropriate headers have already been included. #elif GTEST_HAS_POSIX_RE @@ -786,8 +806,11 @@ #ifndef GTEST_HAS_EXCEPTIONS // The user didn't tell us whether exceptions are enabled, so we need // to figure it out. -# if defined(_MSC_VER) || defined(__BORLANDC__) -// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS +# if defined(_MSC_VER) && defined(_CPPUNWIND) +// MSVC defines _CPPUNWIND to 1 iff exceptions are enabled. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__BORLANDC__) +// C++Builder's implementation of the STL uses the _HAS_EXCEPTIONS // macro to enable exceptions, so we'll do the same. // Assumes that exceptions are enabled by default. # ifndef _HAS_EXCEPTIONS @@ -831,21 +854,17 @@ # define GTEST_HAS_STD_STRING 1 #elif !GTEST_HAS_STD_STRING // The user told us that ::std::string isn't available. -# error "Google Test cannot be used where ::std::string isn't available." +# error "::std::string isn't available." #endif // !defined(GTEST_HAS_STD_STRING) #ifndef GTEST_HAS_GLOBAL_STRING -// The user didn't tell us whether ::string is available, so we need -// to figure it out. - # define GTEST_HAS_GLOBAL_STRING 0 - #endif // GTEST_HAS_GLOBAL_STRING #ifndef GTEST_HAS_STD_WSTRING // The user didn't tell us whether ::std::wstring is available, so we need // to figure it out. -// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring +// FIXME: uses autoconf to detect whether ::std::wstring // is available. // Cygwin 1.7 and below doesn't support ::std::wstring. @@ -888,8 +907,8 @@ !defined(__EXCEPTIONS) # define GTEST_HAS_RTTI 0 # else -# define GTEST_HAS_RTTI 1 -# endif // GTEST_OS_LINUX_ANDROID && _STLPORT_MAJOR && !__EXCEPTIONS +# define GTEST_HAS_RTTI 1 +# endif // GTEST_OS_LINUX_ANDROID && __STLPORT_MAJOR && !__EXCEPTIONS # else # define GTEST_HAS_RTTI 0 # endif // __GXX_RTTI @@ -933,8 +952,9 @@ // // To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 // to your compiler flags. -# define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX \ - || GTEST_OS_QNX || GTEST_OS_FREEBSD || GTEST_OS_NACL) +#define GTEST_HAS_PTHREAD \ + (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX || GTEST_OS_QNX || \ + GTEST_OS_FREEBSD || GTEST_OS_NACL || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA) #endif // GTEST_HAS_PTHREAD #if GTEST_HAS_PTHREAD @@ -949,7 +969,7 @@ // Determines if hash_map/hash_set are available. // Only used for testing against those containers. #if !defined(GTEST_HAS_HASH_MAP_) -# ifdef _MSC_VER +# if defined(_MSC_VER) && (_MSC_VER < 1900) # define GTEST_HAS_HASH_MAP_ 1 // Indicates that hash_map is available. # define GTEST_HAS_HASH_SET_ 1 // Indicates that hash_set is available. # endif // _MSC_VER @@ -962,6 +982,14 @@ # if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) // STLport, provided with the Android NDK, has neither or . # define GTEST_HAS_TR1_TUPLE 0 +# elif defined(_MSC_VER) && (_MSC_VER >= 1910) +// Prevent `warning C4996: 'std::tr1': warning STL4002: +// The non-Standard std::tr1 namespace and TR1-only machinery +// are deprecated and will be REMOVED.` +# define GTEST_HAS_TR1_TUPLE 0 +# elif GTEST_LANG_CXX11 && defined(_LIBCPP_VERSION) +// libc++ doesn't support TR1. +# define GTEST_HAS_TR1_TUPLE 0 # else // The user didn't tell us not to do it, so we assume it's OK. # define GTEST_HAS_TR1_TUPLE 1 @@ -971,6 +999,10 @@ // Determines whether Google Test's own tr1 tuple implementation // should be used. #ifndef GTEST_USE_OWN_TR1_TUPLE +// We use our own tuple implementation on Symbian. +# if GTEST_OS_SYMBIAN +# define GTEST_USE_OWN_TR1_TUPLE 1 +# else // The user didn't tell us, so we need to figure it out. // We use our own TR1 tuple if we aren't sure the user has an @@ -984,8 +1016,8 @@ // support TR1 tuple. libc++ only provides std::tuple, in C++11 mode, // and it can be used with some compilers that define __GNUC__. # if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000) \ - && !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) && !defined(_STLPORT_MAJOR) \ - || (defined(_MSC_VER) && _MSC_VER >= 1600) + && !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) \ + || (defined(_MSC_VER) && _MSC_VER >= 1600 && _MSC_VER < 1900) # define GTEST_ENV_HAS_TR1_TUPLE_ 1 # else # define GTEST_ENV_HAS_TR1_TUPLE_ 0 @@ -1007,12 +1039,11 @@ # undef GTEST_HAS_TR1_TUPLE # define GTEST_HAS_TR1_TUPLE 1 # endif - +# endif // GTEST_OS_SYMBIAN #endif // GTEST_USE_OWN_TR1_TUPLE -// To avoid conditional compilation everywhere, we make it -// gtest-port.h's responsibility to #include the header implementing -// tuple. +// To avoid conditional compilation we make it gtest-port.h's responsibility +// to #include the header implementing tuple. #if GTEST_HAS_STD_TUPLE_ # include // IWYU pragma: export # define GTEST_TUPLE_NAMESPACE_ ::std @@ -1058,11 +1089,12 @@ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan) + // Implements a subset of TR1 tuple needed by Google Test and Google Mock. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ @@ -1070,7 +1102,7 @@ // The compiler used in Symbian has a bug that prevents us from declaring the // tuple template as a friend (it complains that tuple is redefined). This -// hack bypasses the bug by declaring the members that should otherwise be +// bypasses the bug by declaring the members that should otherwise be // private as public. // Sun Studio versions < 12 also have the above bug. #if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) @@ -1178,52 +1210,52 @@ template struct TupleElement; template -struct TupleElement { +struct TupleElement { typedef T0 type; }; template -struct TupleElement { +struct TupleElement { typedef T1 type; }; template -struct TupleElement { +struct TupleElement { typedef T2 type; }; template -struct TupleElement { +struct TupleElement { typedef T3 type; }; template -struct TupleElement { +struct TupleElement { typedef T4 type; }; template -struct TupleElement { +struct TupleElement { typedef T5 type; }; template -struct TupleElement { +struct TupleElement { typedef T6 type; }; template -struct TupleElement { +struct TupleElement { typedef T7 type; }; template -struct TupleElement { +struct TupleElement { typedef T8 type; }; template -struct TupleElement { +struct TupleElement { typedef T9 type; }; @@ -1766,57 +1798,57 @@ inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, template struct tuple_size; template -struct tuple_size { +struct tuple_size { static const int value = 0; }; template -struct tuple_size { +struct tuple_size { static const int value = 1; }; template -struct tuple_size { +struct tuple_size { static const int value = 2; }; template -struct tuple_size { +struct tuple_size { static const int value = 3; }; template -struct tuple_size { +struct tuple_size { static const int value = 4; }; template -struct tuple_size { +struct tuple_size { static const int value = 5; }; template -struct tuple_size { +struct tuple_size { static const int value = 6; }; template -struct tuple_size { +struct tuple_size { static const int value = 7; }; template -struct tuple_size { +struct tuple_size { static const int value = 8; }; template -struct tuple_size { +struct tuple_size { static const int value = 9; }; template -struct tuple_size { +struct tuple_size { static const int value = 10; }; @@ -2002,8 +2034,8 @@ template inline bool operator==(const GTEST_10_TUPLE_(T)& t, const GTEST_10_TUPLE_(U)& u) { return gtest_internal::SameSizeTuplePrefixComparator< - tuple_size::value, - tuple_size::value>::Eq(t, u); + tuple_size::value, + tuple_size::value>::Eq(t, u); } template @@ -2046,22 +2078,6 @@ inline bool operator!=(const GTEST_10_TUPLE_(T)& t, #undef GTEST_TUPLE_ELEMENT_ #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ -# elif GTEST_ENV_HAS_STD_TUPLE_ -# include -// C++11 puts its tuple into the ::std namespace rather than -// ::std::tr1. gtest expects tuple to live in ::std::tr1, so put it there. -// This causes undefined behavior, but supported compilers react in -// the way we intend. -namespace std { -namespace tr1 { -using ::std::get; -using ::std::make_tuple; -using ::std::tuple; -using ::std::tuple_element; -using ::std::tuple_size; -} -} - # elif GTEST_OS_SYMBIAN // On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to @@ -2086,20 +2102,22 @@ using ::std::tuple_size; // Until version 4.3.2, gcc has a bug that causes , // which is #included by , to not compile when RTTI is // disabled. _TR1_FUNCTIONAL is the header guard for -// . Hence the following #define is a hack to prevent +// . Hence the following #define is used to prevent // from being included. # define _TR1_FUNCTIONAL 1 # include # undef _TR1_FUNCTIONAL // Allows the user to #include - // if he chooses to. + // if they choose to. # else # include // NOLINT # endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 -# else -// If the compiler is not GCC 4.0+, we assume the user is using a -// spec-conforming TR1 implementation. +// VS 2010 now has tr1 support. +# elif defined(_MSC_VER) && _MSC_VER >= 1600 # include // IWYU pragma: export // NOLINT + +# else // GTEST_USE_OWN_TR1_TUPLE +# include // IWYU pragma: export // NOLINT # endif // GTEST_USE_OWN_TR1_TUPLE #endif // GTEST_HAS_TR1_TUPLE @@ -2113,14 +2131,18 @@ using ::std::tuple_size; # if GTEST_OS_LINUX && !defined(__ia64__) # if GTEST_OS_LINUX_ANDROID -// On Android, clone() is only available on ARM starting with Gingerbread. -# if (defined(__arm__) || defined(__mips__)) && __ANDROID_API__ >= 9 +// On Android, clone() became available at different API levels for each 32-bit +// architecture. +# if defined(__LP64__) || \ + (defined(__arm__) && __ANDROID_API__ >= 9) || \ + (defined(__mips__) && __ANDROID_API__ >= 12) || \ + (defined(__i386__) && __ANDROID_API__ >= 17) # define GTEST_HAS_CLONE 1 # else # define GTEST_HAS_CLONE 0 # endif # else -# define GTEST_HAS_CLONE 1 +# define GTEST_HAS_CLONE 1 # endif # else # define GTEST_HAS_CLONE 0 @@ -2145,22 +2167,18 @@ using ::std::tuple_size; // Google Test does not support death tests for VC 7.1 and earlier as // abort() in a VC 7.1 application compiled as GUI in debug config // pops up a dialog window that cannot be suppressed programmatically. -#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ - (GTEST_OS_MAC && !GTEST_OS_IOS) || \ - (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ +#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ + (GTEST_OS_MAC && !GTEST_OS_IOS) || \ + (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \ - GTEST_OS_OPENBSD || GTEST_OS_QNX || GTEST_OS_FREEBSD) + GTEST_OS_OPENBSD || GTEST_OS_QNX || GTEST_OS_FREEBSD || \ + GTEST_OS_NETBSD || GTEST_OS_FUCHSIA) # define GTEST_HAS_DEATH_TEST 1 # include // NOLINT #else # define GTEST_HAS_DEATH_TEST 0 #endif -// We don't support MSVC 7.1 with exceptions disabled now. Therefore -// all the compilers we care about are adequate for supporting -// value-parameterized tests. -#define GTEST_HAS_PARAM_TEST 1 - // Determines whether to support type-driven tests. // Typed tests need and variadic macros, which GCC, VC++ 8.0, @@ -2175,7 +2193,7 @@ using ::std::tuple_size; // value-parameterized tests are enabled. The implementation doesn't // work on Sun Studio since it doesn't understand templated conversion // operators. -#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC) +#if (GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_) && !defined(__SUNPRO_CC) # define GTEST_HAS_COMBINE 1 #endif @@ -2228,15 +2246,39 @@ using ::std::tuple_size; # define GTEST_ATTRIBUTE_UNUSED_ #endif +#if GTEST_LANG_CXX11 +# define GTEST_CXX11_EQUALS_DELETE_ = delete +#else // GTEST_LANG_CXX11 +# define GTEST_CXX11_EQUALS_DELETE_ +#endif // GTEST_LANG_CXX11 + +// Use this annotation before a function that takes a printf format string. +#if (defined(__GNUC__) || defined(__clang__)) && !defined(COMPILER_ICC) +# if defined(__MINGW_PRINTF_FORMAT) +// MinGW has two different printf implementations. Ensure the format macro +// matches the selected implementation. See +// https://sourceforge.net/p/mingw-w64/wiki2/gnu%20printf/. +# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \ + __attribute__((__format__(__MINGW_PRINTF_FORMAT, string_index, \ + first_to_check))) +# else +# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \ + __attribute__((__format__(__printf__, string_index, first_to_check))) +# endif +#else +# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) +#endif + + // A macro to disallow operator= // This should be used in the private: declarations for a class. -#define GTEST_DISALLOW_ASSIGN_(type)\ - void operator=(type const &) +#define GTEST_DISALLOW_ASSIGN_(type) \ + void operator=(type const &) GTEST_CXX11_EQUALS_DELETE_ // A macro to disallow copy constructor and operator= // This should be used in the private: declarations for a class. -#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\ - type(type const &);\ +#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type) \ + type(type const &) GTEST_CXX11_EQUALS_DELETE_; \ GTEST_DISALLOW_ASSIGN_(type) // Tell the compiler to warn about unused return values for functions declared @@ -2284,6 +2326,11 @@ using ::std::tuple_size; #endif // GTEST_HAS_SEH +// GTEST_API_ qualifies all symbols that must be exported. The definitions below +// are guarded by #ifndef to give embedders a chance to define GTEST_API_ in +// gtest/internal/custom/gtest-port.h +#ifndef GTEST_API_ + #ifdef _MSC_VER # if GTEST_LINKED_AS_SHARED_LIBRARY # define GTEST_API_ __declspec(dllimport) @@ -2292,11 +2339,17 @@ using ::std::tuple_size; # endif #elif __GNUC__ >= 4 || defined(__clang__) # define GTEST_API_ __attribute__((visibility ("default"))) -#endif // _MSC_VER +#endif // _MSC_VER + +#endif // GTEST_API_ #ifndef GTEST_API_ # define GTEST_API_ -#endif +#endif // GTEST_API_ + +#ifndef GTEST_DEFAULT_DEATH_TEST_STYLE +# define GTEST_DEFAULT_DEATH_TEST_STYLE "fast" +#endif // GTEST_DEFAULT_DEATH_TEST_STYLE #ifdef __GNUC__ // Ask the compiler to never inline a given function. @@ -2306,10 +2359,12 @@ using ::std::tuple_size; #endif // _LIBCPP_VERSION is defined by the libc++ library from the LLVM project. -#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) -# define GTEST_HAS_CXXABI_H_ 1 -#else -# define GTEST_HAS_CXXABI_H_ 0 +#if !defined(GTEST_HAS_CXXABI_H_) +# if defined(__GLIBCXX__) || (defined(_LIBCPP_VERSION) && !defined(_MSC_VER)) +# define GTEST_HAS_CXXABI_H_ 1 +# else +# define GTEST_HAS_CXXABI_H_ 0 +# endif #endif // A function level attribute to disable checking for use of uninitialized @@ -2452,6 +2507,16 @@ struct StaticAssertTypeEqHelper { enum { value = true }; }; +// Same as std::is_same<>. +template +struct IsSame { + enum { value = false }; +}; +template +struct IsSame { + enum { value = true }; +}; + // Evaluates to the number of elements in 'array'. #define GTEST_ARRAY_SIZE_(array) (sizeof(array) / sizeof(array[0])) @@ -2521,6 +2586,10 @@ static void swap(scoped_ptr& a, scoped_ptr& b) { // Defines RE. +#if GTEST_USES_PCRE +// if used, PCRE is injected by custom/gtest-port.h +#elif GTEST_USES_POSIX_RE || GTEST_USES_SIMPLE_RE + // A simple C++ wrapper for . It uses the POSIX Extended // Regular Expression syntax. class GTEST_API_ RE { @@ -2532,11 +2601,11 @@ class GTEST_API_ RE { // Constructs an RE from a string. RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT -#if GTEST_HAS_GLOBAL_STRING +# if GTEST_HAS_GLOBAL_STRING RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT -#endif // GTEST_HAS_GLOBAL_STRING +# endif // GTEST_HAS_GLOBAL_STRING RE(const char* regex) { Init(regex); } // NOLINT ~RE(); @@ -2549,7 +2618,7 @@ class GTEST_API_ RE { // PartialMatch(str, re) returns true iff regular expression re // matches a substring of str (including str itself). // - // TODO(wan@google.com): make FullMatch() and PartialMatch() work + // FIXME: make FullMatch() and PartialMatch() work // when str contains NUL characters. static bool FullMatch(const ::std::string& str, const RE& re) { return FullMatch(str.c_str(), re); @@ -2558,7 +2627,7 @@ class GTEST_API_ RE { return PartialMatch(str.c_str(), re); } -#if GTEST_HAS_GLOBAL_STRING +# if GTEST_HAS_GLOBAL_STRING static bool FullMatch(const ::string& str, const RE& re) { return FullMatch(str.c_str(), re); @@ -2567,7 +2636,7 @@ class GTEST_API_ RE { return PartialMatch(str.c_str(), re); } -#endif // GTEST_HAS_GLOBAL_STRING +# endif // GTEST_HAS_GLOBAL_STRING static bool FullMatch(const char* str, const RE& re); static bool PartialMatch(const char* str, const RE& re); @@ -2576,25 +2645,27 @@ class GTEST_API_ RE { void Init(const char* regex); // We use a const char* instead of an std::string, as Google Test used to be - // used where std::string is not available. TODO(wan@google.com): change to + // used where std::string is not available. FIXME: change to // std::string. const char* pattern_; bool is_valid_; -#if GTEST_USES_POSIX_RE +# if GTEST_USES_POSIX_RE regex_t full_regex_; // For FullMatch(). regex_t partial_regex_; // For PartialMatch(). -#else // GTEST_USES_SIMPLE_RE +# else // GTEST_USES_SIMPLE_RE const char* full_pattern_; // For FullMatch(); -#endif +# endif GTEST_DISALLOW_ASSIGN_(RE); }; +#endif // GTEST_USES_PCRE + // Formats a source file path and a line number as they would appear // in an error message from the compiler used to compile this code. GTEST_API_ ::std::string FormatFileLocation(const char* file, int line); @@ -2680,13 +2751,59 @@ inline void FlushInfoLog() { fflush(NULL); } GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ << gtest_error +// Adds reference to a type if it is not a reference type, +// otherwise leaves it unchanged. This is the same as +// tr1::add_reference, which is not widely available yet. +template +struct AddReference { typedef T& type; }; // NOLINT +template +struct AddReference { typedef T& type; }; // NOLINT + +// A handy wrapper around AddReference that works when the argument T +// depends on template parameters. +#define GTEST_ADD_REFERENCE_(T) \ + typename ::testing::internal::AddReference::type + +// Transforms "T" into "const T&" according to standard reference collapsing +// rules (this is only needed as a backport for C++98 compilers that do not +// support reference collapsing). Specifically, it transforms: +// +// char ==> const char& +// const char ==> const char& +// char& ==> char& +// const char& ==> const char& +// +// Note that the non-const reference will not have "const" added. This is +// standard, and necessary so that "T" can always bind to "const T&". +template +struct ConstRef { typedef const T& type; }; +template +struct ConstRef { typedef T& type; }; + +// The argument T must depend on some template parameters. +#define GTEST_REFERENCE_TO_CONST_(T) \ + typename ::testing::internal::ConstRef::type + #if GTEST_HAS_STD_MOVE_ +using std::forward; using std::move; + +template +struct RvalueRef { + typedef T&& type; +}; #else // GTEST_HAS_STD_MOVE_ template const T& move(const T& t) { return t; } +template +GTEST_ADD_REFERENCE_(T) forward(GTEST_ADD_REFERENCE_(T) t) { return t; } + +template +struct RvalueRef { + typedef const T& type; +}; #endif // GTEST_HAS_STD_MOVE_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. @@ -2787,10 +2904,6 @@ GTEST_API_ void CaptureStderr(); GTEST_API_ std::string GetCapturedStderr(); #endif // GTEST_HAS_STREAM_REDIRECTION - -// Returns a path to temporary directory. -GTEST_API_ std::string TempDir(); - // Returns the size (in bytes) of a file. GTEST_API_ size_t GetFileSize(FILE* file); @@ -2798,14 +2911,18 @@ GTEST_API_ size_t GetFileSize(FILE* file); GTEST_API_ std::string ReadEntireFile(FILE* file); // All command line arguments. -GTEST_API_ const ::std::vector& GetArgvs(); +GTEST_API_ std::vector GetArgvs(); #if GTEST_HAS_DEATH_TEST -const ::std::vector& GetInjectableArgvs(); -void SetInjectableArgvs(const ::std::vector* - new_argvs); - +std::vector GetInjectableArgvs(); +// Deprecated: pass the args vector by value instead. +void SetInjectableArgvs(const std::vector* new_argvs); +void SetInjectableArgvs(const std::vector& new_argvs); +#if GTEST_HAS_GLOBAL_STRING +void SetInjectableArgvs(const std::vector< ::string>& new_argvs); +#endif // GTEST_HAS_GLOBAL_STRING +void ClearInjectableArgvs(); #endif // GTEST_HAS_DEATH_TEST @@ -3055,7 +3172,7 @@ class GTEST_API_ Mutex { // Initializes owner_thread_id_ and critical_section_ in static mutexes. void ThreadSafeLazyInit(); - // Per http://blogs.msdn.com/b/oldnewthing/archive/2004/02/23/78395.aspx, + // Per https://blogs.msdn.microsoft.com/oldnewthing/20040223-00/?p=40503, // we assume that 0 is an invalid value for thread IDs. unsigned int owner_thread_id_; @@ -3339,8 +3456,13 @@ class MutexBase { extern ::testing::internal::MutexBase mutex // Defines and statically (i.e. at link time) initializes a static mutex. -# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ - ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false, pthread_t() } +// The initialization list here does not explicitly initialize each field, +// instead relying on default initialization for the unspecified fields. In +// particular, the owner_ field (a pthread_t) is not explicitly initialized. +// This allows initialization to work whether pthread_t is a scalar or struct. +// The flag -Wmissing-field-initializers must not be specified for this to work. +#define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::MutexBase mutex = {PTHREAD_MUTEX_INITIALIZER, false, 0} // The Mutex class can only be used for mutexes created at runtime. It // shares its API with MutexBase otherwise. @@ -3397,7 +3519,7 @@ extern "C" inline void DeleteThreadLocalValue(void* value_holder) { // Implements thread-local storage on pthreads-based systems. template -class ThreadLocal { +class GTEST_API_ ThreadLocal { public: ThreadLocal() : key_(CreateKey()), default_factory_(new DefaultValueHolderFactory()) {} @@ -3529,7 +3651,7 @@ class GTestMutexLock { typedef GTestMutexLock MutexLock; template -class ThreadLocal { +class GTEST_API_ ThreadLocal { public: ThreadLocal() : value_() {} explicit ThreadLocal(const T& value) : value_(value) {} @@ -3548,12 +3670,13 @@ class ThreadLocal { GTEST_API_ size_t GetThreadCount(); // Passing non-POD classes through ellipsis (...) crashes the ARM -// compiler and generates a warning in Sun Studio. The Nokia Symbian +// compiler and generates a warning in Sun Studio before 12u4. The Nokia Symbian // and the IBM XL C/C++ compiler try to instantiate a copy constructor // for objects passed through ellipsis (...), failing for uncopyable // objects. We define this to ensure that only POD is passed through // ellipsis on these systems. -#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC) +#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || \ + (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x5130) // We lose support for NULL detection where the compiler doesn't like // passing non-POD classes through ellipsis (...). # define GTEST_ELLIPSIS_NEEDS_POD_ 1 @@ -3579,6 +3702,13 @@ template const bool bool_constant::value; typedef bool_constant false_type; typedef bool_constant true_type; +template +struct is_same : public false_type {}; + +template +struct is_same : public true_type {}; + + template struct is_pointer : public false_type {}; @@ -3590,6 +3720,7 @@ struct IteratorTraits { typedef typename Iterator::value_type value_type; }; + template struct IteratorTraits { typedef T value_type; @@ -3721,7 +3852,7 @@ inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } // Functions deprecated by MSVC 8.0. -GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996 /* deprecated function */) +GTEST_DISABLE_MSC_DEPRECATED_PUSH_() inline const char* StrNCpy(char* dest, const char* src, size_t n) { return strncpy(dest, src, n); @@ -3769,7 +3900,7 @@ inline const char* GetEnv(const char* name) { #endif } -GTEST_DISABLE_MSC_WARNINGS_POP_() +GTEST_DISABLE_MSC_DEPRECATED_POP_() #if GTEST_OS_WINDOWS_MOBILE // Windows CE has no C library. The abort() function is used in @@ -3885,15 +4016,15 @@ typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. # define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) # define GTEST_DECLARE_int32_(name) \ GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) -#define GTEST_DECLARE_string_(name) \ +# define GTEST_DECLARE_string_(name) \ GTEST_API_ extern ::std::string GTEST_FLAG(name) // Macros for defining flags. -#define GTEST_DEFINE_bool_(name, default_val, doc) \ +# define GTEST_DEFINE_bool_(name, default_val, doc) \ GTEST_API_ bool GTEST_FLAG(name) = (default_val) -#define GTEST_DEFINE_int32_(name, default_val, doc) \ +# define GTEST_DEFINE_int32_(name, default_val, doc) \ GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) -#define GTEST_DEFINE_string_(name, default_val, doc) \ +# define GTEST_DEFINE_string_(name, default_val, doc) \ GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val) #endif // !defined(GTEST_DECLARE_bool_) @@ -3907,7 +4038,7 @@ typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. // Parses 'str' for a 32-bit signed integer. If successful, writes the result // to *value and returns true; otherwise leaves *value unchanged and returns // false. -// TODO(chandlerc): Find a better way to refactor flag and environment parsing +// FIXME: Find a better way to refactor flag and environment parsing // out of both gtest-port.cc and gtest.cc to avoid exporting this utility // function. bool ParseInt32(const Message& src_text, const char* str, Int32* value); @@ -3916,7 +4047,8 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value); // corresponding to the given Google Test flag. bool BoolFromGTestEnv(const char* flag, bool default_val); GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); -std::string StringFromGTestEnv(const char* flag, const char* default_val); +std::string OutputFlagAlsoCheckEnvVar(); +const char* StringFromGTestEnv(const char* flag, const char* default_val); } // namespace internal } // namespace testing @@ -3972,10 +4104,9 @@ std::string StringFromGTestEnv(const char* flag, const char* default_val); // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + // -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines the Message class. // @@ -3989,12 +4120,17 @@ std::string StringFromGTestEnv(const char* flag, const char* default_val); // to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user // program! +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ #define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ #include +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + // Ensures that there is at least one operator<< in the global namespace. // See Message& operator<<(...) below for why. void operator<<(const testing::internal::Secret&, int); @@ -4141,7 +4277,6 @@ class GTEST_API_ Message { std::string GetString() const; private: - #if GTEST_OS_SYMBIAN // These are needed as the Nokia Symbian Compiler cannot decide between // const T& and const T* in a function template. The Nokia compiler _can_ @@ -4192,8 +4327,10 @@ std::string StreamableToString(const T& streamable) { } // namespace internal } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ -// Copyright 2005, Google Inc. +// Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -4222,17 +4359,59 @@ std::string StreamableToString(const T& streamable) { // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) +// Google Test filepath utilities +// +// This header file declares classes and functions used internally by +// Google Test. They are subject to change without notice. +// +// This file is #included in gtest/internal/gtest-internal.h. +// Do not include this header file separately! + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ + +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file declares the String class and functions used internally by // Google Test. They are subject to change without notice. They should not used // by code external to Google Test. // -// This header file is #included by . +// This header file is #included by gtest-internal.h. // It should not be #included by other files. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ @@ -4359,48 +4538,9 @@ GTEST_API_ std::string StringStreamToString(::std::stringstream* stream); } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: keith.ray@gmail.com (Keith Ray) -// -// Google Test filepath utilities -// -// This header file declares classes and functions used internally by -// Google Test. They are subject to change without notice. -// -// This file is #included in . -// Do not include this header file separately! - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) namespace testing { namespace internal { @@ -4563,6 +4703,8 @@ class GTEST_API_ FilePath { } // namespace internal } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ // This file was GENERATED by command: // pump.py gtest-type-util.h.pump @@ -4596,8 +4738,7 @@ class GTEST_API_ FilePath { // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan) + // Type utilities needed for implementing typed and type-parameterized // tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! @@ -4607,6 +4748,8 @@ class GTEST_API_ FilePath { // Please contact googletestframework@googlegroups.com if you need // more. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ @@ -4622,6 +4765,22 @@ class GTEST_API_ FilePath { namespace testing { namespace internal { +// Canonicalizes a given name with respect to the Standard C++ Library. +// This handles removing the inline namespace within `std` that is +// used by various standard libraries (e.g., `std::__1`). Names outside +// of namespace std are returned unmodified. +inline std::string CanonicalizeForStdLibVersioning(std::string s) { + static const char prefix[] = "std::__"; + if (s.compare(0, strlen(prefix), prefix) == 0) { + std::string::size_type end = s.find("::", strlen(prefix)); + if (end != s.npos) { + // Erase everything between the initial `std` and the second `::`. + s.erase(strlen("std"), end - strlen("std")); + } + } + return s; +} + // GetTypeName() returns a human-readable name of type T. // NB: This function is also used in Google Mock, so don't move it inside of // the typed-test-only section below. @@ -4640,7 +4799,7 @@ std::string GetTypeName() { char* const readable_name = __cxa_demangle(name, 0, 0, &status); const std::string name_str(status == 0 ? readable_name : name); free(readable_name); - return name_str; + return CanonicalizeForStdLibVersioning(name_str); # else return name; # endif // GTEST_HAS_CXXABI_H_ || __HP_aCC @@ -7906,6 +8065,9 @@ struct TypeList* dest); +// The default argument to the template below for the case when the user does +// not provide a name generator. +struct DefaultNameGenerator { + template + static std::string GetName(int i) { + return StreamableToString(i); + } +}; + +template +struct NameGeneratorSelector { + typedef Provided type; +}; + +template +void GenerateNamesRecursively(Types0, std::vector*, int) {} + +template +void GenerateNamesRecursively(Types, std::vector* result, int i) { + result->push_back(NameGenerator::template GetName(i)); + GenerateNamesRecursively(typename Types::Tail(), result, + i + 1); +} + +template +std::vector GenerateNames() { + std::vector result; + GenerateNamesRecursively(Types(), &result, 0); + return result; +} + // TypeParameterizedTest::Register() // registers a list of type-parameterized tests with Google Test. The // return value is insignificant - we just need to return something @@ -8457,10 +8640,10 @@ class TypeParameterizedTest { // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase, // Types). Valid values for 'index' are [0, N - 1] where N is the // length of Types. - static bool Register(const char* prefix, - CodeLocation code_location, - const char* case_name, const char* test_names, - int index) { + static bool Register(const char* prefix, const CodeLocation& code_location, + const char* case_name, const char* test_names, int index, + const std::vector& type_names = + GenerateNames()) { typedef typename Types::Head Type; typedef Fixture FixtureClass; typedef typename GTEST_BIND_(TestSel, Type) TestClass; @@ -8468,20 +8651,23 @@ class TypeParameterizedTest { // First, registers the first type-parameterized test in the type // list. MakeAndRegisterTestInfo( - (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/" - + StreamableToString(index)).c_str(), + (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + + "/" + type_names[index]) + .c_str(), StripTrailingSpaces(GetPrefixUntilComma(test_names)).c_str(), GetTypeName().c_str(), NULL, // No value parameter. - code_location, - GetTypeId(), - TestClass::SetUpTestCase, - TestClass::TearDownTestCase, - new TestFactoryImpl); + code_location, GetTypeId(), TestClass::SetUpTestCase, + TestClass::TearDownTestCase, new TestFactoryImpl); // Next, recurses (at compile time) with the tail of the type list. - return TypeParameterizedTest - ::Register(prefix, code_location, case_name, test_names, index + 1); + return TypeParameterizedTest::Register(prefix, + code_location, + case_name, + test_names, + index + 1, + type_names); } }; @@ -8489,9 +8675,11 @@ class TypeParameterizedTest { template class TypeParameterizedTest { public: - static bool Register(const char* /*prefix*/, CodeLocation, + static bool Register(const char* /*prefix*/, const CodeLocation&, const char* /*case_name*/, const char* /*test_names*/, - int /*index*/) { + int /*index*/, + const std::vector& = + std::vector() /*type_names*/) { return true; } }; @@ -8504,8 +8692,10 @@ template class TypeParameterizedTestCase { public: static bool Register(const char* prefix, CodeLocation code_location, - const TypedTestCasePState* state, - const char* case_name, const char* test_names) { + const TypedTestCasePState* state, const char* case_name, + const char* test_names, + const std::vector& type_names = + GenerateNames()) { std::string test_name = StripTrailingSpaces( GetPrefixUntilComma(test_names)); if (!state->TestExists(test_name)) { @@ -8522,12 +8712,14 @@ class TypeParameterizedTestCase { // First, register the first test in 'Test' for each type in 'Types'. TypeParameterizedTest::Register( - prefix, test_location, case_name, test_names, 0); + prefix, test_location, case_name, test_names, 0, type_names); // Next, recurses (at compile time) with the tail of the test list. - return TypeParameterizedTestCase - ::Register(prefix, code_location, state, - case_name, SkipComma(test_names)); + return TypeParameterizedTestCase::Register(prefix, code_location, + state, case_name, + SkipComma(test_names), + type_names); } }; @@ -8535,9 +8727,11 @@ class TypeParameterizedTestCase { template class TypeParameterizedTestCase { public: - static bool Register(const char* /*prefix*/, CodeLocation, + static bool Register(const char* /*prefix*/, const CodeLocation&, const TypedTestCasePState* /*state*/, - const char* /*case_name*/, const char* /*test_names*/) { + const char* /*case_name*/, const char* /*test_names*/, + const std::vector& = + std::vector() /*type_names*/) { return true; } }; @@ -8654,31 +8848,6 @@ struct RemoveConst { #define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T)) -// Adds reference to a type if it is not a reference type, -// otherwise leaves it unchanged. This is the same as -// tr1::add_reference, which is not widely available yet. -template -struct AddReference { typedef T& type; }; // NOLINT -template -struct AddReference { typedef T& type; }; // NOLINT - -// A handy wrapper around AddReference that works when the argument T -// depends on template parameters. -#define GTEST_ADD_REFERENCE_(T) \ - typename ::testing::internal::AddReference::type - -// Adds a reference to const on top of T as necessary. For example, -// it transforms -// -// char ==> const char& -// const char ==> const char& -// char& ==> const char& -// const char& ==> const char& -// -// The argument T must depend on some template parameters. -#define GTEST_REFERENCE_TO_CONST_(T) \ - GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T)) - // ImplicitlyConvertible::value is a compile-time bool // constant that's true iff type From can be implicitly converted to // type To. @@ -8748,8 +8917,11 @@ struct IsAProtocolMessage // a container class by checking the type of IsContainerTest(0). // The value of the expression is insignificant. // -// Note that we look for both C::iterator and C::const_iterator. The -// reason is that C++ injects the name of a class as a member of the +// In C++11 mode we check the existence of a const_iterator and that an +// iterator is properly implemented for the container. +// +// For pre-C++11 that we look for both C::iterator and C::const_iterator. +// The reason is that C++ injects the name of a class as a member of the // class itself (e.g. you can refer to class iterator as either // 'iterator' or 'iterator::iterator'). If we look for C::iterator // only, for example, we would mistakenly think that a class named @@ -8759,17 +8931,96 @@ struct IsAProtocolMessage // IsContainerTest(typename C::const_iterator*) and // IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++. typedef int IsContainer; +#if GTEST_LANG_CXX11 +template ().begin()), + class = decltype(::std::declval().end()), + class = decltype(++::std::declval()), + class = decltype(*::std::declval()), + class = typename C::const_iterator> +IsContainer IsContainerTest(int /* dummy */) { + return 0; +} +#else template IsContainer IsContainerTest(int /* dummy */, typename C::iterator* /* it */ = NULL, typename C::const_iterator* /* const_it */ = NULL) { return 0; } +#endif // GTEST_LANG_CXX11 typedef char IsNotContainer; template IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; } +// Trait to detect whether a type T is a hash table. +// The heuristic used is that the type contains an inner type `hasher` and does +// not contain an inner type `reverse_iterator`. +// If the container is iterable in reverse, then order might actually matter. +template +struct IsHashTable { + private: + template + static char test(typename U::hasher*, typename U::reverse_iterator*); + template + static int test(typename U::hasher*, ...); + template + static char test(...); + + public: + static const bool value = sizeof(test(0, 0)) == sizeof(int); +}; + +template +const bool IsHashTable::value; + +template +struct VoidT { + typedef void value_type; +}; + +template +struct HasValueType : false_type {}; +template +struct HasValueType > : true_type { +}; + +template (0)) == sizeof(IsContainer), + bool = HasValueType::value> +struct IsRecursiveContainerImpl; + +template +struct IsRecursiveContainerImpl : public false_type {}; + +// Since the IsRecursiveContainerImpl depends on the IsContainerTest we need to +// obey the same inconsistencies as the IsContainerTest, namely check if +// something is a container is relying on only const_iterator in C++11 and +// is relying on both const_iterator and iterator otherwise +template +struct IsRecursiveContainerImpl : public false_type {}; + +template +struct IsRecursiveContainerImpl { + #if GTEST_LANG_CXX11 + typedef typename IteratorTraits::value_type + value_type; +#else + typedef typename IteratorTraits::value_type value_type; +#endif + typedef is_same type; +}; + +// IsRecursiveContainer is a unary compile-time predicate that +// evaluates whether C is a recursive container type. A recursive container +// type is a container type whose value_type is equal to the container type +// itself. An example for a recursive container type is +// boost::filesystem::path, whose iterator has a value_type that is equal to +// boost::filesystem::path. +template +struct IsRecursiveContainer : public IsRecursiveContainerImpl::type {}; + // EnableIf::type is void when 'Cond' is true, and // undefined when 'Cond' is false. To use SFINAE to make a function // overload only apply when a particular expression is true, add @@ -8901,7 +9152,7 @@ class NativeArray { private: enum { kCheckTypeIsNotConstOrAReference = StaticAssertTypeEqHelper< - Element, GTEST_REMOVE_REFERENCE_AND_CONST_(Element)>::value, + Element, GTEST_REMOVE_REFERENCE_AND_CONST_(Element)>::value }; // Initializes this object with a copy of the input. @@ -8946,7 +9197,7 @@ class NativeArray { #define GTEST_SUCCESS_(message) \ GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) -// Suppresses MSVC warnings 4072 (unreachable code) for the code following +// Suppress MSVC warning 4702 (unreachable code) for the code following // statement if it returns or throws (or doesn't return or throw in some // situations). #define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ @@ -9066,7 +9317,6 @@ ::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ - // Copyright 2005, Google Inc. // All rights reserved. // @@ -9095,14 +9345,14 @@ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + // -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines the public API for death tests. It is // #included by gtest.h so a user doesn't need to include this // directly. +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ @@ -9136,12 +9386,11 @@ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines internal utilities needed for implementing // death tests. They are subject to change without notice. +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ @@ -9161,6 +9410,9 @@ const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; #if GTEST_HAS_DEATH_TEST +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + // DeathTest is a class that hides much of the complexity of the // GTEST_DEATH_TEST_ macro. It is abstract; its static Create method // returns a concrete class that depends on the prevailing death test @@ -9244,6 +9496,8 @@ class GTEST_API_ DeathTest { GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest); }; +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + // Factory interface for death tests. May be mocked out for testing. class DeathTestFactory { public: @@ -9326,14 +9580,18 @@ GTEST_API_ bool ExitedUnsuccessfully(int exit_status); // can be streamed. // This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in -// NDEBUG mode. In this case we need the statements to be executed, the regex is -// ignored, and the macro must accept a streamed message even though the message -// is never printed. -# define GTEST_EXECUTE_STATEMENT_(statement, regex) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } else \ +// NDEBUG mode. In this case we need the statements to be executed and the macro +// must accept a streamed message even though the message is never printed. +// The regex object is not evaluated, but it is used to prevent "unused" +// warnings and to avoid an expression that doesn't compile in debug mode. +#define GTEST_EXECUTE_STATEMENT_(statement, regex) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } else if (!::testing::internal::AlwaysTrue()) { \ + const ::testing::internal::RE& gtest_regex = (regex); \ + static_cast(gtest_regex); \ + } else \ ::testing::Message() // A class representing the parsed contents of the @@ -9372,53 +9630,6 @@ class InternalRunDeathTestFlag { // the flag is specified; otherwise returns NULL. InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); -#else // GTEST_HAS_DEATH_TEST - -// This macro is used for implementing macros such as -// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where -// death tests are not supported. Those macros must compile on such systems -// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on -// systems that support death tests. This allows one to write such a macro -// on a system that does not support death tests and be sure that it will -// compile on a death-test supporting system. -// -// Parameters: -// statement - A statement that a macro such as EXPECT_DEATH would test -// for program termination. This macro has to make sure this -// statement is compiled but not executed, to ensure that -// EXPECT_DEATH_IF_SUPPORTED compiles with a certain -// parameter iff EXPECT_DEATH compiles with it. -// regex - A regex that a macro such as EXPECT_DEATH would use to test -// the output of statement. This parameter has to be -// compiled but not evaluated by this macro, to ensure that -// this macro only accepts expressions that a macro such as -// EXPECT_DEATH would accept. -// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED -// and a return statement for ASSERT_DEATH_IF_SUPPORTED. -// This ensures that ASSERT_DEATH_IF_SUPPORTED will not -// compile inside functions where ASSERT_DEATH doesn't -// compile. -// -// The branch that has an always false condition is used to ensure that -// statement and regex are compiled (and thus syntactically correct) but -// never executed. The unreachable code macro protects the terminator -// statement from generating an 'unreachable code' warning in case -// statement unconditionally returns or throws. The Message constructor at -// the end allows the syntax of streaming additional messages into the -// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. -# define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - GTEST_LOG_(WARNING) \ - << "Death tests are not supported on this platform.\n" \ - << "Statement '" #statement "' cannot be verified."; \ - } else if (::testing::internal::AlwaysFalse()) { \ - ::testing::internal::RE::PartialMatch(".*", (regex)); \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - terminator; \ - } else \ - ::testing::Message() - #endif // GTEST_HAS_DEATH_TEST } // namespace internal @@ -9485,10 +9696,11 @@ GTEST_API_ bool InDeathTestChild(); // // On the regular expressions used in death tests: // +// GOOGLETEST_CM0005 DO NOT DELETE // On POSIX-compliant systems (*nix), we use the library, // which uses the POSIX extended regex syntax. // -// On other platforms (e.g. Windows), we only support a simple regex +// On other platforms (e.g. Windows or Mac), we only support a simple regex // syntax implemented as part of Google Test. This limited // implementation should be enough most of the time when writing // death tests; though it lacks many features you can find in PCRE @@ -9546,7 +9758,7 @@ GTEST_API_ bool InDeathTestChild(); // is rarely a problem as people usually don't put the test binary // directory in PATH. // -// TODO(wan@google.com): make thread-safe death tests search the PATH. +// FIXME: make thread-safe death tests search the PATH. // Asserts that a given statement causes the program to exit, with an // integer exit status that satisfies predicate, and emitting error output @@ -9584,9 +9796,10 @@ class GTEST_API_ ExitedWithCode { const int exit_code_; }; -# if !GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // Tests that an exit code describes an exit due to termination by a // given signal. +// GOOGLETEST_CM0006 DO NOT DELETE class GTEST_API_ KilledBySignal { public: explicit KilledBySignal(int signum); @@ -9658,6 +9871,54 @@ class GTEST_API_ KilledBySignal { # endif // NDEBUG for EXPECT_DEBUG_DEATH #endif // GTEST_HAS_DEATH_TEST +// This macro is used for implementing macros such as +// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where +// death tests are not supported. Those macros must compile on such systems +// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on +// systems that support death tests. This allows one to write such a macro +// on a system that does not support death tests and be sure that it will +// compile on a death-test supporting system. It is exposed publicly so that +// systems that have death-tests with stricter requirements than +// GTEST_HAS_DEATH_TEST can write their own equivalent of +// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED. +// +// Parameters: +// statement - A statement that a macro such as EXPECT_DEATH would test +// for program termination. This macro has to make sure this +// statement is compiled but not executed, to ensure that +// EXPECT_DEATH_IF_SUPPORTED compiles with a certain +// parameter iff EXPECT_DEATH compiles with it. +// regex - A regex that a macro such as EXPECT_DEATH would use to test +// the output of statement. This parameter has to be +// compiled but not evaluated by this macro, to ensure that +// this macro only accepts expressions that a macro such as +// EXPECT_DEATH would accept. +// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED +// and a return statement for ASSERT_DEATH_IF_SUPPORTED. +// This ensures that ASSERT_DEATH_IF_SUPPORTED will not +// compile inside functions where ASSERT_DEATH doesn't +// compile. +// +// The branch that has an always false condition is used to ensure that +// statement and regex are compiled (and thus syntactically correct) but +// never executed. The unreachable code macro protects the terminator +// statement from generating an 'unreachable code' warning in case +// statement unconditionally returns or throws. The Message constructor at +// the end allows the syntax of streaming additional messages into the +// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. +# define GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, terminator) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_LOG_(WARNING) \ + << "Death tests are not supported on this platform.\n" \ + << "Statement '" #statement "' cannot be verified."; \ + } else if (::testing::internal::AlwaysFalse()) { \ + ::testing::internal::RE::PartialMatch(".*", (regex)); \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + terminator; \ + } else \ + ::testing::Message() + // EXPECT_DEATH_IF_SUPPORTED(statement, regex) and // ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if // death tests are supported; otherwise they just issue a warning. This is @@ -9670,9 +9931,9 @@ class GTEST_API_ KilledBySignal { ASSERT_DEATH(statement, regex) #else # define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ - GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, ) + GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, ) # define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ - GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return) + GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, return) #endif } // namespace testing @@ -9711,13 +9972,12 @@ class GTEST_API_ KilledBySignal { // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: vladl@google.com (Vlad Losev) -// // Macros and functions for implementing parameterized tests -// in Google C++ Testing Framework (Google Test) +// in Google C++ Testing and Mocking Framework (Google Test) // // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ @@ -9759,7 +10019,7 @@ TEST_P(FooTest, HasBlahBlah) { // Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test // case with any set of parameters you want. Google Test defines a number // of functions for generating test parameters. They return what we call -// (surprise!) parameter generators. Here is a summary of them, which +// (surprise!) parameter generators. Here is a summary of them, which // are all in the testing namespace: // // @@ -9864,9 +10124,6 @@ TEST_P(DerivedTest, DoesBlah) { # include #endif -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. // Copyright 2008 Google Inc. // All Rights Reserved. // @@ -9895,11 +10152,12 @@ TEST_P(DerivedTest, DoesBlah) { // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: vladl@google.com (Vlad Losev) + // Type and function utilities for implementing parameterized tests. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ @@ -9910,9 +10168,6 @@ TEST_P(DerivedTest, DoesBlah) { #include #include -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. // Copyright 2003 Google Inc. // All rights reserved. // @@ -9942,8 +10197,6 @@ TEST_P(DerivedTest, DoesBlah) { // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: Dan Egnor (egnor@google.com) -// // A "smart" pointer type with reference tracking. Every pointer to a // particular object is kept on a circular linked list. When the last pointer // to an object is destroyed or reassigned, the object is deleted. @@ -9977,9 +10230,11 @@ TEST_P(DerivedTest, DoesBlah) { // raw pointer (e.g. via get()) concurrently, and // - it's safe to write to two linked_ptrs that point to the same // shared object concurrently. -// TODO(wan@google.com): rename this to safe_linked_ptr to avoid +// FIXME: rename this to safe_linked_ptr to avoid // confusion with normal linked_ptr. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ @@ -10183,10 +10438,9 @@ linked_ptr make_linked_ptr(T* ptr) { // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan) -// Google Test - The Google C++ Testing Framework + +// Google Test - The Google C++ Testing and Mocking Framework // // This file implements a universal value printer that can print a // value of any type T: @@ -10203,6 +10457,10 @@ linked_ptr make_linked_ptr(T* ptr) { // 2. operator<<(ostream&, const T&) defined in either foo or the // global namespace. // +// However if T is an STL-style container then it is printed element-wise +// unless foo::PrintTo(const T&, ostream*) is defined. Note that +// operator<<() is ignored for container types. +// // If none of the above is defined, it will print the debug string of // the value if it is a protocol buffer, or print the raw bytes in the // value otherwise. @@ -10249,6 +10507,8 @@ linked_ptr make_linked_ptr(T* ptr) { // being defined as many user-defined container types don't have // value_type. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ #define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ @@ -10262,6 +10522,16 @@ linked_ptr make_linked_ptr(T* ptr) { # include #endif +#ifndef GTEST_HAS_ABSL +#define GTEST_HAS_ABSL 0 +#endif + +#if GTEST_HAS_ABSL +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "absl/types/variant.h" +#endif // GTEST_HAS_ABSL + namespace testing { // Definitions in the 'internal' and 'internal2' name spaces are @@ -10280,7 +10550,11 @@ enum TypeKind { kProtobuf, // a protobuf type kConvertibleToInteger, // a type implicitly convertible to BiggestInt // (e.g. a named or unnamed enum type) - kOtherType // anything else +#if GTEST_HAS_ABSL + kConvertibleToStringView, // a type implicitly convertible to + // absl::string_view +#endif + kOtherType // anything else }; // TypeWithoutFormatter::PrintValue(value, os) is called @@ -10292,7 +10566,8 @@ class TypeWithoutFormatter { public: // This default version is called when kTypeKind is kOtherType. static void PrintValue(const T& value, ::std::ostream* os) { - PrintBytesInObjectTo(reinterpret_cast(&value), + PrintBytesInObjectTo(static_cast( + reinterpret_cast(&value)), sizeof(value), os); } }; @@ -10306,10 +10581,10 @@ template class TypeWithoutFormatter { public: static void PrintValue(const T& value, ::std::ostream* os) { - const ::testing::internal::string short_str = value.ShortDebugString(); - const ::testing::internal::string pretty_str = - short_str.length() <= kProtobufOneLinerMaxLength ? - short_str : ("\n" + value.DebugString()); + std::string pretty_str = value.ShortDebugString(); + if (pretty_str.length() > kProtobufOneLinerMaxLength) { + pretty_str = "\n" + value.DebugString(); + } *os << ("<" + pretty_str + ">"); } }; @@ -10330,6 +10605,19 @@ class TypeWithoutFormatter { } }; +#if GTEST_HAS_ABSL +template +class TypeWithoutFormatter { + public: + // Since T has neither operator<< nor PrintTo() but can be implicitly + // converted to absl::string_view, we print it as a absl::string_view. + // + // Note: the implementation is further below, as it depends on + // internal::PrintTo symbol which is defined later in the file. + static void PrintValue(const T& value, ::std::ostream* os); +}; +#endif + // Prints the given value to the given ostream. If the value is a // protocol message, its debug string is printed; if it's an enum or // of a type implicitly convertible to BiggestInt, it's printed as an @@ -10357,10 +10645,19 @@ class TypeWithoutFormatter { template ::std::basic_ostream& operator<<( ::std::basic_ostream& os, const T& x) { - TypeWithoutFormatter::value ? kProtobuf : - internal::ImplicitlyConvertible::value ? - kConvertibleToInteger : kOtherType)>::PrintValue(x, &os); + TypeWithoutFormatter::value + ? kProtobuf + : internal::ImplicitlyConvertible< + const T&, internal::BiggestInt>::value + ? kConvertibleToInteger + : +#if GTEST_HAS_ABSL + internal::ImplicitlyConvertible< + const T&, absl::string_view>::value + ? kConvertibleToStringView + : +#endif + kOtherType)>::PrintValue(x, &os); return os; } @@ -10519,11 +10816,18 @@ class UniversalPrinter; template void UniversalPrint(const T& value, ::std::ostream* os); +enum DefaultPrinterType { + kPrintContainer, + kPrintPointer, + kPrintFunctionPointer, + kPrintOther, +}; +template struct WrapPrinterType {}; + // Used to print an STL-style container when the user doesn't define // a PrintTo() for it. template -void DefaultPrintTo(IsContainer /* dummy */, - false_type /* is not a pointer */, +void DefaultPrintTo(WrapPrinterType /* dummy */, const C& container, ::std::ostream* os) { const size_t kMaxCount = 32; // The maximum number of elements to print. *os << '{'; @@ -10556,40 +10860,34 @@ void DefaultPrintTo(IsContainer /* dummy */, // implementation-defined. Therefore they will be printed as raw // bytes.) template -void DefaultPrintTo(IsNotContainer /* dummy */, - true_type /* is a pointer */, +void DefaultPrintTo(WrapPrinterType /* dummy */, T* p, ::std::ostream* os) { if (p == NULL) { *os << "NULL"; } else { - // C++ doesn't allow casting from a function pointer to any object - // pointer. - // - // IsTrue() silences warnings: "Condition is always true", - // "unreachable code". - if (IsTrue(ImplicitlyConvertible::value)) { - // T is not a function type. We just call << to print p, - // relying on ADL to pick up user-defined << for their pointer - // types, if any. - *os << p; - } else { - // T is a function type, so '*os << p' doesn't do what we want - // (it just prints p as bool). We want to print p as a const - // void*. However, we cannot cast it to const void* directly, - // even using reinterpret_cast, as earlier versions of gcc - // (e.g. 3.4.5) cannot compile the cast when p is a function - // pointer. Casting to UInt64 first solves the problem. - *os << reinterpret_cast( - reinterpret_cast(p)); - } + // T is not a function type. We just call << to print p, + // relying on ADL to pick up user-defined << for their pointer + // types, if any. + *os << p; + } +} +template +void DefaultPrintTo(WrapPrinterType /* dummy */, + T* p, ::std::ostream* os) { + if (p == NULL) { + *os << "NULL"; + } else { + // T is a function type, so '*os << p' doesn't do what we want + // (it just prints p as bool). We want to print p as a const + // void*. + *os << reinterpret_cast(p); } } // Used to print a non-container, non-pointer value when the user // doesn't define PrintTo() for it. template -void DefaultPrintTo(IsNotContainer /* dummy */, - false_type /* is not a pointer */, +void DefaultPrintTo(WrapPrinterType /* dummy */, const T& value, ::std::ostream* os) { ::testing_internal::DefaultPrintNonContainerTo(value, os); } @@ -10607,11 +10905,8 @@ void DefaultPrintTo(IsNotContainer /* dummy */, // wants). template void PrintTo(const T& value, ::std::ostream* os) { - // DefaultPrintTo() is overloaded. The type of its first two - // arguments determine which version will be picked. If T is an - // STL-style container, the version for container will be called; if - // T is a pointer, the pointer version will be called; otherwise the - // generic version will be called. + // DefaultPrintTo() is overloaded. The type of its first argument + // determines which version will be picked. // // Note that we check for container types here, prior to we check // for protocol message types in our operator<<. The rationale is: @@ -10623,13 +10918,27 @@ void PrintTo(const T& value, ::std::ostream* os) { // elements; therefore we check for container types here to ensure // that our format is used. // - // The second argument of DefaultPrintTo() is needed to bypass a bug - // in Symbian's C++ compiler that prevents it from picking the right - // overload between: - // - // PrintTo(const T& x, ...); - // PrintTo(T* x, ...); - DefaultPrintTo(IsContainerTest(0), is_pointer(), value, os); + // Note that MSVC and clang-cl do allow an implicit conversion from + // pointer-to-function to pointer-to-object, but clang-cl warns on it. + // So don't use ImplicitlyConvertible if it can be helped since it will + // cause this warning, and use a separate overload of DefaultPrintTo for + // function pointers so that the `*os << p` in the object pointer overload + // doesn't cause that warning either. + DefaultPrintTo( + WrapPrinterType < + (sizeof(IsContainerTest(0)) == sizeof(IsContainer)) && + !IsRecursiveContainer::value + ? kPrintContainer + : !is_pointer::value + ? kPrintOther +#if GTEST_LANG_CXX11 + : std::is_function::type>::value +#else + : !internal::ImplicitlyConvertible::value +#endif + ? kPrintFunctionPointer + : kPrintPointer > (), + value, os); } // The following list of PrintTo() overloads tells @@ -10736,6 +11045,17 @@ inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { } #endif // GTEST_HAS_STD_WSTRING +#if GTEST_HAS_ABSL +// Overload for absl::string_view. +inline void PrintTo(absl::string_view sp, ::std::ostream* os) { + PrintTo(::std::string(sp), os); +} +#endif // GTEST_HAS_ABSL + +#if GTEST_LANG_CXX11 +inline void PrintTo(std::nullptr_t, ::std::ostream* os) { *os << "(nullptr)"; } +#endif // GTEST_LANG_CXX11 + #if GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_ // Helper function for printing a tuple. T must be instantiated with // a tuple type. @@ -10865,6 +11185,48 @@ class UniversalPrinter { GTEST_DISABLE_MSC_WARNINGS_POP_() }; +#if GTEST_HAS_ABSL + +// Printer for absl::optional + +template +class UniversalPrinter<::absl::optional> { + public: + static void Print(const ::absl::optional& value, ::std::ostream* os) { + *os << '('; + if (!value) { + *os << "nullopt"; + } else { + UniversalPrint(*value, os); + } + *os << ')'; + } +}; + +// Printer for absl::variant + +template +class UniversalPrinter<::absl::variant> { + public: + static void Print(const ::absl::variant& value, ::std::ostream* os) { + *os << '('; + absl::visit(Visitor{os}, value); + *os << ')'; + } + + private: + struct Visitor { + template + void operator()(const U& u) const { + *os << "'" << GetTypeName() << "' with value "; + UniversalPrint(u, os); + } + ::std::ostream* os; + }; +}; + +#endif // GTEST_HAS_ABSL + // UniversalPrintArray(begin, len, os) prints an array of 'len' // elements, starting at address 'begin'. template @@ -10878,7 +11240,7 @@ void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { // If the array has more than kThreshold elements, we'll have to // omit some details by printing only the first and the last // kChunkSize elements. - // TODO(wan@google.com): let the user control the threshold using a flag. + // FIXME: let the user control the threshold using a flag. if (len <= kThreshold) { PrintRawArrayTo(begin, len, os); } else { @@ -10960,7 +11322,7 @@ class UniversalTersePrinter { if (str == NULL) { *os << "NULL"; } else { - UniversalPrint(string(str), os); + UniversalPrint(std::string(str), os); } } }; @@ -11011,7 +11373,7 @@ void UniversalPrint(const T& value, ::std::ostream* os) { UniversalPrinter::Print(value, os); } -typedef ::std::vector Strings; +typedef ::std::vector< ::std::string> Strings; // TuplePolicy must provide: // - tuple_size @@ -11030,12 +11392,13 @@ struct TuplePolicy { static const size_t tuple_size = ::std::tr1::tuple_size::value; template - struct tuple_element : ::std::tr1::tuple_element {}; + struct tuple_element : ::std::tr1::tuple_element(I), Tuple> { + }; template - static typename AddReference< - const typename ::std::tr1::tuple_element::type>::type get( - const Tuple& tuple) { + static typename AddReference(I), Tuple>::type>::type + get(const Tuple& tuple) { return ::std::tr1::get(tuple); } }; @@ -11131,6 +11494,16 @@ Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { } // namespace internal +#if GTEST_HAS_ABSL +namespace internal2 { +template +void TypeWithoutFormatter::PrintValue( + const T& value, ::std::ostream* os) { + internal::PrintTo(absl::string_view(value), os); +} +} // namespace internal2 +#endif + template ::std::string PrintToString(const T& value) { ::std::stringstream ss; @@ -11176,8 +11549,8 @@ ::std::string PrintToString(const T& value) { // installation of gTest. // It will be included from gtest-printers.h and the overrides in this file // will be visible to everyone. -// See documentation at gtest/gtest-printers.h for details on how to define a -// custom printer. +// +// Injection point for custom user configurations. See README for details // // ** Custom implementation starts here ** @@ -11188,8 +11561,6 @@ ::std::string PrintToString(const T& value) { #endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ -#if GTEST_HAS_PARAM_TEST - namespace testing { // Input to a parameterized test name generator, describing a test parameter. @@ -11616,7 +11987,7 @@ class ParameterizedTestCaseInfoBase { virtual ~ParameterizedTestCaseInfoBase() {} // Base part of test case name for display purposes. - virtual const string& GetTestCaseName() const = 0; + virtual const std::string& GetTestCaseName() const = 0; // Test case id to verify identity. virtual TypeId GetTestCaseTypeId() const = 0; // UnitTest class invokes this method to register tests in this @@ -11655,7 +12026,7 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { : test_case_name_(name), code_location_(code_location) {} // Test case base name for display purposes. - virtual const string& GetTestCaseName() const { return test_case_name_; } + virtual const std::string& GetTestCaseName() const { return test_case_name_; } // Test case id to verify identity. virtual TypeId GetTestCaseTypeId() const { return GetTypeId(); } // TEST_P macro uses AddTestPattern() to record information @@ -11673,11 +12044,10 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { } // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information // about a generator. - int AddTestCaseInstantiation(const string& instantiation_name, + int AddTestCaseInstantiation(const std::string& instantiation_name, GeneratorCreationFunc* func, ParamNameGeneratorFunc* name_func, - const char* file, - int line) { + const char* file, int line) { instantiations_.push_back( InstantiationInfo(instantiation_name, func, name_func, file, line)); return 0; // Return value used only to run this method in namespace scope. @@ -11694,13 +12064,13 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { for (typename InstantiationContainer::iterator gen_it = instantiations_.begin(); gen_it != instantiations_.end(); ++gen_it) { - const string& instantiation_name = gen_it->name; + const std::string& instantiation_name = gen_it->name; ParamGenerator generator((*gen_it->generator)()); ParamNameGeneratorFunc* name_func = gen_it->name_func; const char* file = gen_it->file; int line = gen_it->line; - string test_case_name; + std::string test_case_name; if ( !instantiation_name.empty() ) test_case_name = instantiation_name + "/"; test_case_name += test_info->test_case_base_name; @@ -11753,8 +12123,8 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { test_base_name(a_test_base_name), test_meta_factory(a_test_meta_factory) {} - const string test_case_base_name; - const string test_base_name; + const std::string test_case_base_name; + const std::string test_base_name; const scoped_ptr > test_meta_factory; }; typedef ::std::vector > TestInfoContainer; @@ -11795,7 +12165,7 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { return true; } - const string test_case_name_; + const std::string test_case_name_; CodeLocation code_location_; TestInfoContainer tests_; InstantiationContainer instantiations_; @@ -11870,8 +12240,6 @@ class ParameterizedTestCaseRegistry { } // namespace internal } // namespace testing -#endif // GTEST_HAS_PARAM_TEST - #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ // This file was GENERATED by command: // pump.py gtest-param-util-generated.h.pump @@ -11905,8 +12273,7 @@ class ParameterizedTestCaseRegistry { // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: vladl@google.com (Vlad Losev) + // Type and function utilities for implementing parameterized tests. // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! @@ -11918,14 +12285,11 @@ class ParameterizedTestCaseRegistry { // by the maximum arity of the implementation of tuple which is // currently set at 10. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. - -#if GTEST_HAS_PARAM_TEST namespace testing { @@ -11957,6 +12321,8 @@ class ValueArray1 { return ValuesIn(array); } + ValueArray1(const ValueArray1& other) : v1_(other.v1_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray1& other); @@ -11975,6 +12341,8 @@ class ValueArray2 { return ValuesIn(array); } + ValueArray2(const ValueArray2& other) : v1_(other.v1_), v2_(other.v2_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray2& other); @@ -11995,6 +12363,9 @@ class ValueArray3 { return ValuesIn(array); } + ValueArray3(const ValueArray3& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray3& other); @@ -12017,6 +12388,9 @@ class ValueArray4 { return ValuesIn(array); } + ValueArray4(const ValueArray4& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray4& other); @@ -12040,6 +12414,9 @@ class ValueArray5 { return ValuesIn(array); } + ValueArray5(const ValueArray5& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray5& other); @@ -12066,6 +12443,9 @@ class ValueArray6 { return ValuesIn(array); } + ValueArray6(const ValueArray6& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray6& other); @@ -12093,6 +12473,10 @@ class ValueArray7 { return ValuesIn(array); } + ValueArray7(const ValueArray7& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray7& other); @@ -12122,6 +12506,10 @@ class ValueArray8 { return ValuesIn(array); } + ValueArray8(const ValueArray8& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray8& other); @@ -12153,6 +12541,10 @@ class ValueArray9 { return ValuesIn(array); } + ValueArray9(const ValueArray9& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray9& other); @@ -12185,6 +12577,10 @@ class ValueArray10 { return ValuesIn(array); } + ValueArray10(const ValueArray10& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray10& other); @@ -12219,6 +12615,11 @@ class ValueArray11 { return ValuesIn(array); } + ValueArray11(const ValueArray11& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray11& other); @@ -12255,6 +12656,11 @@ class ValueArray12 { return ValuesIn(array); } + ValueArray12(const ValueArray12& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray12& other); @@ -12293,6 +12699,11 @@ class ValueArray13 { return ValuesIn(array); } + ValueArray13(const ValueArray13& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray13& other); @@ -12332,6 +12743,11 @@ class ValueArray14 { return ValuesIn(array); } + ValueArray14(const ValueArray14& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray14& other); @@ -12373,6 +12789,12 @@ class ValueArray15 { return ValuesIn(array); } + ValueArray15(const ValueArray15& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray15& other); @@ -12417,6 +12839,12 @@ class ValueArray16 { return ValuesIn(array); } + ValueArray16(const ValueArray16& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray16& other); @@ -12462,6 +12890,12 @@ class ValueArray17 { return ValuesIn(array); } + ValueArray17(const ValueArray17& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray17& other); @@ -12509,6 +12943,12 @@ class ValueArray18 { return ValuesIn(array); } + ValueArray18(const ValueArray18& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray18& other); @@ -12557,6 +12997,13 @@ class ValueArray19 { return ValuesIn(array); } + ValueArray19(const ValueArray19& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray19& other); @@ -12607,6 +13054,13 @@ class ValueArray20 { return ValuesIn(array); } + ValueArray20(const ValueArray20& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray20& other); @@ -12660,6 +13114,13 @@ class ValueArray21 { return ValuesIn(array); } + ValueArray21(const ValueArray21& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray21& other); @@ -12714,6 +13175,13 @@ class ValueArray22 { return ValuesIn(array); } + ValueArray22(const ValueArray22& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray22& other); @@ -12770,6 +13238,14 @@ class ValueArray23 { return ValuesIn(array); } + ValueArray23(const ValueArray23& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray23& other); @@ -12828,6 +13304,14 @@ class ValueArray24 { return ValuesIn(array); } + ValueArray24(const ValueArray24& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray24& other); @@ -12887,6 +13371,14 @@ class ValueArray25 { return ValuesIn(array); } + ValueArray25(const ValueArray25& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray25& other); @@ -12948,6 +13440,14 @@ class ValueArray26 { return ValuesIn(array); } + ValueArray26(const ValueArray26& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray26& other); @@ -13012,6 +13512,15 @@ class ValueArray27 { return ValuesIn(array); } + ValueArray27(const ValueArray27& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray27& other); @@ -13077,6 +13586,15 @@ class ValueArray28 { return ValuesIn(array); } + ValueArray28(const ValueArray28& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray28& other); @@ -13143,6 +13661,15 @@ class ValueArray29 { return ValuesIn(array); } + ValueArray29(const ValueArray29& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray29& other); @@ -13212,6 +13739,15 @@ class ValueArray30 { return ValuesIn(array); } + ValueArray30(const ValueArray30& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray30& other); @@ -13283,6 +13819,16 @@ class ValueArray31 { return ValuesIn(array); } + ValueArray31(const ValueArray31& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray31& other); @@ -13355,6 +13901,16 @@ class ValueArray32 { return ValuesIn(array); } + ValueArray32(const ValueArray32& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray32& other); @@ -13430,6 +13986,16 @@ class ValueArray33 { return ValuesIn(array); } + ValueArray33(const ValueArray33& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray33& other); @@ -13506,6 +14072,16 @@ class ValueArray34 { return ValuesIn(array); } + ValueArray34(const ValueArray34& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray34& other); @@ -13583,6 +14159,17 @@ class ValueArray35 { return ValuesIn(array); } + ValueArray35(const ValueArray35& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray35& other); @@ -13663,6 +14250,17 @@ class ValueArray36 { return ValuesIn(array); } + ValueArray36(const ValueArray36& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray36& other); @@ -13745,6 +14343,17 @@ class ValueArray37 { return ValuesIn(array); } + ValueArray37(const ValueArray37& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray37& other); @@ -13828,6 +14437,17 @@ class ValueArray38 { return ValuesIn(array); } + ValueArray38(const ValueArray38& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray38& other); @@ -13913,6 +14533,18 @@ class ValueArray39 { return ValuesIn(array); } + ValueArray39(const ValueArray39& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray39& other); @@ -14000,6 +14632,18 @@ class ValueArray40 { return ValuesIn(array); } + ValueArray40(const ValueArray40& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray40& other); @@ -14089,6 +14733,18 @@ class ValueArray41 { return ValuesIn(array); } + ValueArray41(const ValueArray41& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray41& other); @@ -14180,6 +14836,18 @@ class ValueArray42 { return ValuesIn(array); } + ValueArray42(const ValueArray42& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray42& other); @@ -14272,6 +14940,19 @@ class ValueArray43 { return ValuesIn(array); } + ValueArray43(const ValueArray43& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray43& other); @@ -14366,6 +15047,19 @@ class ValueArray44 { return ValuesIn(array); } + ValueArray44(const ValueArray44& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_), v44_(other.v44_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray44& other); @@ -14462,6 +15156,19 @@ class ValueArray45 { return ValuesIn(array); } + ValueArray45(const ValueArray45& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_), v44_(other.v44_), v45_(other.v45_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray45& other); @@ -14560,6 +15267,19 @@ class ValueArray46 { return ValuesIn(array); } + ValueArray46(const ValueArray46& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_), v44_(other.v44_), v45_(other.v45_), v46_(other.v46_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray46& other); @@ -14660,6 +15380,20 @@ class ValueArray47 { return ValuesIn(array); } + ValueArray47(const ValueArray47& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_), v44_(other.v44_), v45_(other.v45_), v46_(other.v46_), + v47_(other.v47_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray47& other); @@ -14762,6 +15496,20 @@ class ValueArray48 { return ValuesIn(array); } + ValueArray48(const ValueArray48& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_), v44_(other.v44_), v45_(other.v45_), v46_(other.v46_), + v47_(other.v47_), v48_(other.v48_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray48& other); @@ -14865,6 +15613,20 @@ class ValueArray49 { return ValuesIn(array); } + ValueArray49(const ValueArray49& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_), v44_(other.v44_), v45_(other.v45_), v46_(other.v46_), + v47_(other.v47_), v48_(other.v48_), v49_(other.v49_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray49& other); @@ -14969,6 +15731,20 @@ class ValueArray50 { return ValuesIn(array); } + ValueArray50(const ValueArray50& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_), v44_(other.v44_), v45_(other.v45_), v46_(other.v46_), + v47_(other.v47_), v48_(other.v48_), v49_(other.v49_), v50_(other.v50_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray50& other); @@ -15081,7 +15857,7 @@ class CartesianProductGenerator2 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -15113,7 +15889,7 @@ class CartesianProductGenerator2 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_); + current_value_.reset(new ParamType(*current1_, *current2_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -15135,7 +15911,7 @@ class CartesianProductGenerator2 const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator2::Iterator // No implementation - assignment is unsupported. @@ -15204,7 +15980,7 @@ class CartesianProductGenerator3 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -15240,7 +16016,7 @@ class CartesianProductGenerator3 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -15266,7 +16042,7 @@ class CartesianProductGenerator3 const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator3::Iterator // No implementation - assignment is unsupported. @@ -15345,7 +16121,7 @@ class CartesianProductGenerator4 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -15385,8 +16161,8 @@ class CartesianProductGenerator4 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -15416,7 +16192,7 @@ class CartesianProductGenerator4 const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator4::Iterator // No implementation - assignment is unsupported. @@ -15503,7 +16279,7 @@ class CartesianProductGenerator5 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -15547,8 +16323,8 @@ class CartesianProductGenerator5 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -15582,7 +16358,7 @@ class CartesianProductGenerator5 const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator5::Iterator // No implementation - assignment is unsupported. @@ -15680,7 +16456,7 @@ class CartesianProductGenerator6 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -15728,8 +16504,8 @@ class CartesianProductGenerator6 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -15767,7 +16543,7 @@ class CartesianProductGenerator6 const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator6::Iterator // No implementation - assignment is unsupported. @@ -15874,7 +16650,7 @@ class CartesianProductGenerator7 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -15926,8 +16702,8 @@ class CartesianProductGenerator7 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -15969,7 +16745,7 @@ class CartesianProductGenerator7 const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator7::Iterator // No implementation - assignment is unsupported. @@ -16087,7 +16863,7 @@ class CartesianProductGenerator8 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -16143,8 +16919,8 @@ class CartesianProductGenerator8 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_, *current8_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -16190,7 +16966,7 @@ class CartesianProductGenerator8 const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator8::Iterator // No implementation - assignment is unsupported. @@ -16316,7 +17092,7 @@ class CartesianProductGenerator9 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -16376,9 +17152,9 @@ class CartesianProductGenerator9 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_, - *current9_); + *current9_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -16428,7 +17204,7 @@ class CartesianProductGenerator9 const typename ParamGenerator::iterator begin9_; const typename ParamGenerator::iterator end9_; typename ParamGenerator::iterator current9_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator9::Iterator // No implementation - assignment is unsupported. @@ -16563,7 +17339,7 @@ class CartesianProductGenerator10 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -16627,9 +17403,9 @@ class CartesianProductGenerator10 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_, - *current9_, *current10_); + *current9_, *current10_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -16683,7 +17459,7 @@ class CartesianProductGenerator10 const typename ParamGenerator::iterator begin10_; const typename ParamGenerator::iterator end10_; typename ParamGenerator::iterator current10_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator10::Iterator // No implementation - assignment is unsupported. @@ -17014,12 +17790,8 @@ CartesianProductHolder10(const Generator1& g1, const Generator2& g2, } // namespace internal } // namespace testing -#endif // GTEST_HAS_PARAM_TEST - #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ -#if GTEST_HAS_PARAM_TEST - namespace testing { // Functions producing parameter generators. @@ -17099,7 +17871,7 @@ internal::ParamGenerator Range(T start, T end) { // each with C-string values of "foo", "bar", and "baz": // // const char* strings[] = {"foo", "bar", "baz"}; -// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); +// INSTANTIATE_TEST_CASE_P(StringSequence, StringTest, ValuesIn(strings)); // // This instantiates tests from test case StlStringTest // each with STL strings with values "a" and "b": @@ -18201,8 +18973,6 @@ internal::CartesianProductHolder10AddTestPattern(\ - #test_case_name, \ - #test_name, \ + GTEST_STRINGIFY_(test_case_name), \ + GTEST_STRINGIFY_(test_name), \ new ::testing::internal::TestMetaFactory< \ GTEST_TEST_CLASS_NAME_(\ test_case_name, test_name)>()); \ @@ -18238,11 +19008,11 @@ internal::CartesianProductHolder10, and return std::string. // // testing::PrintToStringParamName is a builtin test suffix generator that -// returns the value of testing::PrintToString(GetParam()). It does not work -// for std::string or C strings. +// returns the value of testing::PrintToString(GetParam()). // // Note: test names must be non-empty, unique, and may only contain ASCII -// alphanumeric characters or underscore. +// alphanumeric characters or underscore. Because PrintToString adds quotes +// to std::string and C strings, it won't work for these types. # define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator, ...) \ static ::testing::internal::ParamGenerator \ @@ -18252,7 +19022,7 @@ internal::CartesianProductHolder10 \ (__VA_ARGS__)(info); \ } \ - int gtest_##prefix##test_case_name##_dummy_ GTEST_ATTRIBUTE_UNUSED_ = \ + static int gtest_##prefix##test_case_name##_dummy_ GTEST_ATTRIBUTE_UNUSED_ = \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ #test_case_name, \ @@ -18265,8 +19035,6 @@ internal::CartesianProductHolder10 #include +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + namespace testing { // A copyable object representing the result of a test part (i.e. an @@ -18502,6 +19275,8 @@ class GTEST_API_ HasNewFatalFailureHelper } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ // Copyright 2008 Google Inc. // All Rights Reserved. @@ -18531,8 +19306,9 @@ class GTEST_API_ HasNewFatalFailureHelper // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan) + + +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ @@ -18587,6 +19363,24 @@ TYPED_TEST(FooTest, DoesBlah) { TYPED_TEST(FooTest, HasPropertyA) { ... } +// TYPED_TEST_CASE takes an optional third argument which allows to specify a +// class that generates custom test name suffixes based on the type. This should +// be a class which has a static template function GetName(int index) returning +// a string for each type. The provided integer index equals the index of the +// type in the provided type list. In many cases the index can be ignored. +// +// For example: +// class MyTypeNames { +// public: +// template +// static std::string GetName(int) { +// if (std::is_same()) return "char"; +// if (std::is_same()) return "int"; +// if (std::is_same()) return "unsignedInt"; +// } +// }; +// TYPED_TEST_CASE(FooTest, MyTypes, MyTypeNames); + #endif // 0 // Type-parameterized tests are abstract test patterns parameterized @@ -18648,6 +19442,11 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); // If the type list contains only one type, you can write that type // directly without Types<...>: // INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); +// +// Similar to the optional argument of TYPED_TEST_CASE above, +// INSTANTIATE_TEST_CASE_P takes an optional fourth argument which allows to +// generate custom names. +// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes, MyTypeNames); #endif // 0 @@ -18662,32 +19461,46 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); // given test case. # define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_ +// Expands to the name of the typedef for the NameGenerator, responsible for +// creating the suffixes of the name. +#define GTEST_NAME_GENERATOR_(TestCaseName) \ + gtest_type_params_##TestCaseName##_NameGenerator + // The 'Types' template argument below must have spaces around it // since some compilers may choke on '>>' when passing a template // instance (e.g. Types) -# define TYPED_TEST_CASE(CaseName, Types) \ - typedef ::testing::internal::TypeList< Types >::type \ - GTEST_TYPE_PARAMS_(CaseName) - -# define TYPED_TEST(CaseName, TestName) \ - template \ - class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ - : public CaseName { \ - private: \ - typedef CaseName TestFixture; \ - typedef gtest_TypeParam_ TypeParam; \ - virtual void TestBody(); \ - }; \ - bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \ - ::testing::internal::TypeParameterizedTest< \ - CaseName, \ - ::testing::internal::TemplateSel< \ - GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \ - GTEST_TYPE_PARAMS_(CaseName)>::Register(\ - "", ::testing::internal::CodeLocation(__FILE__, __LINE__), \ - #CaseName, #TestName, 0); \ - template \ - void GTEST_TEST_CLASS_NAME_(CaseName, TestName)::TestBody() +# define TYPED_TEST_CASE(CaseName, Types, ...) \ + typedef ::testing::internal::TypeList< Types >::type GTEST_TYPE_PARAMS_( \ + CaseName); \ + typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \ + GTEST_NAME_GENERATOR_(CaseName) + +# define TYPED_TEST(CaseName, TestName) \ + template \ + class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ + : public CaseName { \ + private: \ + typedef CaseName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + static bool gtest_##CaseName##_##TestName##_registered_ \ + GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTest< \ + CaseName, \ + ::testing::internal::TemplateSel, \ + GTEST_TYPE_PARAMS_( \ + CaseName)>::Register("", \ + ::testing::internal::CodeLocation( \ + __FILE__, __LINE__), \ + #CaseName, #TestName, 0, \ + ::testing::internal::GenerateNames< \ + GTEST_NAME_GENERATOR_(CaseName), \ + GTEST_TYPE_PARAMS_(CaseName)>()); \ + template \ + void GTEST_TEST_CLASS_NAME_(CaseName, \ + TestName)::TestBody() #endif // GTEST_HAS_TYPED_TEST @@ -18744,27 +19557,35 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); namespace GTEST_CASE_NAMESPACE_(CaseName) { \ typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ } \ - static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\ - __FILE__, __LINE__, #__VA_ARGS__) + static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) \ + GTEST_ATTRIBUTE_UNUSED_ = \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames( \ + __FILE__, __LINE__, #__VA_ARGS__) // The 'Types' template argument below must have spaces around it // since some compilers may choke on '>>' when passing a template // instance (e.g. Types) -# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \ - bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \ - ::testing::internal::TypeParameterizedTestCase::type>::Register(\ - #Prefix, \ - ::testing::internal::CodeLocation(__FILE__, __LINE__), \ - >EST_TYPED_TEST_CASE_P_STATE_(CaseName), \ - #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName)) +# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types, ...) \ + static bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTestCase< \ + CaseName, GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \ + ::testing::internal::TypeList< Types >::type>:: \ + Register(#Prefix, \ + ::testing::internal::CodeLocation(__FILE__, __LINE__), \ + >EST_TYPED_TEST_CASE_P_STATE_(CaseName), #CaseName, \ + GTEST_REGISTERED_TEST_NAMES_(CaseName), \ + ::testing::internal::GenerateNames< \ + ::testing::internal::NameGeneratorSelector< \ + __VA_ARGS__>::type, \ + ::testing::internal::TypeList< Types >::type>()) #endif // GTEST_HAS_TYPED_TEST_P #endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + // Depending on the platform, different string classes are available. // On Linux, in addition to ::std::string, Google also makes use of // class ::string, which has the same interface as ::std::string, but @@ -18782,6 +19603,15 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); namespace testing { +// Silence C4100 (unreferenced formal parameter) and 4805 +// unsafe mix of type 'const int' and type 'const bool' +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4805) +# pragma warning(disable:4100) +#endif + + // Declares the flags. // This flag temporary enables the disabled tests. @@ -18803,6 +19633,10 @@ GTEST_DECLARE_string_(color); // the tests to run. If the filter is not given all tests are executed. GTEST_DECLARE_string_(filter); +// This flag controls whether Google Test installs a signal handler that dumps +// debugging information when fatal signals are raised. +GTEST_DECLARE_bool_(install_failure_signal_handler); + // OpenCV extension: same as filter, but for the parameters string. GTEST_DECLARE_string_(param_filter); @@ -18818,6 +19652,9 @@ GTEST_DECLARE_string_(output); // test. GTEST_DECLARE_bool_(print_time); +// This flags control whether Google Test prints UTF8 characters as text. +GTEST_DECLARE_bool_(print_utf8); + // This flag specifies the random number seed. GTEST_DECLARE_int32_(random_seed); @@ -18838,7 +19675,7 @@ GTEST_DECLARE_int32_(stack_trace_depth); // When this flag is specified, a failed assertion will throw an // exception if exceptions are enabled, or exit the program with a -// non-zero code otherwise. +// non-zero code otherwise. For use with an external test framework. GTEST_DECLARE_bool_(throw_on_failure); // When this flag is set with a "host:port" string, on supported @@ -18846,6 +19683,10 @@ GTEST_DECLARE_bool_(throw_on_failure); // the specified host machine. GTEST_DECLARE_string_(stream_result_to); +#if GTEST_USE_OWN_FLAGFILE_FLAG_ +GTEST_DECLARE_string_(flagfile); +#endif // GTEST_USE_OWN_FLAGFILE_FLAG_ + // The upper limit for valid stack trace depths. const int kMaxStackTraceDepth = 100; @@ -18863,6 +19704,7 @@ class TestEventListenersAccessor; class TestEventRepeater; class UnitTestRecordPropertyTestHelper; class WindowsDeathTest; +class FuchsiaDeathTest; class UnitTestImpl* GetUnitTestImpl(); void ReportFailureInUnknownLocation(TestPartResult::Type result_type, const std::string& message); @@ -18962,7 +19804,9 @@ class GTEST_API_ AssertionResult { // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult(const AssertionResult& other); +#if defined(_MSC_VER) && _MSC_VER < 1910 GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 /* forcing value to bool */) +#endif // Used in the EXPECT_TRUE/FALSE(bool_expression). // @@ -18979,7 +19823,9 @@ class GTEST_API_ AssertionResult { /*enabler*/ = NULL) : success_(success) {} +#if defined(_MSC_VER) && _MSC_VER < 1910 GTEST_DISABLE_MSC_WARNINGS_POP_() +#endif // Assignment operator. AssertionResult& operator=(AssertionResult other) { @@ -19000,7 +19846,7 @@ class GTEST_API_ AssertionResult { const char* message() const { return message_.get() != NULL ? message_->c_str() : ""; } - // TODO(vladl@google.com): Remove this after making sure no clients use it. + // FIXME: Remove this after making sure no clients use it. // Deprecated; please use message() instead. const char* failure_message() const { return message(); } @@ -19048,681 +19894,1064 @@ GTEST_API_ AssertionResult AssertionFailure(); // Deprecated; use AssertionFailure() << msg. GTEST_API_ AssertionResult AssertionFailure(const Message& msg); -// The abstract class that all tests inherit from. -// -// In Google Test, a unit test program contains one or many TestCases, and -// each TestCase contains one or many Tests. -// -// When you define a test using the TEST macro, you don't need to -// explicitly derive from Test - the TEST macro automatically does -// this for you. -// -// The only time you derive from Test is when defining a test fixture -// to be used a TEST_F. For example: +} // namespace testing + +// Includes the auto-generated header that implements a family of generic +// predicate assertion macros. This include comes late because it relies on +// APIs declared above. +// Copyright 2006, Google Inc. +// All rights reserved. // -// class FooTest : public testing::Test { -// protected: -// void SetUp() override { ... } -// void TearDown() override { ... } -// ... -// }; +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: // -// TEST_F(FooTest, Bar) { ... } -// TEST_F(FooTest, Baz) { ... } +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. // -// Test is not copyable. -class GTEST_API_ Test { - public: - friend class TestInfo; +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // Defines types for pointers to functions that set up and tear down - // a test case. - typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc; - typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc; +// This file is AUTOMATICALLY GENERATED on 01/02/2018 by command +// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! +// +// Implements a family of generic predicate assertion macros. - // The d'tor is virtual as we intend to inherit from Test. - virtual ~Test(); +// GOOGLETEST_CM0001 DO NOT DELETE - // Sets up the stuff shared by all tests in this test case. - // - // Google Test will call Foo::SetUpTestCase() before running the first - // test in test case Foo. Hence a sub-class can define its own - // SetUpTestCase() method to shadow the one defined in the super - // class. - static void SetUpTestCase() {} +#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ - // Tears down the stuff shared by all tests in this test case. - // - // Google Test will call Foo::TearDownTestCase() after running the last - // test in test case Foo. Hence a sub-class can define its own - // TearDownTestCase() method to shadow the one defined in the super - // class. - static void TearDownTestCase() {} - // Returns true iff the current test has a fatal failure. - static bool HasFatalFailure(); +namespace testing { - // Returns true iff the current test has a non-fatal failure. - static bool HasNonfatalFailure(); +// This header implements a family of generic predicate assertion +// macros: +// +// ASSERT_PRED_FORMAT1(pred_format, v1) +// ASSERT_PRED_FORMAT2(pred_format, v1, v2) +// ... +// +// where pred_format is a function or functor that takes n (in the +// case of ASSERT_PRED_FORMATn) values and their source expression +// text, and returns a testing::AssertionResult. See the definition +// of ASSERT_EQ in gtest.h for an example. +// +// If you don't care about formatting, you can use the more +// restrictive version: +// +// ASSERT_PRED1(pred, v1) +// ASSERT_PRED2(pred, v1, v2) +// ... +// +// where pred is an n-ary function or functor that returns bool, +// and the values v1, v2, ..., must support the << operator for +// streaming to std::ostream. +// +// We also define the EXPECT_* variations. +// +// For now we only support predicates whose arity is at most 5. - // Returns true iff the current test has a (either fatal or - // non-fatal) failure. - static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } +// GTEST_ASSERT_ is the basic statement to which all of the assertions +// in this file reduce. Don't use this in your code. - // Logs a property for the current test, test case, or for the entire - // invocation of the test program when used outside of the context of a - // test case. Only the last value for a given key is remembered. These - // are public static so they can be called from utility functions that are - // not members of the test fixture. Calls to RecordProperty made during - // lifespan of the test (from the moment its constructor starts to the - // moment its destructor finishes) will be output in XML as attributes of - // the element. Properties recorded from fixture's - // SetUpTestCase or TearDownTestCase are logged as attributes of the - // corresponding element. Calls to RecordProperty made in the - // global context (before or after invocation of RUN_ALL_TESTS and from - // SetUp/TearDown method of Environment objects registered with Google - // Test) will be output as attributes of the element. - static void RecordProperty(const std::string& key, const std::string& value); - static void RecordProperty(const std::string& key, int value); +#define GTEST_ASSERT_(expression, on_failure) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::testing::AssertionResult gtest_ar = (expression)) \ + ; \ + else \ + on_failure(gtest_ar.failure_message()) - protected: - // Creates a Test object. - Test(); - // Sets up the test fixture. - virtual void SetUp(); +// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use +// this in your code. +template +AssertionResult AssertPred1Helper(const char* pred_text, + const char* e1, + Pred pred, + const T1& v1) { + if (pred(v1)) return AssertionSuccess(); - // Tears down the test fixture. - virtual void TearDown(); + return AssertionFailure() << pred_text << "(" + << e1 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1; +} - private: - // Returns true iff the current test has the same fixture class as - // the first test in the current test case. - static bool HasSameFixtureClass(); +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. +// Don't use this in your code. +#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, v1), \ + on_failure) - // Runs the test after the test fixture has been set up. - // - // A sub-class must implement this to define the test logic. - // - // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM. - // Instead, use the TEST or TEST_F macro. - virtual void TestBody() = 0; +// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use +// this in your code. +#define GTEST_PRED1_(pred, v1, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \ + #v1, \ + pred, \ + v1), on_failure) - // Sets up, executes, and tears down the test. - void Run(); +// Unary predicate assertion macros. +#define EXPECT_PRED_FORMAT1(pred_format, v1) \ + GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED1(pred, v1) \ + GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT1(pred_format, v1) \ + GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED1(pred, v1) \ + GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_) - // Deletes self. We deliberately pick an unusual name for this - // internal method to avoid clashing with names used in user TESTs. - void DeleteSelf_() { delete this; } - const internal::scoped_ptr< GTEST_FLAG_SAVER_ > gtest_flag_saver_; - // Often a user misspells SetUp() as Setup() and spends a long time - // wondering why it is never called by Google Test. The declaration of - // the following method is solely for catching such an error at - // compile time: - // - // - The return type is deliberately chosen to be not void, so it - // will be a conflict if void Setup() is declared in the user's - // test fixture. - // - // - This method is private, so it will be another compiler error - // if the method is called from the user's test fixture. - // - // DO NOT OVERRIDE THIS FUNCTION. - // - // If you see an error about overriding the following function or - // about it being private, you have mis-spelled SetUp() as Setup(). - struct Setup_should_be_spelled_SetUp {}; - virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } +// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use +// this in your code. +template +AssertionResult AssertPred2Helper(const char* pred_text, + const char* e1, + const char* e2, + Pred pred, + const T1& v1, + const T2& v2) { + if (pred(v1, v2)) return AssertionSuccess(); - // We disallow copying Tests. - GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); -}; + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2; +} -typedef internal::TimeInMillis TimeInMillis; +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. +// Don't use this in your code. +#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), \ + on_failure) -// A copyable object representing a user specified test property which can be -// output as a key/value string pair. -// -// Don't inherit from TestProperty as its destructor is not virtual. -class TestProperty { - public: - // C'tor. TestProperty does NOT have a default constructor. - // Always use this constructor (with parameters) to create a - // TestProperty object. - TestProperty(const std::string& a_key, const std::string& a_value) : - key_(a_key), value_(a_value) { - } +// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use +// this in your code. +#define GTEST_PRED2_(pred, v1, v2, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \ + #v1, \ + #v2, \ + pred, \ + v1, \ + v2), on_failure) - // Gets the user supplied key. - const char* key() const { - return key_.c_str(); - } +// Binary predicate assertion macros. +#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \ + GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED2(pred, v1, v2) \ + GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \ + GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED2(pred, v1, v2) \ + GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_) - // Gets the user supplied value. - const char* value() const { - return value_.c_str(); - } - // Sets a new value, overriding the one supplied in the constructor. - void SetValue(const std::string& new_value) { - value_ = new_value; - } - private: - // The key supplied by the user. - std::string key_; - // The value supplied by the user. - std::string value_; -}; +// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use +// this in your code. +template +AssertionResult AssertPred3Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3) { + if (pred(v1, v2, v3)) return AssertionSuccess(); -// The result of a single Test. This includes a list of -// TestPartResults, a list of TestProperties, a count of how many -// death tests there are in the Test, and how much time it took to run -// the Test. -// -// TestResult is not copyable. -class GTEST_API_ TestResult { - public: - // Creates an empty TestResult. - TestResult(); + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3; +} - // D'tor. Do not inherit from TestResult. - ~TestResult(); +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. +// Don't use this in your code. +#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3), \ + on_failure) - // Gets the number of all test parts. This is the sum of the number - // of successful test parts and the number of failed test parts. - int total_part_count() const; +// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use +// this in your code. +#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + pred, \ + v1, \ + v2, \ + v3), on_failure) - // Returns the number of the test properties. - int test_property_count() const; +// Ternary predicate assertion macros. +#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \ + GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED3(pred, v1, v2, v3) \ + GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \ + GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED3(pred, v1, v2, v3) \ + GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_) - // Returns true iff the test passed (i.e. no test part failed). - bool Passed() const { return !Failed(); } - // Returns true iff the test failed. - bool Failed() const; - // Returns true iff the test fatally failed. - bool HasFatalFailure() const; +// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use +// this in your code. +template +AssertionResult AssertPred4Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + const char* e4, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4) { + if (pred(v1, v2, v3, v4)) return AssertionSuccess(); - // Returns true iff the test has a non-fatal failure. - bool HasNonfatalFailure() const; + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ", " + << e4 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3 + << "\n" << e4 << " evaluates to " << v4; +} - // Returns the elapsed time, in milliseconds. - TimeInMillis elapsed_time() const { return elapsed_time_; } +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. +// Don't use this in your code. +#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4), \ + on_failure) - // Returns the i-th test part result among all the results. i can range - // from 0 to test_property_count() - 1. If i is not in that range, aborts - // the program. - const TestPartResult& GetTestPartResult(int i) const; +// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use +// this in your code. +#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + #v4, \ + pred, \ + v1, \ + v2, \ + v3, \ + v4), on_failure) - // Returns the i-th test property. i can range from 0 to - // test_property_count() - 1. If i is not in that range, aborts the - // program. - const TestProperty& GetTestProperty(int i) const; +// 4-ary predicate assertion macros. +#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ + GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED4(pred, v1, v2, v3, v4) \ + GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ + GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED4(pred, v1, v2, v3, v4) \ + GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) - private: - friend class TestInfo; - friend class TestCase; - friend class UnitTest; - friend class internal::DefaultGlobalTestPartResultReporter; - friend class internal::ExecDeathTest; - friend class internal::TestResultAccessor; - friend class internal::UnitTestImpl; - friend class internal::WindowsDeathTest; - // Gets the vector of TestPartResults. - const std::vector& test_part_results() const { - return test_part_results_; - } - // Gets the vector of TestProperties. - const std::vector& test_properties() const { - return test_properties_; - } +// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use +// this in your code. +template +AssertionResult AssertPred5Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + const char* e4, + const char* e5, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4, + const T5& v5) { + if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); - // Sets the elapsed time. - void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } - - // Adds a test property to the list. The property is validated and may add - // a non-fatal failure if invalid (e.g., if it conflicts with reserved - // key names). If a property is already recorded for the same key, the - // value will be updated, rather than storing multiple values for the same - // key. xml_element specifies the element for which the property is being - // recorded and is used for validation. - void RecordProperty(const std::string& xml_element, - const TestProperty& test_property); - - // Adds a failure if the key is a reserved attribute of Google Test - // testcase tags. Returns true if the property is valid. - // TODO(russr): Validate attribute names are legal and human readable. - static bool ValidateTestProperty(const std::string& xml_element, - const TestProperty& test_property); + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ", " + << e4 << ", " + << e5 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3 + << "\n" << e4 << " evaluates to " << v4 + << "\n" << e5 << " evaluates to " << v5; +} - // Adds a test part result to the list. - void AddTestPartResult(const TestPartResult& test_part_result); +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. +// Don't use this in your code. +#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5), \ + on_failure) - // Returns the death test count. - int death_test_count() const { return death_test_count_; } +// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use +// this in your code. +#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + #v4, \ + #v5, \ + pred, \ + v1, \ + v2, \ + v3, \ + v4, \ + v5), on_failure) - // Increments the death test count, returning the new count. - int increment_death_test_count() { return ++death_test_count_; } +// 5-ary predicate assertion macros. +#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ + GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \ + GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ + GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \ + GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) - // Clears the test part results. - void ClearTestPartResults(); - // Clears the object. - void Clear(); - // Protects mutable state of the property vector and of owned - // properties, whose values may be updated. - internal::Mutex test_properites_mutex_; +} // namespace testing - // The vector of TestPartResults - std::vector test_part_results_; - // The vector of TestProperties - std::vector test_properties_; - // Running count of death tests. - int death_test_count_; - // The elapsed time, in milliseconds. - TimeInMillis elapsed_time_; +#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ - // We disallow copying TestResult. - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult); -}; // class TestResult +namespace testing { -// A TestInfo object stores the following information about a test: +// The abstract class that all tests inherit from. // -// Test case name -// Test name -// Whether the test should be run -// A function pointer that creates the test object when invoked -// Test result +// In Google Test, a unit test program contains one or many TestCases, and +// each TestCase contains one or many Tests. // -// The constructor of TestInfo registers itself with the UnitTest -// singleton such that the RUN_ALL_TESTS() macro knows which tests to -// run. -class GTEST_API_ TestInfo { +// When you define a test using the TEST macro, you don't need to +// explicitly derive from Test - the TEST macro automatically does +// this for you. +// +// The only time you derive from Test is when defining a test fixture +// to be used in a TEST_F. For example: +// +// class FooTest : public testing::Test { +// protected: +// void SetUp() override { ... } +// void TearDown() override { ... } +// ... +// }; +// +// TEST_F(FooTest, Bar) { ... } +// TEST_F(FooTest, Baz) { ... } +// +// Test is not copyable. +class GTEST_API_ Test { public: - // Destructs a TestInfo object. This function is not virtual, so - // don't inherit from TestInfo. - ~TestInfo(); - - // Returns the test case name. - const char* test_case_name() const { return test_case_name_.c_str(); } - - // Returns the test name. - const char* name() const { return name_.c_str(); } - - // Returns the name of the parameter type, or NULL if this is not a typed - // or a type-parameterized test. - const char* type_param() const { - if (type_param_.get() != NULL) - return type_param_->c_str(); - return NULL; - } - - // Returns the text representation of the value parameter, or NULL if this - // is not a value-parameterized test. - const char* value_param() const { - if (value_param_.get() != NULL) - return value_param_->c_str(); - return NULL; - } + friend class TestInfo; - // Returns the file name where this test is defined. - const char* file() const { return location_.file.c_str(); } + // Defines types for pointers to functions that set up and tear down + // a test case. + typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc; + typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc; - // Returns the line where this test is defined. - int line() const { return location_.line; } + // The d'tor is virtual as we intend to inherit from Test. + virtual ~Test(); - // Returns true if this test should run, that is if the test is not - // disabled (or it is disabled but the also_run_disabled_tests flag has - // been specified) and its full name matches the user-specified filter. - // - // Google Test allows the user to filter the tests by their full names. - // The full name of a test Bar in test case Foo is defined as - // "Foo.Bar". Only the tests that match the filter will run. + // Sets up the stuff shared by all tests in this test case. // - // A filter is a colon-separated list of glob (not regex) patterns, - // optionally followed by a '-' and a colon-separated list of - // negative patterns (tests to exclude). A test is run if it - // matches one of the positive patterns and does not match any of - // the negative patterns. + // Google Test will call Foo::SetUpTestCase() before running the first + // test in test case Foo. Hence a sub-class can define its own + // SetUpTestCase() method to shadow the one defined in the super + // class. + static void SetUpTestCase() {} + + // Tears down the stuff shared by all tests in this test case. // - // For example, *A*:Foo.* is a filter that matches any string that - // contains the character 'A' or starts with "Foo.". - bool should_run() const { return should_run_; } + // Google Test will call Foo::TearDownTestCase() after running the last + // test in test case Foo. Hence a sub-class can define its own + // TearDownTestCase() method to shadow the one defined in the super + // class. + static void TearDownTestCase() {} - // Returns true iff this test will appear in the XML report. - bool is_reportable() const { - // For now, the XML report includes all tests matching the filter. - // In the future, we may trim tests that are excluded because of - // sharding. - return matches_filter_; - } + // Returns true iff the current test has a fatal failure. + static bool HasFatalFailure(); - // Returns the result of the test. - const TestResult* result() const { return &result_; } + // Returns true iff the current test has a non-fatal failure. + static bool HasNonfatalFailure(); - private: -#if GTEST_HAS_DEATH_TEST - friend class internal::DefaultDeathTestFactory; -#endif // GTEST_HAS_DEATH_TEST - friend class Test; - friend class TestCase; - friend class internal::UnitTestImpl; - friend class internal::StreamingListenerTest; - friend TestInfo* internal::MakeAndRegisterTestInfo( - const char* test_case_name, - const char* name, - const char* type_param, - const char* value_param, - internal::CodeLocation code_location, - internal::TypeId fixture_class_id, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc, - internal::TestFactoryBase* factory); + // Returns true iff the current test has a (either fatal or + // non-fatal) failure. + static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } - // Constructs a TestInfo object. The newly constructed instance assumes - // ownership of the factory object. - TestInfo(const std::string& test_case_name, - const std::string& name, - const char* a_type_param, // NULL if not a type-parameterized test - const char* a_value_param, // NULL if not a value-parameterized test - internal::CodeLocation a_code_location, - internal::TypeId fixture_class_id, - internal::TestFactoryBase* factory); + // Logs a property for the current test, test case, or for the entire + // invocation of the test program when used outside of the context of a + // test case. Only the last value for a given key is remembered. These + // are public static so they can be called from utility functions that are + // not members of the test fixture. Calls to RecordProperty made during + // lifespan of the test (from the moment its constructor starts to the + // moment its destructor finishes) will be output in XML as attributes of + // the element. Properties recorded from fixture's + // SetUpTestCase or TearDownTestCase are logged as attributes of the + // corresponding element. Calls to RecordProperty made in the + // global context (before or after invocation of RUN_ALL_TESTS and from + // SetUp/TearDown method of Environment objects registered with Google + // Test) will be output as attributes of the element. + static void RecordProperty(const std::string& key, const std::string& value); + static void RecordProperty(const std::string& key, int value); - // Increments the number of death tests encountered in this test so - // far. - int increment_death_test_count() { - return result_.increment_death_test_count(); - } + protected: + // Creates a Test object. + Test(); - // Creates the test object, runs it, records its result, and then - // deletes it. - void Run(); + // Sets up the test fixture. + virtual void SetUp(); - static void ClearTestResult(TestInfo* test_info) { - test_info->result_.Clear(); - } + // Tears down the test fixture. + virtual void TearDown(); - // These fields are immutable properties of the test. - const std::string test_case_name_; // Test case name - const std::string name_; // Test name - // Name of the parameter type, or NULL if this is not a typed or a - // type-parameterized test. - const internal::scoped_ptr type_param_; - // Text representation of the value parameter, or NULL if this is not a - // value-parameterized test. - const internal::scoped_ptr value_param_; - internal::CodeLocation location_; - const internal::TypeId fixture_class_id_; // ID of the test fixture class - bool should_run_; // True iff this test should run - bool is_disabled_; // True iff this test is disabled - bool matches_filter_; // True if this test matches the - // user-specified filter. - internal::TestFactoryBase* const factory_; // The factory that creates - // the test object + private: + // Returns true iff the current test has the same fixture class as + // the first test in the current test case. + static bool HasSameFixtureClass(); - // This field is mutable and needs to be reset before running the - // test for the second time. - TestResult result_; + // Runs the test after the test fixture has been set up. + // + // A sub-class must implement this to define the test logic. + // + // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM. + // Instead, use the TEST or TEST_F macro. + virtual void TestBody() = 0; - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); -}; + // Sets up, executes, and tears down the test. + void Run(); -// A test case, which consists of a vector of TestInfos. -// -// TestCase is not copyable. -class GTEST_API_ TestCase { - public: - // Creates a TestCase with the given name. + // Deletes self. We deliberately pick an unusual name for this + // internal method to avoid clashing with names used in user TESTs. + void DeleteSelf_() { delete this; } + + const internal::scoped_ptr< GTEST_FLAG_SAVER_ > gtest_flag_saver_; + + // Often a user misspells SetUp() as Setup() and spends a long time + // wondering why it is never called by Google Test. The declaration of + // the following method is solely for catching such an error at + // compile time: // - // TestCase does NOT have a default constructor. Always use this - // constructor to create a TestCase object. + // - The return type is deliberately chosen to be not void, so it + // will be a conflict if void Setup() is declared in the user's + // test fixture. // - // Arguments: + // - This method is private, so it will be another compiler error + // if the method is called from the user's test fixture. // - // name: name of the test case - // a_type_param: the name of the test's type parameter, or NULL if - // this is not a type-parameterized test. - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case - TestCase(const char* name, const char* a_type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc); + // DO NOT OVERRIDE THIS FUNCTION. + // + // If you see an error about overriding the following function or + // about it being private, you have mis-spelled SetUp() as Setup(). + struct Setup_should_be_spelled_SetUp {}; + virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } - // Destructor of TestCase. - virtual ~TestCase(); + // We disallow copying Tests. + GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); +}; - // Gets the name of the TestCase. - const char* name() const { return name_.c_str(); } +typedef internal::TimeInMillis TimeInMillis; - // Returns the name of the parameter type, or NULL if this is not a - // type-parameterized test case. - const char* type_param() const { - if (type_param_.get() != NULL) - return type_param_->c_str(); - return NULL; +// A copyable object representing a user specified test property which can be +// output as a key/value string pair. +// +// Don't inherit from TestProperty as its destructor is not virtual. +class TestProperty { + public: + // C'tor. TestProperty does NOT have a default constructor. + // Always use this constructor (with parameters) to create a + // TestProperty object. + TestProperty(const std::string& a_key, const std::string& a_value) : + key_(a_key), value_(a_value) { } - // Returns true if any test in this test case should run. - bool should_run() const { return should_run_; } + // Gets the user supplied key. + const char* key() const { + return key_.c_str(); + } - // Gets the number of successful tests in this test case. - int successful_test_count() const; + // Gets the user supplied value. + const char* value() const { + return value_.c_str(); + } - // Gets the number of failed tests in this test case. - int failed_test_count() const; + // Sets a new value, overriding the one supplied in the constructor. + void SetValue(const std::string& new_value) { + value_ = new_value; + } - // Gets the number of disabled tests that will be reported in the XML report. - int reportable_disabled_test_count() const; + private: + // The key supplied by the user. + std::string key_; + // The value supplied by the user. + std::string value_; +}; - // Gets the number of disabled tests in this test case. - int disabled_test_count() const; +// The result of a single Test. This includes a list of +// TestPartResults, a list of TestProperties, a count of how many +// death tests there are in the Test, and how much time it took to run +// the Test. +// +// TestResult is not copyable. +class GTEST_API_ TestResult { + public: + // Creates an empty TestResult. + TestResult(); - // Gets the number of tests to be printed in the XML report. - int reportable_test_count() const; + // D'tor. Do not inherit from TestResult. + ~TestResult(); - // Get the number of tests in this test case that should run. - int test_to_run_count() const; + // Gets the number of all test parts. This is the sum of the number + // of successful test parts and the number of failed test parts. + int total_part_count() const; - // Gets the number of all tests in this test case. - int total_test_count() const; + // Returns the number of the test properties. + int test_property_count() const; - // Returns true iff the test case passed. + // Returns true iff the test passed (i.e. no test part failed). bool Passed() const { return !Failed(); } - // Returns true iff the test case failed. - bool Failed() const { return failed_test_count() > 0; } + // Returns true iff the test failed. + bool Failed() const; + + // Returns true iff the test fatally failed. + bool HasFatalFailure() const; + + // Returns true iff the test has a non-fatal failure. + bool HasNonfatalFailure() const; // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } - // Returns the i-th test among all the tests. i can range from 0 to - // total_test_count() - 1. If i is not in that range, returns NULL. - const TestInfo* GetTestInfo(int i) const; + // Returns the i-th test part result among all the results. i can range from 0 + // to total_part_count() - 1. If i is not in that range, aborts the program. + const TestPartResult& GetTestPartResult(int i) const; - // Returns the TestResult that holds test properties recorded during - // execution of SetUpTestCase and TearDownTestCase. - const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; } + // Returns the i-th test property. i can range from 0 to + // test_property_count() - 1. If i is not in that range, aborts the + // program. + const TestProperty& GetTestProperty(int i) const; private: - friend class Test; + friend class TestInfo; + friend class TestCase; + friend class UnitTest; + friend class internal::DefaultGlobalTestPartResultReporter; + friend class internal::ExecDeathTest; + friend class internal::TestResultAccessor; friend class internal::UnitTestImpl; + friend class internal::WindowsDeathTest; + friend class internal::FuchsiaDeathTest; - // Gets the (mutable) vector of TestInfos in this TestCase. - std::vector& test_info_list() { return test_info_list_; } + // Gets the vector of TestPartResults. + const std::vector& test_part_results() const { + return test_part_results_; + } - // Gets the (immutable) vector of TestInfos in this TestCase. - const std::vector& test_info_list() const { - return test_info_list_; + // Gets the vector of TestProperties. + const std::vector& test_properties() const { + return test_properties_; } - // Returns the i-th test among all the tests. i can range from 0 to - // total_test_count() - 1. If i is not in that range, returns NULL. - TestInfo* GetMutableTestInfo(int i); + // Sets the elapsed time. + void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } - // Sets the should_run member. - void set_should_run(bool should) { should_run_ = should; } + // Adds a test property to the list. The property is validated and may add + // a non-fatal failure if invalid (e.g., if it conflicts with reserved + // key names). If a property is already recorded for the same key, the + // value will be updated, rather than storing multiple values for the same + // key. xml_element specifies the element for which the property is being + // recorded and is used for validation. + void RecordProperty(const std::string& xml_element, + const TestProperty& test_property); - // Adds a TestInfo to this test case. Will delete the TestInfo upon - // destruction of the TestCase object. - void AddTestInfo(TestInfo * test_info); + // Adds a failure if the key is a reserved attribute of Google Test + // testcase tags. Returns true if the property is valid. + // FIXME: Validate attribute names are legal and human readable. + static bool ValidateTestProperty(const std::string& xml_element, + const TestProperty& test_property); - // Clears the results of all tests in this test case. - void ClearResult(); + // Adds a test part result to the list. + void AddTestPartResult(const TestPartResult& test_part_result); - // Clears the results of all tests in the given test case. - static void ClearTestCaseResult(TestCase* test_case) { - test_case->ClearResult(); - } + // Returns the death test count. + int death_test_count() const { return death_test_count_; } - // Runs every test in this TestCase. - void Run(); + // Increments the death test count, returning the new count. + int increment_death_test_count() { return ++death_test_count_; } - // Runs SetUpTestCase() for this TestCase. This wrapper is needed - // for catching exceptions thrown from SetUpTestCase(). - void RunSetUpTestCase() { (*set_up_tc_)(); } + // Clears the test part results. + void ClearTestPartResults(); - // Runs TearDownTestCase() for this TestCase. This wrapper is - // needed for catching exceptions thrown from TearDownTestCase(). - void RunTearDownTestCase() { (*tear_down_tc_)(); } + // Clears the object. + void Clear(); - // Returns true iff test passed. - static bool TestPassed(const TestInfo* test_info) { - return test_info->should_run() && test_info->result()->Passed(); - } + // Protects mutable state of the property vector and of owned + // properties, whose values may be updated. + internal::Mutex test_properites_mutex_; - // Returns true iff test failed. - static bool TestFailed(const TestInfo* test_info) { - return test_info->should_run() && test_info->result()->Failed(); - } + // The vector of TestPartResults + std::vector test_part_results_; + // The vector of TestProperties + std::vector test_properties_; + // Running count of death tests. + int death_test_count_; + // The elapsed time, in milliseconds. + TimeInMillis elapsed_time_; - // Returns true iff the test is disabled and will be reported in the XML - // report. - static bool TestReportableDisabled(const TestInfo* test_info) { - return test_info->is_reportable() && test_info->is_disabled_; + // We disallow copying TestResult. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult); +}; // class TestResult + +// A TestInfo object stores the following information about a test: +// +// Test case name +// Test name +// Whether the test should be run +// A function pointer that creates the test object when invoked +// Test result +// +// The constructor of TestInfo registers itself with the UnitTest +// singleton such that the RUN_ALL_TESTS() macro knows which tests to +// run. +class GTEST_API_ TestInfo { + public: + // Destructs a TestInfo object. This function is not virtual, so + // don't inherit from TestInfo. + ~TestInfo(); + + // Returns the test case name. + const char* test_case_name() const { return test_case_name_.c_str(); } + + // Returns the test name. + const char* name() const { return name_.c_str(); } + + // Returns the name of the parameter type, or NULL if this is not a typed + // or a type-parameterized test. + const char* type_param() const { + if (type_param_.get() != NULL) + return type_param_->c_str(); + return NULL; } - // Returns true iff test is disabled. - static bool TestDisabled(const TestInfo* test_info) { - return test_info->is_disabled_; + // Returns the text representation of the value parameter, or NULL if this + // is not a value-parameterized test. + const char* value_param() const { + if (value_param_.get() != NULL) + return value_param_->c_str(); + return NULL; } + // Returns the file name where this test is defined. + const char* file() const { return location_.file.c_str(); } + + // Returns the line where this test is defined. + int line() const { return location_.line; } + + // Return true if this test should not be run because it's in another shard. + bool is_in_another_shard() const { return is_in_another_shard_; } + + // Returns true if this test should run, that is if the test is not + // disabled (or it is disabled but the also_run_disabled_tests flag has + // been specified) and its full name matches the user-specified filter. + // + // Google Test allows the user to filter the tests by their full names. + // The full name of a test Bar in test case Foo is defined as + // "Foo.Bar". Only the tests that match the filter will run. + // + // A filter is a colon-separated list of glob (not regex) patterns, + // optionally followed by a '-' and a colon-separated list of + // negative patterns (tests to exclude). A test is run if it + // matches one of the positive patterns and does not match any of + // the negative patterns. + // + // For example, *A*:Foo.* is a filter that matches any string that + // contains the character 'A' or starts with "Foo.". + bool should_run() const { return should_run_; } + // Returns true iff this test will appear in the XML report. - static bool TestReportable(const TestInfo* test_info) { - return test_info->is_reportable(); + bool is_reportable() const { + // The XML report includes tests matching the filter, excluding those + // run in other shards. + return matches_filter_ && !is_in_another_shard_; } - // Returns true if the given test should run. - static bool ShouldRunTest(const TestInfo* test_info) { - return test_info->should_run(); + // Returns the result of the test. + const TestResult* result() const { return &result_; } + + private: +#if GTEST_HAS_DEATH_TEST + friend class internal::DefaultDeathTestFactory; +#endif // GTEST_HAS_DEATH_TEST + friend class Test; + friend class TestCase; + friend class internal::UnitTestImpl; + friend class internal::StreamingListenerTest; + friend TestInfo* internal::MakeAndRegisterTestInfo( + const char* test_case_name, + const char* name, + const char* type_param, + const char* value_param, + internal::CodeLocation code_location, + internal::TypeId fixture_class_id, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc, + internal::TestFactoryBase* factory); + + // Constructs a TestInfo object. The newly constructed instance assumes + // ownership of the factory object. + TestInfo(const std::string& test_case_name, + const std::string& name, + const char* a_type_param, // NULL if not a type-parameterized test + const char* a_value_param, // NULL if not a value-parameterized test + internal::CodeLocation a_code_location, + internal::TypeId fixture_class_id, + internal::TestFactoryBase* factory); + + // Increments the number of death tests encountered in this test so + // far. + int increment_death_test_count() { + return result_.increment_death_test_count(); } - // Shuffles the tests in this test case. - void ShuffleTests(internal::Random* random); + // Creates the test object, runs it, records its result, and then + // deletes it. + void Run(); - // Restores the test order to before the first shuffle. - void UnshuffleTests(); + static void ClearTestResult(TestInfo* test_info) { + test_info->result_.Clear(); + } - // Name of the test case. - std::string name_; + // These fields are immutable properties of the test. + const std::string test_case_name_; // Test case name + const std::string name_; // Test name // Name of the parameter type, or NULL if this is not a typed or a // type-parameterized test. const internal::scoped_ptr type_param_; - // The vector of TestInfos in their original order. It owns the - // elements in the vector. - std::vector test_info_list_; - // Provides a level of indirection for the test list to allow easy - // shuffling and restoring the test order. The i-th element in this - // vector is the index of the i-th test in the shuffled test list. - std::vector test_indices_; - // Pointer to the function that sets up the test case. - Test::SetUpTestCaseFunc set_up_tc_; - // Pointer to the function that tears down the test case. - Test::TearDownTestCaseFunc tear_down_tc_; - // True iff any test in this test case should run. - bool should_run_; - // Elapsed time, in milliseconds. - TimeInMillis elapsed_time_; - // Holds test properties recorded during execution of SetUpTestCase and - // TearDownTestCase. - TestResult ad_hoc_test_result_; + // Text representation of the value parameter, or NULL if this is not a + // value-parameterized test. + const internal::scoped_ptr value_param_; + internal::CodeLocation location_; + const internal::TypeId fixture_class_id_; // ID of the test fixture class + bool should_run_; // True iff this test should run + bool is_disabled_; // True iff this test is disabled + bool matches_filter_; // True if this test matches the + // user-specified filter. + bool is_in_another_shard_; // Will be run in another shard. + internal::TestFactoryBase* const factory_; // The factory that creates + // the test object - // We disallow copying TestCases. - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); + // This field is mutable and needs to be reset before running the + // test for the second time. + TestResult result_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); }; -// An Environment object is capable of setting up and tearing down an -// environment. You should subclass this to define your own -// environment(s). -// -// An Environment object does the set-up and tear-down in virtual -// methods SetUp() and TearDown() instead of the constructor and the -// destructor, as: +// A test case, which consists of a vector of TestInfos. // -// 1. You cannot safely throw from a destructor. This is a problem -// as in some cases Google Test is used where exceptions are enabled, and -// we may want to implement ASSERT_* using exceptions where they are -// available. -// 2. You cannot use ASSERT_* directly in a constructor or -// destructor. -class Environment { +// TestCase is not copyable. +class GTEST_API_ TestCase { public: - // The d'tor is virtual as we need to subclass Environment. - virtual ~Environment() {} + // Creates a TestCase with the given name. + // + // TestCase does NOT have a default constructor. Always use this + // constructor to create a TestCase object. + // + // Arguments: + // + // name: name of the test case + // a_type_param: the name of the test's type parameter, or NULL if + // this is not a type-parameterized test. + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + TestCase(const char* name, const char* a_type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc); - // Override this to define how to set up the environment. - virtual void SetUp() {} + // Destructor of TestCase. + virtual ~TestCase(); - // Override this to define how to tear down the environment. - virtual void TearDown() {} - private: - // If you see an error about overriding the following function or - // about it being private, you have mis-spelled SetUp() as Setup(). - struct Setup_should_be_spelled_SetUp {}; - virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } -}; + // Gets the name of the TestCase. + const char* name() const { return name_.c_str(); } -// The interface for tracing execution of tests. The methods are organized in -// the order the corresponding events are fired. -class TestEventListener { - public: - virtual ~TestEventListener() {} + // Returns the name of the parameter type, or NULL if this is not a + // type-parameterized test case. + const char* type_param() const { + if (type_param_.get() != NULL) + return type_param_->c_str(); + return NULL; + } - // Fired before any test activity starts. - virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; + // Returns true if any test in this test case should run. + bool should_run() const { return should_run_; } - // Fired before each iteration of tests starts. There may be more than - // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration - // index, starting from 0. - virtual void OnTestIterationStart(const UnitTest& unit_test, - int iteration) = 0; + // Gets the number of successful tests in this test case. + int successful_test_count() const; - // Fired before environment set-up for each iteration of tests starts. - virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0; + // Gets the number of failed tests in this test case. + int failed_test_count() const; - // Fired after environment set-up for each iteration of tests ends. - virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; + // Gets the number of disabled tests that will be reported in the XML report. + int reportable_disabled_test_count() const; - // Fired before the test case starts. - virtual void OnTestCaseStart(const TestCase& test_case) = 0; + // Gets the number of disabled tests in this test case. + int disabled_test_count() const; - // Fired before the test starts. - virtual void OnTestStart(const TestInfo& test_info) = 0; + // Gets the number of tests to be printed in the XML report. + int reportable_test_count() const; - // Fired after a failed assertion or a SUCCEED() invocation. - virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; + // Get the number of tests in this test case that should run. + int test_to_run_count() const; - // Fired after the test ends. - virtual void OnTestEnd(const TestInfo& test_info) = 0; + // Gets the number of all tests in this test case. + int total_test_count() const; - // Fired after the test case ends. + // Returns true iff the test case passed. + bool Passed() const { return !Failed(); } + + // Returns true iff the test case failed. + bool Failed() const { return failed_test_count() > 0; } + + // Returns the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns the i-th test among all the tests. i can range from 0 to + // total_test_count() - 1. If i is not in that range, returns NULL. + const TestInfo* GetTestInfo(int i) const; + + // Returns the TestResult that holds test properties recorded during + // execution of SetUpTestCase and TearDownTestCase. + const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; } + + private: + friend class Test; + friend class internal::UnitTestImpl; + + // Gets the (mutable) vector of TestInfos in this TestCase. + std::vector& test_info_list() { return test_info_list_; } + + // Gets the (immutable) vector of TestInfos in this TestCase. + const std::vector& test_info_list() const { + return test_info_list_; + } + + // Returns the i-th test among all the tests. i can range from 0 to + // total_test_count() - 1. If i is not in that range, returns NULL. + TestInfo* GetMutableTestInfo(int i); + + // Sets the should_run member. + void set_should_run(bool should) { should_run_ = should; } + + // Adds a TestInfo to this test case. Will delete the TestInfo upon + // destruction of the TestCase object. + void AddTestInfo(TestInfo * test_info); + + // Clears the results of all tests in this test case. + void ClearResult(); + + // Clears the results of all tests in the given test case. + static void ClearTestCaseResult(TestCase* test_case) { + test_case->ClearResult(); + } + + // Runs every test in this TestCase. + void Run(); + + // Runs SetUpTestCase() for this TestCase. This wrapper is needed + // for catching exceptions thrown from SetUpTestCase(). + void RunSetUpTestCase() { (*set_up_tc_)(); } + + // Runs TearDownTestCase() for this TestCase. This wrapper is + // needed for catching exceptions thrown from TearDownTestCase(). + void RunTearDownTestCase() { (*tear_down_tc_)(); } + + // Returns true iff test passed. + static bool TestPassed(const TestInfo* test_info) { + return test_info->should_run() && test_info->result()->Passed(); + } + + // Returns true iff test failed. + static bool TestFailed(const TestInfo* test_info) { + return test_info->should_run() && test_info->result()->Failed(); + } + + // Returns true iff the test is disabled and will be reported in the XML + // report. + static bool TestReportableDisabled(const TestInfo* test_info) { + return test_info->is_reportable() && test_info->is_disabled_; + } + + // Returns true iff test is disabled. + static bool TestDisabled(const TestInfo* test_info) { + return test_info->is_disabled_; + } + + // Returns true iff this test will appear in the XML report. + static bool TestReportable(const TestInfo* test_info) { + return test_info->is_reportable(); + } + + // Returns true if the given test should run. + static bool ShouldRunTest(const TestInfo* test_info) { + return test_info->should_run(); + } + + // Shuffles the tests in this test case. + void ShuffleTests(internal::Random* random); + + // Restores the test order to before the first shuffle. + void UnshuffleTests(); + + // Name of the test case. + std::string name_; + // Name of the parameter type, or NULL if this is not a typed or a + // type-parameterized test. + const internal::scoped_ptr type_param_; + // The vector of TestInfos in their original order. It owns the + // elements in the vector. + std::vector test_info_list_; + // Provides a level of indirection for the test list to allow easy + // shuffling and restoring the test order. The i-th element in this + // vector is the index of the i-th test in the shuffled test list. + std::vector test_indices_; + // Pointer to the function that sets up the test case. + Test::SetUpTestCaseFunc set_up_tc_; + // Pointer to the function that tears down the test case. + Test::TearDownTestCaseFunc tear_down_tc_; + // True iff any test in this test case should run. + bool should_run_; + // Elapsed time, in milliseconds. + TimeInMillis elapsed_time_; + // Holds test properties recorded during execution of SetUpTestCase and + // TearDownTestCase. + TestResult ad_hoc_test_result_; + + // We disallow copying TestCases. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); +}; + +// An Environment object is capable of setting up and tearing down an +// environment. You should subclass this to define your own +// environment(s). +// +// An Environment object does the set-up and tear-down in virtual +// methods SetUp() and TearDown() instead of the constructor and the +// destructor, as: +// +// 1. You cannot safely throw from a destructor. This is a problem +// as in some cases Google Test is used where exceptions are enabled, and +// we may want to implement ASSERT_* using exceptions where they are +// available. +// 2. You cannot use ASSERT_* directly in a constructor or +// destructor. +class Environment { + public: + // The d'tor is virtual as we need to subclass Environment. + virtual ~Environment() {} + + // Override this to define how to set up the environment. + virtual void SetUp() {} + + // Override this to define how to tear down the environment. + virtual void TearDown() {} + private: + // If you see an error about overriding the following function or + // about it being private, you have mis-spelled SetUp() as Setup(). + struct Setup_should_be_spelled_SetUp {}; + virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } +}; + +#if GTEST_HAS_EXCEPTIONS + +// Exception which can be thrown from TestEventListener::OnTestPartResult. +class GTEST_API_ AssertionException + : public internal::GoogleTestFailureException { + public: + explicit AssertionException(const TestPartResult& result) + : GoogleTestFailureException(result) {} +}; + +#endif // GTEST_HAS_EXCEPTIONS + +// The interface for tracing execution of tests. The methods are organized in +// the order the corresponding events are fired. +class TestEventListener { + public: + virtual ~TestEventListener() {} + + // Fired before any test activity starts. + virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; + + // Fired before each iteration of tests starts. There may be more than + // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration + // index, starting from 0. + virtual void OnTestIterationStart(const UnitTest& unit_test, + int iteration) = 0; + + // Fired before environment set-up for each iteration of tests starts. + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0; + + // Fired after environment set-up for each iteration of tests ends. + virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; + + // Fired before the test case starts. + virtual void OnTestCaseStart(const TestCase& test_case) = 0; + + // Fired before the test starts. + virtual void OnTestStart(const TestInfo& test_info) = 0; + + // Fired after a failed assertion or a SUCCEED() invocation. + // If you want to throw an exception from this function to skip to the next + // TEST, it must be AssertionException defined above, or inherited from it. + virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; + + // Fired after the test ends. + virtual void OnTestEnd(const TestInfo& test_info) = 0; + + // Fired after the test case ends. virtual void OnTestCaseEnd(const TestCase& test_case) = 0; // Fired before environment tear-down for each iteration of tests starts. @@ -19883,14 +21112,12 @@ class GTEST_API_ UnitTest { // Returns the random seed used at the start of the current test run. int random_seed() const; -#if GTEST_HAS_PARAM_TEST // Returns the ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. internal::ParameterizedTestCaseRegistry& parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_); -#endif // GTEST_HAS_PARAM_TEST // Gets the number of successful test cases. int successful_test_case_count() const; @@ -19992,9 +21219,9 @@ class GTEST_API_ UnitTest { // These classes and functions are friends as they need to access private // members of UnitTest. + friend class ScopedTrace; friend class Test; friend class internal::AssertHelper; - friend class internal::ScopedTrace; friend class internal::StreamingListenerTest; friend class internal::UnitTestRecordPropertyTestHelper; friend Environment* AddGlobalTestEnvironment(Environment* env); @@ -20091,11 +21318,9 @@ AssertionResult CmpHelperEQ(const char* lhs_expression, const char* rhs_expression, const T1& lhs, const T2& rhs) { -GTEST_DISABLE_MSC_WARNINGS_PUSH_(4389 /* signed/unsigned mismatch */) if (lhs == rhs) { return AssertionSuccess(); } -GTEST_DISABLE_MSC_WARNINGS_POP_() return CmpHelperEQFailure(lhs_expression, rhs_expression, lhs, rhs); } @@ -20394,8 +21619,8 @@ class GTEST_API_ AssertHelper { : type(t), file(srcfile), line(line_num), message(msg) { } TestPartResult::Type const type; - const char* const file; - int const line; + const char* const file; + int const line; std::string const message; private: @@ -20409,8 +21634,6 @@ class GTEST_API_ AssertHelper { } // namespace internal -#if GTEST_HAS_PARAM_TEST - namespace internal { // Static value used for accessing test parameter during a test lifetime. extern void* g_parameter_; @@ -20460,483 +21683,120 @@ class WithParamInterface { // constructor. This member function is non-static, even though it only // references static data, to reduce the opportunity for incorrect uses // like writing 'WithParamInterface::GetParam()' for a test that - // uses a fixture whose parameter type is int. - const ParamType& GetParam() const { - GTEST_CHECK_(GetParameterPtrRef_() != NULL) - << "GetParam() can only be called inside a value-parameterized test " - << "-- did you intend to write TEST_P instead of TEST_F?"; - return *GetParameterPtrRef_(); - } - - private: - // Sets parameter value. The caller is responsible for making sure the value - // remains alive and unchanged throughout the current test. - static void SetParam(const ParamType* parameter) { - GetParameterPtrRef_() = parameter; - } - - static const ParamType*& GetParameterPtrRef_() - { - return (const ParamType*&)internal::g_parameter_; - } - - // TestClass must be a subclass of WithParamInterface and Test. - template friend class /*internal::*/ParameterizedTestFactory; -}; - -// Most value-parameterized classes can ignore the existence of -// WithParamInterface, and can just inherit from ::testing::TestWithParam. - -template -class TestWithParam : public Test, public WithParamInterface { -}; - -#endif // GTEST_HAS_PARAM_TEST - -// Macros for indicating success/failure in test code. - -// ADD_FAILURE unconditionally adds a failure to the current test. -// SUCCEED generates a success - it doesn't automatically make the -// current test successful, as a test is only successful when it has -// no failure. -// -// EXPECT_* verifies that a certain condition is satisfied. If not, -// it behaves like ADD_FAILURE. In particular: -// -// EXPECT_TRUE verifies that a Boolean condition is true. -// EXPECT_FALSE verifies that a Boolean condition is false. -// -// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except -// that they will also abort the current function on failure. People -// usually want the fail-fast behavior of FAIL and ASSERT_*, but those -// writing data-driven tests often find themselves using ADD_FAILURE -// and EXPECT_* more. - -// Generates a nonfatal failure with a generic message. -#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed") - -// Generates a nonfatal failure at the given source file location with -// a generic message. -#define ADD_FAILURE_AT(file, line) \ - GTEST_MESSAGE_AT_(file, line, "Failed", \ - ::testing::TestPartResult::kNonFatalFailure) - -// Generates a fatal failure with a generic message. -#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") - -// Define this macro to 1 to omit the definition of FAIL(), which is a -// generic name and clashes with some other libraries. -#if !GTEST_DONT_DEFINE_FAIL -# define FAIL() GTEST_FAIL() -#endif - -// Generates a success with a generic message. -#define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded") - -// Define this macro to 1 to omit the definition of SUCCEED(), which -// is a generic name and clashes with some other libraries. -#if !GTEST_DONT_DEFINE_SUCCEED -# define SUCCEED() GTEST_SUCCEED() -#endif - -// Macros for testing exceptions. -// -// * {ASSERT|EXPECT}_THROW(statement, expected_exception): -// Tests that the statement throws the expected exception. -// * {ASSERT|EXPECT}_NO_THROW(statement): -// Tests that the statement doesn't throw any exception. -// * {ASSERT|EXPECT}_ANY_THROW(statement): -// Tests that the statement throws an exception. - -#define EXPECT_THROW(statement, expected_exception) \ - GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_) -#define EXPECT_NO_THROW(statement) \ - GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_) -#define EXPECT_ANY_THROW(statement) \ - GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_) -#define ASSERT_THROW(statement, expected_exception) \ - GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_) -#define ASSERT_NO_THROW(statement) \ - GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_) -#define ASSERT_ANY_THROW(statement) \ - GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_) - -// Boolean assertions. Condition can be either a Boolean expression or an -// AssertionResult. For more information on how to use AssertionResult with -// these macros see comments on that class. -#define EXPECT_TRUE(condition) \ - GTEST_TEST_BOOLEAN_((condition), #condition, false, true, \ - GTEST_NONFATAL_FAILURE_) -#define EXPECT_FALSE(condition) \ - GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ - GTEST_NONFATAL_FAILURE_) -#define ASSERT_TRUE(condition) \ - GTEST_TEST_BOOLEAN_((condition), #condition, false, true, \ - GTEST_FATAL_FAILURE_) -#define ASSERT_FALSE(condition) \ - GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ - GTEST_FATAL_FAILURE_) - -// Includes the auto-generated header that implements a family of -// generic predicate assertion macros. -// Copyright 2006, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// This file is AUTOMATICALLY GENERATED on 10/31/2011 by command -// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! -// -// Implements a family of generic predicate assertion macros. - -#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ -#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ - -// Makes sure this header is not included before gtest.h. -#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ -# error Do not include gtest_pred_impl.h directly. Include gtest.h instead. -#endif // GTEST_INCLUDE_GTEST_GTEST_H_ - -// This header implements a family of generic predicate assertion -// macros: -// -// ASSERT_PRED_FORMAT1(pred_format, v1) -// ASSERT_PRED_FORMAT2(pred_format, v1, v2) -// ... -// -// where pred_format is a function or functor that takes n (in the -// case of ASSERT_PRED_FORMATn) values and their source expression -// text, and returns a testing::AssertionResult. See the definition -// of ASSERT_EQ in gtest.h for an example. -// -// If you don't care about formatting, you can use the more -// restrictive version: -// -// ASSERT_PRED1(pred, v1) -// ASSERT_PRED2(pred, v1, v2) -// ... -// -// where pred is an n-ary function or functor that returns bool, -// and the values v1, v2, ..., must support the << operator for -// streaming to std::ostream. -// -// We also define the EXPECT_* variations. -// -// For now we only support predicates whose arity is at most 5. -// Please email googletestframework@googlegroups.com if you need -// support for higher arities. - -// GTEST_ASSERT_ is the basic statement to which all of the assertions -// in this file reduce. Don't use this in your code. - -#define GTEST_ASSERT_(expression, on_failure) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (const ::testing::AssertionResult gtest_ar = (expression)) \ - ; \ - else \ - on_failure(gtest_ar.failure_message()) - - -// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use -// this in your code. -template -AssertionResult AssertPred1Helper(const char* pred_text, - const char* e1, - Pred pred, - const T1& v1) { - if (pred(v1)) return AssertionSuccess(); - - return AssertionFailure() << pred_text << "(" - << e1 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1; -} - -// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. -// Don't use this in your code. -#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, v1), \ - on_failure) - -// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use -// this in your code. -#define GTEST_PRED1_(pred, v1, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \ - #v1, \ - pred, \ - v1), on_failure) - -// Unary predicate assertion macros. -#define EXPECT_PRED_FORMAT1(pred_format, v1) \ - GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_) -#define EXPECT_PRED1(pred, v1) \ - GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_) -#define ASSERT_PRED_FORMAT1(pred_format, v1) \ - GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_) -#define ASSERT_PRED1(pred, v1) \ - GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_) - - - -// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use -// this in your code. -template -AssertionResult AssertPred2Helper(const char* pred_text, - const char* e1, - const char* e2, - Pred pred, - const T1& v1, - const T2& v2) { - if (pred(v1, v2)) return AssertionSuccess(); - - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2; -} - -// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. -// Don't use this in your code. -#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), \ - on_failure) - -// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use -// this in your code. -#define GTEST_PRED2_(pred, v1, v2, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \ - #v1, \ - #v2, \ - pred, \ - v1, \ - v2), on_failure) - -// Binary predicate assertion macros. -#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \ - GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_) -#define EXPECT_PRED2(pred, v1, v2) \ - GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_) -#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \ - GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_) -#define ASSERT_PRED2(pred, v1, v2) \ - GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_) - - - -// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use -// this in your code. -template -AssertionResult AssertPred3Helper(const char* pred_text, - const char* e1, - const char* e2, - const char* e3, - Pred pred, - const T1& v1, - const T2& v2, - const T3& v3) { - if (pred(v1, v2, v3)) return AssertionSuccess(); - - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3; -} - -// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. -// Don't use this in your code. -#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3), \ - on_failure) - -// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use -// this in your code. -#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \ - #v1, \ - #v2, \ - #v3, \ - pred, \ - v1, \ - v2, \ - v3), on_failure) - -// Ternary predicate assertion macros. -#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \ - GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_) -#define EXPECT_PRED3(pred, v1, v2, v3) \ - GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_) -#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \ - GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_) -#define ASSERT_PRED3(pred, v1, v2, v3) \ - GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_) - + // uses a fixture whose parameter type is int. + const ParamType& GetParam() const { + GTEST_CHECK_(GetParameterPtrRef_() != NULL) + << "GetParam() can only be called inside a value-parameterized test " + << "-- did you intend to write TEST_P instead of TEST_F?"; + return *GetParameterPtrRef_(); + } + private: + // Sets parameter value. The caller is responsible for making sure the value + // remains alive and unchanged throughout the current test. + static void SetParam(const ParamType* parameter) { + GetParameterPtrRef_() = parameter; + } -// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use -// this in your code. -template -AssertionResult AssertPred4Helper(const char* pred_text, - const char* e1, - const char* e2, - const char* e3, - const char* e4, - Pred pred, - const T1& v1, - const T2& v2, - const T3& v3, - const T4& v4) { - if (pred(v1, v2, v3, v4)) return AssertionSuccess(); + static const ParamType*& GetParameterPtrRef_() + { + return (const ParamType*&)internal::g_parameter_; + } - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ", " - << e4 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3 - << "\n" << e4 << " evaluates to " << v4; -} + // TestClass must be a subclass of WithParamInterface and Test. + template friend class /*internal::*/ParameterizedTestFactory; +}; -// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. -// Don't use this in your code. -#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4), \ - on_failure) +// Most value-parameterized classes can ignore the existence of +// WithParamInterface, and can just inherit from ::testing::TestWithParam. -// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use -// this in your code. -#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \ - #v1, \ - #v2, \ - #v3, \ - #v4, \ - pred, \ - v1, \ - v2, \ - v3, \ - v4), on_failure) +template +class TestWithParam : public Test, public WithParamInterface { +}; -// 4-ary predicate assertion macros. -#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ - GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) -#define EXPECT_PRED4(pred, v1, v2, v3, v4) \ - GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) -#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ - GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) -#define ASSERT_PRED4(pred, v1, v2, v3, v4) \ - GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) +// Macros for indicating success/failure in test code. +// ADD_FAILURE unconditionally adds a failure to the current test. +// SUCCEED generates a success - it doesn't automatically make the +// current test successful, as a test is only successful when it has +// no failure. +// +// EXPECT_* verifies that a certain condition is satisfied. If not, +// it behaves like ADD_FAILURE. In particular: +// +// EXPECT_TRUE verifies that a Boolean condition is true. +// EXPECT_FALSE verifies that a Boolean condition is false. +// +// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except +// that they will also abort the current function on failure. People +// usually want the fail-fast behavior of FAIL and ASSERT_*, but those +// writing data-driven tests often find themselves using ADD_FAILURE +// and EXPECT_* more. +// Generates a nonfatal failure with a generic message. +#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed") -// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use -// this in your code. -template -AssertionResult AssertPred5Helper(const char* pred_text, - const char* e1, - const char* e2, - const char* e3, - const char* e4, - const char* e5, - Pred pred, - const T1& v1, - const T2& v2, - const T3& v3, - const T4& v4, - const T5& v5) { - if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); +// Generates a nonfatal failure at the given source file location with +// a generic message. +#define ADD_FAILURE_AT(file, line) \ + GTEST_MESSAGE_AT_(file, line, "Failed", \ + ::testing::TestPartResult::kNonFatalFailure) - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ", " - << e4 << ", " - << e5 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3 - << "\n" << e4 << " evaluates to " << v4 - << "\n" << e5 << " evaluates to " << v5; -} +// Generates a fatal failure with a generic message. +#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") -// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. -// Don't use this in your code. -#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5), \ - on_failure) +// Define this macro to 1 to omit the definition of FAIL(), which is a +// generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_FAIL +# define FAIL() GTEST_FAIL() +#endif -// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use -// this in your code. -#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \ - #v1, \ - #v2, \ - #v3, \ - #v4, \ - #v5, \ - pred, \ - v1, \ - v2, \ - v3, \ - v4, \ - v5), on_failure) +// Generates a success with a generic message. +#define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded") -// 5-ary predicate assertion macros. -#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ - GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) -#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \ - GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) -#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ - GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) -#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \ - GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) +// Define this macro to 1 to omit the definition of SUCCEED(), which +// is a generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_SUCCEED +# define SUCCEED() GTEST_SUCCEED() +#endif +// Macros for testing exceptions. +// +// * {ASSERT|EXPECT}_THROW(statement, expected_exception): +// Tests that the statement throws the expected exception. +// * {ASSERT|EXPECT}_NO_THROW(statement): +// Tests that the statement doesn't throw any exception. +// * {ASSERT|EXPECT}_ANY_THROW(statement): +// Tests that the statement throws an exception. +#define EXPECT_THROW(statement, expected_exception) \ + GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_) +#define EXPECT_NO_THROW(statement) \ + GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_) +#define EXPECT_ANY_THROW(statement) \ + GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_) +#define ASSERT_THROW(statement, expected_exception) \ + GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_) +#define ASSERT_NO_THROW(statement) \ + GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_) +#define ASSERT_ANY_THROW(statement) \ + GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_) -#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ +// Boolean assertions. Condition can be either a Boolean expression or an +// AssertionResult. For more information on how to use AssertionResult with +// these macros see comments on that class. +#define EXPECT_TRUE(condition) \ + GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ + GTEST_NONFATAL_FAILURE_) +#define EXPECT_FALSE(condition) \ + GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ + GTEST_NONFATAL_FAILURE_) +#define ASSERT_TRUE(condition) \ + GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ + GTEST_FATAL_FAILURE_) +#define ASSERT_FALSE(condition) \ + GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ + GTEST_FATAL_FAILURE_) // Macros for testing equalities and inequalities. // @@ -20979,8 +21839,8 @@ AssertionResult AssertPred5Helper(const char* pred_text, // // Examples: // -// EXPECT_NE(5, Foo()); -// EXPECT_EQ(NULL, a_pointer); +// EXPECT_NE(Foo(), 5); +// EXPECT_EQ(a_pointer, NULL); // ASSERT_LT(i, array_size); // ASSERT_GT(records.size(), 0) << "There is no record left."; @@ -21166,6 +22026,57 @@ GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, #define EXPECT_NO_FATAL_FAILURE(statement) \ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) +// Causes a trace (including the given source file path and line number, +// and the given message) to be included in every test failure message generated +// by code in the scope of the lifetime of an instance of this class. The effect +// is undone with the destruction of the instance. +// +// The message argument can be anything streamable to std::ostream. +// +// Example: +// testing::ScopedTrace trace("file.cc", 123, "message"); +// +class GTEST_API_ ScopedTrace { + public: + // The c'tor pushes the given source file location and message onto + // a trace stack maintained by Google Test. + + // Template version. Uses Message() to convert the values into strings. + // Slow, but flexible. + template + ScopedTrace(const char* file, int line, const T& message) { + PushTrace(file, line, (Message() << message).GetString()); + } + + // Optimize for some known types. + ScopedTrace(const char* file, int line, const char* message) { + PushTrace(file, line, message ? message : "(null)"); + } + +#if GTEST_HAS_GLOBAL_STRING + ScopedTrace(const char* file, int line, const ::string& message) { + PushTrace(file, line, message); + } +#endif + + ScopedTrace(const char* file, int line, const std::string& message) { + PushTrace(file, line, message); + } + + // The d'tor pops the info pushed by the c'tor. + // + // Note that the d'tor is not virtual in order to be efficient. + // Don't inherit from ScopedTrace! + ~ScopedTrace(); + + private: + void PushTrace(const char* file, int line, std::string message); + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); +} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its + // c'tor and d'tor. Therefore it doesn't + // need to be used otherwise. + // Causes a trace (including the source file path, the current line // number, and the given message) to be included in every test failure // message generated by code in the current scope. The effect is @@ -21177,9 +22088,14 @@ GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, // of the dummy variable name, thus allowing multiple SCOPED_TRACE()s // to appear in the same block - as long as they are on different // lines. +// +// Assuming that each thread maintains its own stack of traces. +// Therefore, a SCOPED_TRACE() would (correctly) only affect the +// assertions in its own thread. #define SCOPED_TRACE(message) \ - ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ - __FILE__, __LINE__, ::testing::Message() << (message)) + ::testing::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ + __FILE__, __LINE__, (message)) + // Compile-time assertion for type equality. // StaticAssertTypeEq() compiles iff type1 and type2 are @@ -21259,7 +22175,7 @@ bool StaticAssertTypeEq() { // name of the test within the test case. // // A test fixture class must be declared earlier. The user should put -// his test code between braces after using this macro. Example: +// the test code between braces after using this macro. Example: // // class FooTest : public testing::Test { // protected: @@ -21274,14 +22190,22 @@ bool StaticAssertTypeEq() { // } // // TEST_F(FooTest, ReturnsElementCountCorrectly) { -// EXPECT_EQ(0, a_.size()); -// EXPECT_EQ(1, b_.size()); +// EXPECT_EQ(a_.size(), 0); +// EXPECT_EQ(b_.size(), 1); // } #define TEST_F(test_fixture, test_name)\ GTEST_TEST_(test_fixture, test_name, test_fixture, \ ::testing::internal::GetTypeId()) +// Returns a path to temporary directory. +// Tries to determine an appropriate directory for the platform. +GTEST_API_ std::string TempDir(); + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + } // namespace testing // Use this function in main() to run all tests. It returns 0 if all @@ -21298,4 +22222,6 @@ inline int RUN_ALL_TESTS() { return ::testing::UnitTest::GetInstance()->Run(); } +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_INCLUDE_GTEST_GTEST_H_ diff --git a/modules/ts/misc/run.py b/modules/ts/misc/run.py index 74b353a53275..29c0aa6b90a6 100755 --- a/modules/ts/misc/run.py +++ b/modules/ts/misc/run.py @@ -40,6 +40,9 @@ parser.add_argument("--valgrind_supp", metavar="FILE", action='append', help="Path to valgrind suppression file (example: --valgrind_supp opencv/platforms/scripts/valgrind.supp)") parser.add_argument("--valgrind_opt", metavar="OPT", action="append", default=[], help="Add command line option to valgrind (example: --valgrind_opt=--leak-check=full)") + # QEMU + parser.add_argument("--qemu", default="", help="Specify qemu binary and base parameters") + # Android parser.add_argument("--android", action="store_true", default=False, help="Android: force all tests to run on device") parser.add_argument("--android_sdk", metavar="PATH", help="Android: path to SDK to use adb and aapt tools") diff --git a/modules/ts/misc/run_suite.py b/modules/ts/misc/run_suite.py index 947db1e2b5f0..c7103a6263a5 100644 --- a/modules/ts/misc/run_suite.py +++ b/modules/ts/misc/run_suite.py @@ -77,7 +77,7 @@ def isTest(self, fullpath): return False return os.access(fullpath, os.X_OK) - def wrapInValgrind(self, cmd=[]): + def wrapCommand(self, cmd, env): if self.options.valgrind: res = ['valgrind'] supp = self.options.valgrind_supp or [] @@ -89,6 +89,14 @@ def wrapInValgrind(self, cmd=[]): res.extend(self.options.valgrind_opt) has_gtest_filter = next((True for x in cmd if x.startswith('--gtest_filter=')), False) return res + cmd + ([longTestFilter(LONG_TESTS_DEBUG_VALGRIND)] if not has_gtest_filter else []) + elif self.options.qemu: + import shlex + res = shlex.split(self.options.qemu) + for (name, value) in [entry for entry in os.environ.items() if entry[0].startswith('OPENCV') and not entry[0] in env]: + res += ['-E', '"{}={}"'.format(name, value)] + for (name, value) in env.items(): + res += ['-E', '"{}={}"'.format(name, value)] + return res + ['--'] + cmd return cmd def tryCommand(self, cmd, workingDir): @@ -125,7 +133,6 @@ def runTest(self, path, logfile, workingDir, args=[]): else: if isColorEnabled(args): args.append("--gtest_color=yes") - cmd = self.wrapInValgrind([exe] + args) env = {} if not self.options.valgrind and self.options.trace: env['OPENCV_TRACE'] = '1' @@ -133,6 +140,7 @@ def runTest(self, path, logfile, workingDir, args=[]): env['OPENCV_TRACE_SYNC_OPENCL'] = '1' tempDir = TempEnvDir('OPENCV_TEMP_PATH', "__opencv_temp.") tempDir.init() + cmd = self.wrapCommand([exe] + args, env) log.warning("Run: %s" % " ".join(cmd)) ret = execute(cmd, cwd=workingDir, env=env) try: diff --git a/modules/ts/src/ts.cpp b/modules/ts/src/ts.cpp index 66dd7656be48..67f48d5041bd 100644 --- a/modules/ts/src/ts.cpp +++ b/modules/ts/src/ts.cpp @@ -721,6 +721,7 @@ void checkIppStatus() } } +static bool checkTestData = false; bool skipUnstableTests = false; bool runBigDataTests = false; int testThreads = 0; @@ -733,6 +734,7 @@ void parseCustomOptions(int argc, char **argv) "{ test_threads |-1 |the number of worker threads, if parallel execution is enabled}" "{ skip_unstable |false |skip unstable tests }" "{ test_bigdata |false |run BigData tests (>=2Gb) }" + "{ test_require_data |false |fail on missing non-required test data instead of skip}" "{ h help |false |print help info }"; cv::CommandLineParser parser(argc, argv, command_line_keys); @@ -756,6 +758,7 @@ void parseCustomOptions(int argc, char **argv) skipUnstableTests = parser.get("skip_unstable"); runBigDataTests = parser.get("test_bigdata"); + checkTestData = parser.get("test_require_data"); } @@ -870,7 +873,7 @@ static std::string findData(const std::string& relative_path, bool required, boo #endif #endif const char* type = findDirectory ? "directory" : "data file"; - if (required) + if (required || checkTestData) CV_Error(cv::Error::StsError, cv::format("OpenCV tests: Can't find required %s: %s", type, relative_path.c_str())); throw SkipTestException(cv::format("OpenCV tests: Can't find %s: %s", type, relative_path.c_str())); } diff --git a/modules/ts/src/ts_gtest.cpp b/modules/ts/src/ts_gtest.cpp index f71efbb0eb68..3bcd09893e6f 100644 --- a/modules/ts/src/ts_gtest.cpp +++ b/modules/ts/src/ts_gtest.cpp @@ -26,10 +26,9 @@ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + // -// Author: mheule@google.com (Markus Heule) -// -// Google C++ Testing Framework (Google Test) +// Google C++ Testing and Mocking Framework (Google Test) // // Sometimes it's desirable to build Google Test by compiling a single file. // This file serves this purpose. @@ -75,10 +74,9 @@ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + // -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // Copyright 2007, Google Inc. // All rights reserved. @@ -108,16 +106,20 @@ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan) + // // Utilities for testing Google Test itself and code that uses Google Test // (e.g. frameworks built on top of Google Test). +// GOOGLETEST_CM0004 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ #define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + namespace testing { // This helper class can be used to mock out Google Test failure reporting @@ -178,13 +180,12 @@ class GTEST_API_ SingleFailureChecker { public: // The constructor remembers the arguments. SingleFailureChecker(const TestPartResultArray* results, - TestPartResult::Type type, - const string& substr); + TestPartResult::Type type, const std::string& substr); ~SingleFailureChecker(); private: const TestPartResultArray* const results_; const TestPartResult::Type type_; - const string substr_; + const std::string substr_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker); }; @@ -193,6 +194,8 @@ class GTEST_API_ SingleFailureChecker { } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + // A set of macros for testing Google Test assertions or code that's expected // to generate Google Test fatal failures. It verifies that the given // statement will cause exactly one fatal Google Test failure with 'substr' @@ -332,7 +335,7 @@ class GTEST_API_ SingleFailureChecker { #if GTEST_OS_LINUX -// TODO(kenton@google.com): Use autoconf to detect availability of +// FIXME: Use autoconf to detect availability of // gettimeofday(). # define GTEST_HAS_GETTIMEOFDAY_ 1 @@ -371,9 +374,9 @@ class GTEST_API_ SingleFailureChecker { # if GTEST_OS_WINDOWS_MINGW // MinGW has gettimeofday() but not _ftime64(). -// TODO(kenton@google.com): Use autoconf to detect availability of +// FIXME: Use autoconf to detect availability of // gettimeofday(). -// TODO(kenton@google.com): There are other ways to get the time on +// FIXME: There are other ways to get the time on // Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW // supports these. consider using them instead. # define GTEST_HAS_GETTIMEOFDAY_ 1 @@ -388,7 +391,7 @@ class GTEST_API_ SingleFailureChecker { #else // Assume other platforms have gettimeofday(). -// TODO(kenton@google.com): Use autoconf to detect availability of +// FIXME: Use autoconf to detect availability of // gettimeofday(). # define GTEST_HAS_GETTIMEOFDAY_ 1 @@ -410,12 +413,6 @@ class GTEST_API_ SingleFailureChecker { # include // NOLINT #endif -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 // Copyright 2005, Google Inc. // All rights reserved. // @@ -445,24 +442,13 @@ class GTEST_API_ SingleFailureChecker { // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Utility functions and classes used by the Google C++ testing framework. -// -// Author: wan@google.com (Zhanyong Wan) -// +// Utility functions and classes used by the Google C++ testing framework.// // This file contains purely Google Test's internal implementation. Please // DO NOT #INCLUDE IT IN A USER PROGRAM. #ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ #define GTEST_SRC_GTEST_INTERNAL_INL_H_ -// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is -// part of Google Test's implementation; otherwise it's undefined. -#if !GTEST_IMPLEMENTATION_ -// If this file is included from the user's code, just say no. -# error "gtest-internal-inl.h is part of Google Test's internal implementation." -# error "It must not be included except by Google Test itself." -#endif // GTEST_IMPLEMENTATION_ - #ifndef _WIN32_WCE # include #endif // !_WIN32_WCE @@ -485,6 +471,9 @@ class GTEST_API_ SingleFailureChecker { #endif // GTEST_OS_WINDOWS +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + namespace testing { // Declares the flags. @@ -510,6 +499,7 @@ const char kParamFilterFlag[] = "param_filter"; const char kListTestsFlag[] = "list_tests"; const char kOutputFlag[] = "output"; const char kPrintTimeFlag[] = "print_time"; +const char kPrintUTF8Flag[] = "print_utf8"; const char kRandomSeedFlag[] = "random_seed"; const char kRepeatFlag[] = "repeat"; const char kShuffleFlag[] = "shuffle"; @@ -591,6 +581,7 @@ class GTestFlagSaver { list_tests_ = GTEST_FLAG(list_tests); output_ = GTEST_FLAG(output); print_time_ = GTEST_FLAG(print_time); + print_utf8_ = GTEST_FLAG(print_utf8); random_seed_ = GTEST_FLAG(random_seed); repeat_ = GTEST_FLAG(repeat); shuffle_ = GTEST_FLAG(shuffle); @@ -613,6 +604,7 @@ class GTestFlagSaver { GTEST_FLAG(list_tests) = list_tests_; GTEST_FLAG(output) = output_; GTEST_FLAG(print_time) = print_time_; + GTEST_FLAG(print_utf8) = print_utf8_; GTEST_FLAG(random_seed) = random_seed_; GTEST_FLAG(repeat) = repeat_; GTEST_FLAG(shuffle) = shuffle_; @@ -635,6 +627,7 @@ class GTestFlagSaver { bool list_tests_; std::string output_; bool print_time_; + bool print_utf8_; internal::Int32 random_seed_; internal::Int32 repeat_; bool shuffle_; @@ -845,7 +838,7 @@ class OsStackTraceGetterInterface { // in the trace. // skip_count - the number of top frames to be skipped; doesn't count // against max_depth. - virtual string CurrentStackTrace(int max_depth, int skip_count) = 0; + virtual std::string CurrentStackTrace(int max_depth, int skip_count) = 0; // UponLeavingGTest() should be called immediately before Google Test calls // user code. It saves some information about the current stack that @@ -865,10 +858,20 @@ class OsStackTraceGetter : public OsStackTraceGetterInterface { public: OsStackTraceGetter() {} - virtual string CurrentStackTrace(int max_depth, int skip_count); + virtual std::string CurrentStackTrace(int max_depth, int skip_count); virtual void UponLeavingGTest(); private: +#if GTEST_HAS_ABSL + Mutex mutex_; // Protects all internal state. + + // We save the stack frame below the frame that calls user code. + // We do this because the address of the frame immediately below + // the user code changes between the call to UponLeavingGTest() + // and any calls to the stack trace code from within the user code. + void* caller_frame_ = nullptr; +#endif // GTEST_HAS_ABSL + GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); }; @@ -1083,13 +1086,11 @@ class GTEST_API_ UnitTestImpl { tear_down_tc)->AddTestInfo(test_info); } -#if GTEST_HAS_PARAM_TEST // Returns ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { return parameterized_test_registry_; } -#endif // GTEST_HAS_PARAM_TEST // Sets the TestCase object for the test that's currently running. void set_current_test_case(TestCase* a_current_test_case) { @@ -1264,14 +1265,12 @@ class GTEST_API_ UnitTestImpl { // shuffled order. std::vector test_case_indices_; -#if GTEST_HAS_PARAM_TEST // ParameterizedTestRegistry object used to register value-parameterized // tests. internal::ParameterizedTestCaseRegistry parameterized_test_registry_; // Indicates whether RegisterParameterizedTests() has been called already. bool parameterized_tests_registered_; -#endif // GTEST_HAS_PARAM_TEST // Index of the last death test case registered. Initially -1. int last_death_test_case_; @@ -1359,7 +1358,6 @@ GTEST_API_ bool IsAsciiWhiteSpace(char ch); GTEST_API_ bool IsAsciiWordChar(char ch); GTEST_API_ bool IsValidEscape(char ch); GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); -GTEST_API_ std::string FormatRegexSyntaxError(const char* regex, int index); GTEST_API_ bool ValidateRegex(const char* regex); GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str); GTEST_API_ bool MatchRepetitionAndRegexAtHead( @@ -1412,7 +1410,7 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) { const bool parse_success = *end == '\0' && errno == 0; - // TODO(vladl@google.com): Convert this to compile time assertion when it is + // FIXME: Convert this to compile time assertion when it is // available. GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); @@ -1452,7 +1450,7 @@ class TestResultAccessor { #if GTEST_CAN_STREAM_RESULTS_ // Streams test results to the given port on the given host machine. -class GTEST_API_ StreamingListener : public EmptyTestEventListener { +class StreamingListener : public EmptyTestEventListener { public: // Abstract base class for writing strings to a socket. class AbstractSocketWriter { @@ -1460,21 +1458,19 @@ class GTEST_API_ StreamingListener : public EmptyTestEventListener { virtual ~AbstractSocketWriter() {} // Sends a string to the socket. - virtual void Send(const string& message) = 0; + virtual void Send(const std::string& message) = 0; // Closes the socket. virtual void CloseConnection() {} // Sends a string and a newline to the socket. - void SendLn(const string& message) { - Send(message + "\n"); - } + void SendLn(const std::string& message) { Send(message + "\n"); } }; // Concrete class for actually writing strings to a socket. class SocketWriter : public AbstractSocketWriter { public: - SocketWriter(const string& host, const string& port) + SocketWriter(const std::string& host, const std::string& port) : sockfd_(-1), host_name_(host), port_num_(port) { MakeConnection(); } @@ -1485,7 +1481,7 @@ class GTEST_API_ StreamingListener : public EmptyTestEventListener { } // Sends a string to the socket. - virtual void Send(const string& message) { + virtual void Send(const std::string& message) { GTEST_CHECK_(sockfd_ != -1) << "Send() can be called only when there is a connection."; @@ -1511,17 +1507,19 @@ class GTEST_API_ StreamingListener : public EmptyTestEventListener { } int sockfd_; // socket file descriptor - const string host_name_; - const string port_num_; + const std::string host_name_; + const std::string port_num_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter); }; // class SocketWriter // Escapes '=', '&', '%', and '\n' characters in str as "%xx". - static string UrlEncode(const char* str); + static std::string UrlEncode(const char* str); - StreamingListener(const string& host, const string& port) - : socket_writer_(new SocketWriter(host, port)) { Start(); } + StreamingListener(const std::string& host, const std::string& port) + : socket_writer_(new SocketWriter(host, port)) { + Start(); + } explicit StreamingListener(AbstractSocketWriter* socket_writer) : socket_writer_(socket_writer) { Start(); } @@ -1582,13 +1580,13 @@ class GTEST_API_ StreamingListener : public EmptyTestEventListener { private: // Sends the given message and a newline to the socket. - void SendLn(const string& message) { socket_writer_->SendLn(message); } + void SendLn(const std::string& message) { socket_writer_->SendLn(message); } // Called at the start of streaming to notify the receiver what // protocol we are using. void Start() { SendLn("gtest_streaming_protocol_version=1.0"); } - string FormatBool(bool value) { return value ? "1" : "0"; } + std::string FormatBool(bool value) { return value ? "1" : "0"; } const scoped_ptr socket_writer_; @@ -1600,13 +1598,27 @@ class GTEST_API_ StreamingListener : public EmptyTestEventListener { } // namespace internal } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ -#undef GTEST_IMPLEMENTATION_ #if GTEST_OS_WINDOWS # define vsnprintf _vsnprintf #endif // GTEST_OS_WINDOWS +#if GTEST_OS_MAC +#ifndef GTEST_OS_IOS +#include +#endif +#endif + +#if GTEST_HAS_ABSL +#include "absl/debugging/failure_signal_handler.h" +#include "absl/debugging/stacktrace.h" +#include "absl/debugging/symbolize.h" +#include "absl/strings/str_cat.h" +#endif // GTEST_HAS_ABSL + namespace testing { using internal::CountIf; @@ -1628,8 +1640,10 @@ static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; // A test filter that matches everything. static const char kUniversalFilter[] = "*"; -// The default output file for XML output. -static const char kDefaultOutputFile[] = "test_detail.xml"; +// The default output format. +static const char kDefaultOutputFormat[] = "xml"; +// The default output file. +static const char kDefaultOutputFile[] = "test_detail"; // The environment variable name for the test shard index. static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; @@ -1648,15 +1662,31 @@ const char kStackTraceMarker[] = "\nStack trace:\n"; // specified on the command line. bool g_help_flag = false; +// Utilty function to Open File for Writing +static FILE* OpenFileForWriting(const std::string& output_file) { + FILE* fileout = NULL; + FilePath output_file_path(output_file); + FilePath output_dir(output_file_path.RemoveFileName()); + + if (output_dir.CreateDirectoriesRecursively()) { + fileout = posix::FOpen(output_file.c_str(), "w"); + } + if (fileout == NULL) { + GTEST_LOG_(FATAL) << "Unable to open file \"" << output_file << "\""; + } + return fileout; +} + } // namespace internal +// Bazel passes in the argument to '--test_filter' via the TESTBRIDGE_TEST_ONLY +// environment variable. static const char* GetDefaultFilter() { -#ifdef GTEST_TEST_FILTER_ENV_VAR_ - const char* const testbridge_test_only = getenv(GTEST_TEST_FILTER_ENV_VAR_); + const char* const testbridge_test_only = + internal::posix::GetEnv("TESTBRIDGE_TEST_ONLY"); if (testbridge_test_only != NULL) { return testbridge_test_only; } -#endif // GTEST_TEST_FILTER_ENV_VAR_ return kUniversalFilter; } @@ -1693,6 +1723,13 @@ GTEST_DEFINE_string_( "exclude). A test is run if it matches one of the positive " "patterns and does not match any of the negative patterns."); +GTEST_DEFINE_bool_( + install_failure_signal_handler, + internal::BoolFromGTestEnv("install_failure_signal_handler", false), + "If true and supported on the current platform, " GTEST_NAME_ " should " + "install a signal handler that dumps debugging information when fatal " + "signals are raised."); + GTEST_DEFINE_string_( param_filter, internal::StringFromGTestEnv("param_filter", GetDefaultFilter()), @@ -1702,12 +1739,18 @@ GTEST_DEFINE_string_( GTEST_DEFINE_bool_(list_tests, false, "List all tests without running them."); +// The net priority order after flag processing is thus: +// --gtest_output command line flag +// GTEST_OUTPUT environment variable +// XML_OUTPUT_FILE environment variable +// '' GTEST_DEFINE_string_( output, - internal::StringFromGTestEnv("output", ""), - "A format (currently must be \"xml\"), optionally followed " - "by a colon and an output file name or directory. A directory " - "is indicated by a trailing pathname separator. " + internal::StringFromGTestEnv("output", + internal::OutputFlagAlsoCheckEnvVar().c_str()), + "A format (defaults to \"xml\" but can be specified to be \"json\"), " + "optionally followed by a colon and an output file name or directory. " + "A directory is indicated by a trailing pathname separator. " "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " "If a directory is specified, output files will be created " "within that directory, with file-names based on the test " @@ -1720,6 +1763,12 @@ GTEST_DEFINE_bool_( "True iff " GTEST_NAME_ " should display elapsed time in text output."); +GTEST_DEFINE_bool_( + print_utf8, + internal::BoolFromGTestEnv("print_utf8", true), + "True iff " GTEST_NAME_ + " prints UTF8 characters as text."); + GTEST_DEFINE_int32_( random_seed, internal::Int32FromGTestEnv("random_seed", 0), @@ -1761,7 +1810,7 @@ GTEST_DEFINE_bool_( internal::BoolFromGTestEnv("throw_on_failure", false), "When this flag is specified, a failed assertion will throw an exception " "if exceptions are enabled or exit the program with a non-zero code " - "otherwise."); + "otherwise. For use with an external test framework."); #if GTEST_USE_OWN_FLAGFILE_FLAG_ GTEST_DEFINE_string_( @@ -1777,7 +1826,8 @@ namespace internal { // than kMaxRange. UInt32 Random::Generate(UInt32 range) { // These constants are the same as are used in glibc's rand(3). - state_ = (1103515245U*state_ + 12345U) % kMaxRange; + // Use wider types than necessary to prevent unsigned overflow diagnostics. + state_ = static_cast(1103515245ULL*state_ + 12345U) % kMaxRange; GTEST_CHECK_(range > 0) << "Cannot generate a number in the range [0, 0)."; @@ -1851,12 +1901,15 @@ void AssertHelper::operator=(const Message& message) const { GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); // A copy of all command line arguments. Set by InitGoogleTest(). -::std::vector g_argvs; +static ::std::vector g_argvs; -const ::std::vector& GetArgvs() { +::std::vector GetArgvs() { #if defined(GTEST_CUSTOM_GET_ARGVS_) - return GTEST_CUSTOM_GET_ARGVS_(); -#else // defined(GTEST_CUSTOM_GET_ARGVS_) + // GTEST_CUSTOM_GET_ARGVS_() may return a container of std::string or + // ::string. This code converts it to the appropriate type. + const auto& custom = GTEST_CUSTOM_GET_ARGVS_(); + return ::std::vector(custom.begin(), custom.end()); +#else // defined(GTEST_CUSTOM_GET_ARGVS_) return g_argvs; #endif // defined(GTEST_CUSTOM_GET_ARGVS_) } @@ -1880,8 +1933,6 @@ FilePath GetCurrentExecutableName() { // Returns the output format, or "" for normal printed output. std::string UnitTestOptions::GetOutputFormat() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); - if (gtest_output_flag == NULL) return std::string(""); - const char* const colon = strchr(gtest_output_flag, ':'); return (colon == NULL) ? std::string(gtest_output_flag) : @@ -1892,19 +1943,22 @@ std::string UnitTestOptions::GetOutputFormat() { // was explicitly specified. std::string UnitTestOptions::GetAbsolutePathToOutputFile() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); - if (gtest_output_flag == NULL) - return ""; + + std::string format = GetOutputFormat(); + if (format.empty()) + format = std::string(kDefaultOutputFormat); const char* const colon = strchr(gtest_output_flag, ':'); if (colon == NULL) - return internal::FilePath::ConcatPaths( + return internal::FilePath::MakeFileName( internal::FilePath( UnitTest::GetInstance()->original_working_dir()), - internal::FilePath(kDefaultOutputFile)).string(); + internal::FilePath(kDefaultOutputFile), 0, + format.c_str()).string(); internal::FilePath output_name(colon + 1); if (!output_name.IsAbsolutePath()) - // TODO(wan@google.com): on Windows \some\path is not an absolute + // FIXME: on Windows \some\path is not an absolute // path (as its meaning depends on the current drive), yet the // following logic for turning it into an absolute path is wrong. // Fix it. @@ -2096,11 +2150,11 @@ extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); // failure of the given type and that the failure message contains the // given substring. static AssertionResult HasOneFailure(const char* /* results_expr */, - const char* /* type_expr */, - const char* /* substr_expr */, - const TestPartResultArray& results, - TestPartResult::Type type, - const string& substr) { + const char* /* type_expr */, + const char* /* substr_expr */, + const TestPartResultArray& results, + TestPartResult::Type type, + const std::string& substr) { const std::string expected(type == TestPartResult::kFatalFailure ? "1 fatal failure" : "1 non-fatal failure"); @@ -2134,13 +2188,10 @@ static AssertionResult HasOneFailure(const char* /* results_expr */, // The constructor of SingleFailureChecker remembers where to look up // test part results, what type of failure we expect, and what // substring the failure message should contain. -SingleFailureChecker:: SingleFailureChecker( - const TestPartResultArray* results, - TestPartResult::Type type, - const string& substr) - : results_(results), - type_(type), - substr_(substr) {} +SingleFailureChecker::SingleFailureChecker(const TestPartResultArray* results, + TestPartResult::Type type, + const std::string& substr) + : results_(results), type_(type), substr_(substr) {} // The destructor of SingleFailureChecker verifies that the given // TestPartResultArray contains exactly one failure that has the given @@ -2281,7 +2332,7 @@ TimeInMillis GetTimeInMillis() { SYSTEMTIME now_systime; FILETIME now_filetime; ULARGE_INTEGER now_int64; - // TODO(kenton@google.com): Shouldn't this just use + // FIXME: Shouldn't this just use // GetSystemTimeAsFileTime()? GetSystemTime(&now_systime); if (SystemTimeToFileTime(&now_systime, &now_filetime)) { @@ -2297,11 +2348,11 @@ TimeInMillis GetTimeInMillis() { // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 // (deprecated function) there. - // TODO(kenton@google.com): Use GetTickCount()? Or use + // FIXME: Use GetTickCount()? Or use // SystemTimeToFileTime() - GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) + GTEST_DISABLE_MSC_DEPRECATED_PUSH_() _ftime64(&now); - GTEST_DISABLE_MSC_WARNINGS_POP_() + GTEST_DISABLE_MSC_DEPRECATED_POP_() return static_cast(now.time) * 1000 + now.millitm; #elif GTEST_HAS_GETTIMEOFDAY_ @@ -2782,13 +2833,14 @@ AssertionResult EqFailure(const char* lhs_expression, const std::string& rhs_value, bool ignoring_case) { Message msg; - msg << " Expected: " << lhs_expression; + msg << "Expected equality of these values:"; + msg << "\n " << lhs_expression; if (lhs_value != lhs_expression) { - msg << "\n Which is: " << lhs_value; + msg << "\n Which is: " << lhs_value; } - msg << "\nTo be equal to: " << rhs_expression; + msg << "\n " << rhs_expression; if (rhs_value != rhs_expression) { - msg << "\n Which is: " << rhs_value; + msg << "\n Which is: " << rhs_value; } if (ignoring_case) { @@ -2835,7 +2887,7 @@ AssertionResult DoubleNearPredFormat(const char* expr1, const double diff = fabs(val1 - val2); if (diff <= abs_error) return AssertionSuccess(); - // TODO(wan): do not print the value of an expression if it's + // FIXME: do not print the value of an expression if it's // already a literal. return AssertionFailure() << "The difference between " << expr1 << " and " << expr2 @@ -3130,7 +3182,7 @@ namespace { AssertionResult HRESULTFailureHelper(const char* expr, const char* expected, long hr) { // NOLINT -# if GTEST_OS_WINDOWS_MOBILE +# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_TV_TITLE // Windows CE doesn't support FormatMessage. const char error_text[] = ""; @@ -3187,7 +3239,7 @@ AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT // Utility functions for encoding Unicode text (wide strings) in // UTF-8. -// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8 +// A Unicode code-point can have up to 21 bits, and is encoded in UTF-8 // like this: // // Code-point length Encoding @@ -3251,7 +3303,7 @@ std::string CodePointToUtf8(UInt32 code_point) { return str; } -// The following two functions only make sense if the the system +// The following two functions only make sense if the system // uses UTF-16 for wide string encoding. All supported systems // with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. @@ -3563,13 +3615,8 @@ static const char* const kReservedTestSuiteAttributes[] = { // The list of reserved attributes used in the element of XML output. static const char* const kReservedTestCaseAttributes[] = { - "classname", - "name", - "status", - "time", - "type_param", - "value_param" -}; + "classname", "name", "status", "time", + "type_param", "value_param", "file", "line"}; template std::vector ArrayAsVector(const char* const (&array)[kSize]) { @@ -3605,8 +3652,9 @@ static std::string FormatWordList(const std::vector& words) { return word_list.GetString(); } -static bool ValidateTestPropertyName(const std::string& property_name, - const std::vector& reserved_names) { +static bool ValidateTestPropertyName( + const std::string& property_name, + const std::vector& reserved_names) { if (std::find(reserved_names.begin(), reserved_names.end(), property_name) != reserved_names.end()) { ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name @@ -3834,7 +3882,7 @@ static std::string PrintTestPartResultToString( GoogleTestFailureException::GoogleTestFailureException( const TestPartResult& failure) - : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} + : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} #endif // GTEST_HAS_EXCEPTIONS @@ -3903,6 +3951,8 @@ Result HandleExceptionsInMethodIfSupported( #if GTEST_HAS_EXCEPTIONS try { return HandleSehExceptionsInMethodIfSupported(object, method, location); + } catch (const AssertionException&) { // NOLINT + // This failure was reported already. } catch (const internal::GoogleTestFailureException&) { // NOLINT // This exception type can only be thrown by a failed Google // Test assertion with the intention of letting another testing @@ -4024,7 +4074,6 @@ TestInfo* MakeAndRegisterTestInfo( return test_info; } -#if GTEST_HAS_PARAM_TEST void ReportInvalidTestCaseType(const char* test_case_name, CodeLocation code_location) { Message errors; @@ -4038,13 +4087,10 @@ void ReportInvalidTestCaseType(const char* test_case_name, << "probably rename one of the classes to put the tests into different\n" << "test cases."; - fprintf(stderr, "%s %s", - FormatFileLocation(code_location.file.c_str(), - code_location.line).c_str(), - errors.GetString().c_str()); + GTEST_LOG_(ERROR) << FormatFileLocation(code_location.file.c_str(), + code_location.line) + << " " << errors.GetString(); } -#endif // GTEST_HAS_PARAM_TEST - } // namespace internal namespace { @@ -4082,12 +4128,10 @@ namespace internal { // and INSTANTIATE_TEST_CASE_P into regular tests and registers those. // This will be done just once during the program runtime. void UnitTestImpl::RegisterParameterizedTests() { -#if GTEST_HAS_PARAM_TEST if (!parameterized_tests_registered_) { parameterized_test_registry_.RegisterTests(); parameterized_tests_registered_ = true; } -#endif } } // namespace internal @@ -4115,18 +4159,18 @@ void TestInfo::Run() { factory_, &internal::TestFactoryBase::CreateTest, "the test fixture's constructor"); - // Runs the test only if the test object was created and its - // constructor didn't generate a fatal failure. - if ((test != NULL) && !Test::HasFatalFailure()) { + // Runs the test if the constructor didn't generate a fatal failure. + // Note that the object will not be null + if (!Test::HasFatalFailure()) { // This doesn't throw as all user code that can throw are wrapped into // exception handling code. test->Run(); } - // Deletes the test object. - impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported( - test, &Test::DeleteSelf_, "the test fixture's destructor"); + // Deletes the test object. + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + test, &Test::DeleteSelf_, "the test fixture's destructor"); result_.set_elapsed_time(internal::GetTimeInMillis() - start); @@ -4352,10 +4396,10 @@ enum GTestColor { }; #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ - !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT + !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW // Returns the character attribute for the given color. -WORD GetColorAttribute(GTestColor color) { +static WORD GetColorAttribute(GTestColor color) { switch (color) { case COLOR_RED: return FOREGROUND_RED; case COLOR_GREEN: return FOREGROUND_GREEN; @@ -4364,6 +4408,37 @@ WORD GetColorAttribute(GTestColor color) { } } +static int GetBitOffset(WORD color_mask) { + if (color_mask == 0) return 0; + + int bitOffset = 0; + while ((color_mask & 1) == 0) { + color_mask >>= 1; + ++bitOffset; + } + return bitOffset; +} + +static WORD GetNewColor(GTestColor color, WORD old_color_attrs) { + // Let's reuse the BG + static const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN | + BACKGROUND_RED | BACKGROUND_INTENSITY; + static const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN | + FOREGROUND_RED | FOREGROUND_INTENSITY; + const WORD existing_bg = old_color_attrs & background_mask; + + WORD new_color = + GetColorAttribute(color) | existing_bg | FOREGROUND_INTENSITY; + static const int bg_bitOffset = GetBitOffset(background_mask); + static const int fg_bitOffset = GetBitOffset(foreground_mask); + + if (((new_color & background_mask) >> bg_bitOffset) == + ((new_color & foreground_mask) >> fg_bitOffset)) { + new_color ^= FOREGROUND_INTENSITY; // invert intensity + } + return new_color; +} + #else // Returns the ANSI color code for the given color. COLOR_DEFAULT is @@ -4384,7 +4459,7 @@ bool ShouldUseColor(bool stdout_is_tty) { const char* const gtest_color = GTEST_FLAG(color).c_str(); if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { -#if GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW // On Windows the TERM variable is usually not set, but the // console there does support colors. return stdout_is_tty; @@ -4441,20 +4516,21 @@ static void ColoredPrintf(GTestColor color, const char* fmt, ...) { } #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ - !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT + !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); // Gets the current text color. CONSOLE_SCREEN_BUFFER_INFO buffer_info; GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); const WORD old_color_attrs = buffer_info.wAttributes; + const WORD new_color = GetNewColor(color, old_color_attrs); // We need to flush the stream buffers into the console before each // SetConsoleTextAttribute call lest it affect the text that is already // printed but has not yet reached the console. fflush(stdout); - SetConsoleTextAttribute(stdout_handle, - GetColorAttribute(color) | FOREGROUND_INTENSITY); + SetConsoleTextAttribute(stdout_handle, new_color); + vprintf(fmt, args); fflush(stdout); @@ -4468,7 +4544,7 @@ static void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_end(args); } -// Text printed in Google Test's text output and --gunit_list_tests +// Text printed in Google Test's text output and --gtest_list_tests // output to label the type parameter and value parameter for a test. static const char kTypeParamLabel[] = "TypeParam"; static const char kValueParamLabel[] = "GetParam()"; @@ -4753,7 +4829,7 @@ void TestEventRepeater::Append(TestEventListener *listener) { listeners_.push_back(listener); } -// TODO(vladl@google.com): Factor the search functionality into Vector::Find. +// FIXME: Factor the search functionality into Vector::Find. TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { for (size_t i = 0; i < listeners_.size(); ++i) { if (listeners_[i] == listener) { @@ -4827,6 +4903,11 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { explicit XmlUnitTestResultPrinter(const char* output_file); virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + void ListTestsMatchingFilter(const std::vector& test_cases); + + // Prints an XML summary of all unit tests. + static void PrintXmlTestsList(std::ostream* stream, + const std::vector& test_cases); private: // Is c a whitespace character that is normalized to a space character @@ -4888,6 +4969,11 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // to delimit this attribute from prior attributes. static std::string TestPropertiesAsXmlAttributes(const TestResult& result); + // Streams an XML representation of the test properties of a TestResult + // object. + static void OutputXmlTestProperties(std::ostream* stream, + const TestResult& result); + // The output file. const std::string output_file_; @@ -4897,46 +4983,30 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // Creates a new XmlUnitTestResultPrinter. XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) : output_file_(output_file) { - if (output_file_.c_str() == NULL || output_file_.empty()) { - fprintf(stderr, "XML output file may not be null\n"); - fflush(stderr); - exit(EXIT_FAILURE); + if (output_file_.empty()) { + GTEST_LOG_(FATAL) << "XML output file may not be null"; } } // Called after the unit test ends. void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, int /*iteration*/) { - FILE* xmlout = NULL; - FilePath output_file(output_file_); - FilePath output_dir(output_file.RemoveFileName()); - - if (output_dir.CreateDirectoriesRecursively()) { - xmlout = posix::FOpen(output_file_.c_str(), "w"); - } - if (xmlout == NULL) { - // TODO(wan): report the reason of the failure. - // - // We don't do it for now as: - // - // 1. There is no urgent need for it. - // 2. It's a bit involved to make the errno variable thread-safe on - // all three operating systems (Linux, Windows, and Mac OS). - // 3. To interpret the meaning of errno in a thread-safe way, - // we need the strerror_r() function, which is not available on - // Windows. - fprintf(stderr, - "Unable to open file \"%s\"\n", - output_file_.c_str()); - fflush(stderr); - exit(EXIT_FAILURE); - } + FILE* xmlout = OpenFileForWriting(output_file_); std::stringstream stream; PrintXmlUnitTest(&stream, unit_test); fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); fclose(xmlout); } +void XmlUnitTestResultPrinter::ListTestsMatchingFilter( + const std::vector& test_cases) { + FILE* xmlout = OpenFileForWriting(output_file_); + std::stringstream stream; + PrintXmlTestsList(&stream, test_cases); + fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); + fclose(xmlout); +} + // Returns an XML-escaped copy of the input string str. If is_attribute // is true, the text is meant to appear as an attribute value, and // normalizable whitespace is preserved by replacing it with character @@ -4947,7 +5017,7 @@ void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, // module will consist of ordinary English text. // If this module is ever modified to produce version 1.1 XML output, // most invalid characters can be retained using character references. -// TODO(wan): It might be nice to have a minimally invasive, human-readable +// FIXME: It might be nice to have a minimally invasive, human-readable // escaping scheme for invalid characters, rather than dropping them. std::string XmlUnitTestResultPrinter::EscapeXml( const std::string& str, bool is_attribute) { @@ -4956,38 +5026,38 @@ std::string XmlUnitTestResultPrinter::EscapeXml( for (size_t i = 0; i < str.size(); ++i) { const char ch = str[i]; switch (ch) { - case '<': - m << "<"; - break; - case '>': - m << ">"; - break; - case '&': - m << "&"; - break; - case '\'': - if (is_attribute) - m << "'"; - else - m << '\''; - break; - case '"': - if (is_attribute) - m << """; - else - m << '"'; - break; - default: + case '<': + m << "<"; + break; + case '>': + m << ">"; + break; + case '&': + m << "&"; + break; + case '\'': + if (is_attribute) + m << "'"; + else + m << '\''; + break; + case '"': + if (is_attribute) + m << """; + else + m << '"'; + break; + default: if (IsValidXmlCharacter(ch)) { if (is_attribute && IsNormalizableWhitespace(ch)) m << "&#x" << String::FormatByte(static_cast(ch)) << ";"; - else + else m << ch; - } - break; - } + } + break; } + } return m.GetString(); } @@ -5008,6 +5078,7 @@ std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( // The following routines generate an XML representation of a UnitTest // object. +// GOOGLETEST_CM0009 DO NOT DELETE // // This is how Google Test concepts map to the DTD: // @@ -5097,13 +5168,17 @@ void XmlUnitTestResultPrinter::OutputXmlAttribute( } // Prints an XML representation of a TestInfo object. -// TODO(wan): There is also value in printing properties with the plain printer. +// FIXME: There is also value in printing properties with the plain printer. void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, const char* test_case_name, const TestInfo& test_info) { const TestResult& result = *test_info.result(); const std::string kTestcase = "testcase"; + if (test_info.is_in_another_shard()) { + return; + } + *stream << " \n"; + return; + } OutputXmlAttribute(stream, kTestcase, "status", test_info.should_run() ? "run" : "notrun"); OutputXmlAttribute(stream, kTestcase, "time", FormatTimeInMillisAsSeconds(result.elapsed_time())); OutputXmlAttribute(stream, kTestcase, "classname", test_case_name); - *stream << TestPropertiesAsXmlAttributes(result); int failures = 0; for (int i = 0; i < result.total_part_count(); ++i) { @@ -5129,22 +5210,28 @@ void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, if (++failures == 1) { *stream << ">\n"; } - const string location = internal::FormatCompilerIndependentFileLocation( - part.file_name(), part.line_number()); - const string summary = location + "\n" + part.summary(); + const std::string location = + internal::FormatCompilerIndependentFileLocation(part.file_name(), + part.line_number()); + const std::string summary = location + "\n" + part.summary(); *stream << " "; - const string detail = location + "\n" + part.message(); + const std::string detail = location + "\n" + part.message(); OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str()); *stream << "\n"; } } - if (failures == 0) + if (failures == 0 && result.test_property_count() == 0) { *stream << " />\n"; - else + } else { + if (failures == 0) { + *stream << ">\n"; + } + OutputXmlTestProperties(stream, result); *stream << " \n"; + } } // Prints an XML representation of a TestCase object @@ -5155,17 +5242,18 @@ void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream, OutputXmlAttribute(stream, kTestsuite, "name", test_case.name()); OutputXmlAttribute(stream, kTestsuite, "tests", StreamableToString(test_case.reportable_test_count())); - OutputXmlAttribute(stream, kTestsuite, "failures", - StreamableToString(test_case.failed_test_count())); - OutputXmlAttribute( - stream, kTestsuite, "disabled", - StreamableToString(test_case.reportable_disabled_test_count())); - OutputXmlAttribute(stream, kTestsuite, "errors", "0"); - OutputXmlAttribute(stream, kTestsuite, "time", - FormatTimeInMillisAsSeconds(test_case.elapsed_time())); - *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result()) - << ">\n"; - + if (!GTEST_FLAG(list_tests)) { + OutputXmlAttribute(stream, kTestsuite, "failures", + StreamableToString(test_case.failed_test_count())); + OutputXmlAttribute( + stream, kTestsuite, "disabled", + StreamableToString(test_case.reportable_disabled_test_count())); + OutputXmlAttribute(stream, kTestsuite, "errors", "0"); + OutputXmlAttribute(stream, kTestsuite, "time", + FormatTimeInMillisAsSeconds(test_case.elapsed_time())); + *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result()); + } + *stream << ">\n"; for (int i = 0; i < test_case.total_test_count(); ++i) { if (test_case.GetTestInfo(i)->is_reportable()) OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); @@ -5199,7 +5287,6 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, OutputXmlAttribute(stream, kTestsuites, "random_seed", StreamableToString(unit_test.random_seed())); } - *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result()); OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); @@ -5212,6 +5299,28 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, *stream << "\n"; } +void XmlUnitTestResultPrinter::PrintXmlTestsList( + std::ostream* stream, const std::vector& test_cases) { + const std::string kTestsuites = "testsuites"; + + *stream << "\n"; + *stream << "<" << kTestsuites; + + int total_tests = 0; + for (size_t i = 0; i < test_cases.size(); ++i) { + total_tests += test_cases[i]->total_test_count(); + } + OutputXmlAttribute(stream, kTestsuites, "tests", + StreamableToString(total_tests)); + OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); + *stream << ">\n"; + + for (size_t i = 0; i < test_cases.size(); ++i) { + PrintXmlTestCase(stream, *test_cases[i]); + } + *stream << "\n"; +} + // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( @@ -5225,119 +5334,536 @@ std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( return attributes.GetString(); } -// End XmlUnitTestResultPrinter +void XmlUnitTestResultPrinter::OutputXmlTestProperties( + std::ostream* stream, const TestResult& result) { + const std::string kProperties = "properties"; + const std::string kProperty = "property"; -#if GTEST_CAN_STREAM_RESULTS_ + if (result.test_property_count() <= 0) { + return; + } -// Checks if str contains '=', '&', '%' or '\n' characters. If yes, -// replaces them by "%xx" where xx is their hexadecimal value. For -// example, replaces "=" with "%3D". This algorithm is O(strlen(str)) -// in both time and space -- important as the input str may contain an -// arbitrarily long test failure message and stack trace. -string StreamingListener::UrlEncode(const char* str) { - string result; - result.reserve(strlen(str) + 1); - for (char ch = *str; ch != '\0'; ch = *++str) { - switch (ch) { - case '%': - case '=': - case '&': - case '\n': - result.append("%" + String::FormatByte(static_cast(ch))); - break; - default: - result.push_back(ch); - break; - } + *stream << "<" << kProperties << ">\n"; + for (int i = 0; i < result.test_property_count(); ++i) { + const TestProperty& property = result.GetTestProperty(i); + *stream << "<" << kProperty; + *stream << " name=\"" << EscapeXmlAttribute(property.key()) << "\""; + *stream << " value=\"" << EscapeXmlAttribute(property.value()) << "\""; + *stream << "/>\n"; } - return result; + *stream << "\n"; } -void StreamingListener::SocketWriter::MakeConnection() { - GTEST_CHECK_(sockfd_ == -1) - << "MakeConnection() can't be called when there is already a connection."; +// End XmlUnitTestResultPrinter - addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. - hints.ai_socktype = SOCK_STREAM; - addrinfo* servinfo = NULL; +// This class generates an JSON output file. +class JsonUnitTestResultPrinter : public EmptyTestEventListener { + public: + explicit JsonUnitTestResultPrinter(const char* output_file); - // Use the getaddrinfo() to get a linked list of IP addresses for - // the given host name. - const int error_num = getaddrinfo( - host_name_.c_str(), port_num_.c_str(), &hints, &servinfo); - if (error_num != 0) { - GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: " - << gai_strerror(error_num); - } + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - // Loop through all the results and connect to the first we can. - for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL; - cur_addr = cur_addr->ai_next) { - sockfd_ = socket( - cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol); - if (sockfd_ != -1) { - // Connect the client socket to the server socket. - if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) { - close(sockfd_); - sockfd_ = -1; - } - } - } + // Prints an JSON summary of all unit tests. + static void PrintJsonTestList(::std::ostream* stream, + const std::vector& test_cases); - freeaddrinfo(servinfo); // all done with this structure + private: + // Returns an JSON-escaped copy of the input string str. + static std::string EscapeJson(const std::string& str); + + //// Verifies that the given attribute belongs to the given element and + //// streams the attribute as JSON. + static void OutputJsonKey(std::ostream* stream, + const std::string& element_name, + const std::string& name, + const std::string& value, + const std::string& indent, + bool comma = true); + static void OutputJsonKey(std::ostream* stream, + const std::string& element_name, + const std::string& name, + int value, + const std::string& indent, + bool comma = true); + + // Streams a JSON representation of a TestInfo object. + static void OutputJsonTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info); + + // Prints a JSON representation of a TestCase object + static void PrintJsonTestCase(::std::ostream* stream, + const TestCase& test_case); + + // Prints a JSON summary of unit_test to output stream out. + static void PrintJsonUnitTest(::std::ostream* stream, + const UnitTest& unit_test); + + // Produces a string representing the test properties in a result as + // a JSON dictionary. + static std::string TestPropertiesAsJson(const TestResult& result, + const std::string& indent); - if (sockfd_ == -1) { - GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to " - << host_name_ << ":" << port_num_; + // The output file. + const std::string output_file_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(JsonUnitTestResultPrinter); +}; + +// Creates a new JsonUnitTestResultPrinter. +JsonUnitTestResultPrinter::JsonUnitTestResultPrinter(const char* output_file) + : output_file_(output_file) { + if (output_file_.empty()) { + GTEST_LOG_(FATAL) << "JSON output file may not be null"; } } -// End of class Streaming Listener -#endif // GTEST_CAN_STREAM_RESULTS__ - -// Class ScopedTrace +void JsonUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + FILE* jsonout = OpenFileForWriting(output_file_); + std::stringstream stream; + PrintJsonUnitTest(&stream, unit_test); + fprintf(jsonout, "%s", StringStreamToString(&stream).c_str()); + fclose(jsonout); +} -// Pushes the given source file location and message onto a per-thread -// trace stack maintained by Google Test. -ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) - GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { - TraceInfo trace; - trace.file = file; - trace.line = line; - trace.message = message.GetString(); +// Returns an JSON-escaped copy of the input string str. +std::string JsonUnitTestResultPrinter::EscapeJson(const std::string& str) { + Message m; - UnitTest::GetInstance()->PushGTestTrace(trace); -} + for (size_t i = 0; i < str.size(); ++i) { + const char ch = str[i]; + switch (ch) { + case '\\': + case '"': + case '/': + m << '\\' << ch; + break; + case '\b': + m << "\\b"; + break; + case '\t': + m << "\\t"; + break; + case '\n': + m << "\\n"; + break; + case '\f': + m << "\\f"; + break; + case '\r': + m << "\\r"; + break; + default: + if (ch < ' ') { + m << "\\u00" << String::FormatByte(static_cast(ch)); + } else { + m << ch; + } + break; + } + } -// Pops the info pushed by the c'tor. -ScopedTrace::~ScopedTrace() - GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { - UnitTest::GetInstance()->PopGTestTrace(); + return m.GetString(); } +// The following routines generate an JSON representation of a UnitTest +// object. -// class OsStackTraceGetter +// Formats the given time in milliseconds as seconds. +static std::string FormatTimeInMillisAsDuration(TimeInMillis ms) { + ::std::stringstream ss; + ss << (static_cast(ms) * 1e-3) << "s"; + return ss.str(); +} -const char* const OsStackTraceGetterInterface::kElidedFramesMarker = - "... " GTEST_NAME_ " internal frames ..."; +// Converts the given epoch time in milliseconds to a date string in the +// RFC3339 format, without the timezone information. +static std::string FormatEpochTimeInMillisAsRFC3339(TimeInMillis ms) { + struct tm time_struct; + if (!PortableLocaltime(static_cast(ms / 1000), &time_struct)) + return ""; + // YYYY-MM-DDThh:mm:ss + return StreamableToString(time_struct.tm_year + 1900) + "-" + + String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" + + String::FormatIntWidth2(time_struct.tm_mday) + "T" + + String::FormatIntWidth2(time_struct.tm_hour) + ":" + + String::FormatIntWidth2(time_struct.tm_min) + ":" + + String::FormatIntWidth2(time_struct.tm_sec) + "Z"; +} -string OsStackTraceGetter::CurrentStackTrace(int /*max_depth*/, - int /*skip_count*/) { - return ""; +static inline std::string Indent(int width) { + return std::string(width, ' '); } -void OsStackTraceGetter::UponLeavingGTest() {} +void JsonUnitTestResultPrinter::OutputJsonKey( + std::ostream* stream, + const std::string& element_name, + const std::string& name, + const std::string& value, + const std::string& indent, + bool comma) { + const std::vector& allowed_names = + GetReservedAttributesForElement(element_name); -// A helper class that creates the premature-exit file in its + GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != + allowed_names.end()) + << "Key \"" << name << "\" is not allowed for value \"" << element_name + << "\"."; + + *stream << indent << "\"" << name << "\": \"" << EscapeJson(value) << "\""; + if (comma) + *stream << ",\n"; +} + +void JsonUnitTestResultPrinter::OutputJsonKey( + std::ostream* stream, + const std::string& element_name, + const std::string& name, + int value, + const std::string& indent, + bool comma) { + const std::vector& allowed_names = + GetReservedAttributesForElement(element_name); + + GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != + allowed_names.end()) + << "Key \"" << name << "\" is not allowed for value \"" << element_name + << "\"."; + + *stream << indent << "\"" << name << "\": " << StreamableToString(value); + if (comma) + *stream << ",\n"; +} + +// Prints a JSON representation of a TestInfo object. +void JsonUnitTestResultPrinter::OutputJsonTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info) { + const TestResult& result = *test_info.result(); + const std::string kTestcase = "testcase"; + const std::string kIndent = Indent(10); + + *stream << Indent(8) << "{\n"; + OutputJsonKey(stream, kTestcase, "name", test_info.name(), kIndent); + + if (test_info.value_param() != NULL) { + OutputJsonKey(stream, kTestcase, "value_param", + test_info.value_param(), kIndent); + } + if (test_info.type_param() != NULL) { + OutputJsonKey(stream, kTestcase, "type_param", test_info.type_param(), + kIndent); + } + if (GTEST_FLAG(list_tests)) { + OutputJsonKey(stream, kTestcase, "file", test_info.file(), kIndent); + OutputJsonKey(stream, kTestcase, "line", test_info.line(), kIndent, false); + *stream << "\n" << Indent(8) << "}"; + return; + } + + OutputJsonKey(stream, kTestcase, "status", + test_info.should_run() ? "RUN" : "NOTRUN", kIndent); + OutputJsonKey(stream, kTestcase, "time", + FormatTimeInMillisAsDuration(result.elapsed_time()), kIndent); + OutputJsonKey(stream, kTestcase, "classname", test_case_name, kIndent, false); + *stream << TestPropertiesAsJson(result, kIndent); + + int failures = 0; + for (int i = 0; i < result.total_part_count(); ++i) { + const TestPartResult& part = result.GetTestPartResult(i); + if (part.failed()) { + *stream << ",\n"; + if (++failures == 1) { + *stream << kIndent << "\"" << "failures" << "\": [\n"; + } + const std::string location = + internal::FormatCompilerIndependentFileLocation(part.file_name(), + part.line_number()); + const std::string message = EscapeJson(location + "\n" + part.message()); + *stream << kIndent << " {\n" + << kIndent << " \"failure\": \"" << message << "\",\n" + << kIndent << " \"type\": \"\"\n" + << kIndent << " }"; + } + } + + if (failures > 0) + *stream << "\n" << kIndent << "]"; + *stream << "\n" << Indent(8) << "}"; +} + +// Prints an JSON representation of a TestCase object +void JsonUnitTestResultPrinter::PrintJsonTestCase(std::ostream* stream, + const TestCase& test_case) { + const std::string kTestsuite = "testsuite"; + const std::string kIndent = Indent(6); + + *stream << Indent(4) << "{\n"; + OutputJsonKey(stream, kTestsuite, "name", test_case.name(), kIndent); + OutputJsonKey(stream, kTestsuite, "tests", test_case.reportable_test_count(), + kIndent); + if (!GTEST_FLAG(list_tests)) { + OutputJsonKey(stream, kTestsuite, "failures", test_case.failed_test_count(), + kIndent); + OutputJsonKey(stream, kTestsuite, "disabled", + test_case.reportable_disabled_test_count(), kIndent); + OutputJsonKey(stream, kTestsuite, "errors", 0, kIndent); + OutputJsonKey(stream, kTestsuite, "time", + FormatTimeInMillisAsDuration(test_case.elapsed_time()), + kIndent, false); + *stream << TestPropertiesAsJson(test_case.ad_hoc_test_result(), kIndent) + << ",\n"; + } + + *stream << kIndent << "\"" << kTestsuite << "\": [\n"; + + bool comma = false; + for (int i = 0; i < test_case.total_test_count(); ++i) { + if (test_case.GetTestInfo(i)->is_reportable()) { + if (comma) { + *stream << ",\n"; + } else { + comma = true; + } + OutputJsonTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); + } + } + *stream << "\n" << kIndent << "]\n" << Indent(4) << "}"; +} + +// Prints a JSON summary of unit_test to output stream out. +void JsonUnitTestResultPrinter::PrintJsonUnitTest(std::ostream* stream, + const UnitTest& unit_test) { + const std::string kTestsuites = "testsuites"; + const std::string kIndent = Indent(2); + *stream << "{\n"; + + OutputJsonKey(stream, kTestsuites, "tests", unit_test.reportable_test_count(), + kIndent); + OutputJsonKey(stream, kTestsuites, "failures", unit_test.failed_test_count(), + kIndent); + OutputJsonKey(stream, kTestsuites, "disabled", + unit_test.reportable_disabled_test_count(), kIndent); + OutputJsonKey(stream, kTestsuites, "errors", 0, kIndent); + if (GTEST_FLAG(shuffle)) { + OutputJsonKey(stream, kTestsuites, "random_seed", unit_test.random_seed(), + kIndent); + } + OutputJsonKey(stream, kTestsuites, "timestamp", + FormatEpochTimeInMillisAsRFC3339(unit_test.start_timestamp()), + kIndent); + OutputJsonKey(stream, kTestsuites, "time", + FormatTimeInMillisAsDuration(unit_test.elapsed_time()), kIndent, + false); + + *stream << TestPropertiesAsJson(unit_test.ad_hoc_test_result(), kIndent) + << ",\n"; + + OutputJsonKey(stream, kTestsuites, "name", "AllTests", kIndent); + *stream << kIndent << "\"" << kTestsuites << "\": [\n"; + + bool comma = false; + for (int i = 0; i < unit_test.total_test_case_count(); ++i) { + if (unit_test.GetTestCase(i)->reportable_test_count() > 0) { + if (comma) { + *stream << ",\n"; + } else { + comma = true; + } + PrintJsonTestCase(stream, *unit_test.GetTestCase(i)); + } + } + + *stream << "\n" << kIndent << "]\n" << "}\n"; +} + +void JsonUnitTestResultPrinter::PrintJsonTestList( + std::ostream* stream, const std::vector& test_cases) { + const std::string kTestsuites = "testsuites"; + const std::string kIndent = Indent(2); + *stream << "{\n"; + int total_tests = 0; + for (size_t i = 0; i < test_cases.size(); ++i) { + total_tests += test_cases[i]->total_test_count(); + } + OutputJsonKey(stream, kTestsuites, "tests", total_tests, kIndent); + + OutputJsonKey(stream, kTestsuites, "name", "AllTests", kIndent); + *stream << kIndent << "\"" << kTestsuites << "\": [\n"; + + for (size_t i = 0; i < test_cases.size(); ++i) { + if (i != 0) { + *stream << ",\n"; + } + PrintJsonTestCase(stream, *test_cases[i]); + } + + *stream << "\n" + << kIndent << "]\n" + << "}\n"; +} +// Produces a string representing the test properties in a result as +// a JSON dictionary. +std::string JsonUnitTestResultPrinter::TestPropertiesAsJson( + const TestResult& result, const std::string& indent) { + Message attributes; + for (int i = 0; i < result.test_property_count(); ++i) { + const TestProperty& property = result.GetTestProperty(i); + attributes << ",\n" << indent << "\"" << property.key() << "\": " + << "\"" << EscapeJson(property.value()) << "\""; + } + return attributes.GetString(); +} + +// End JsonUnitTestResultPrinter + +#if GTEST_CAN_STREAM_RESULTS_ + +// Checks if str contains '=', '&', '%' or '\n' characters. If yes, +// replaces them by "%xx" where xx is their hexadecimal value. For +// example, replaces "=" with "%3D". This algorithm is O(strlen(str)) +// in both time and space -- important as the input str may contain an +// arbitrarily long test failure message and stack trace. +std::string StreamingListener::UrlEncode(const char* str) { + std::string result; + result.reserve(strlen(str) + 1); + for (char ch = *str; ch != '\0'; ch = *++str) { + switch (ch) { + case '%': + case '=': + case '&': + case '\n': + result.append("%" + String::FormatByte(static_cast(ch))); + break; + default: + result.push_back(ch); + break; + } + } + return result; +} + +void StreamingListener::SocketWriter::MakeConnection() { + GTEST_CHECK_(sockfd_ == -1) + << "MakeConnection() can't be called when there is already a connection."; + + addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. + hints.ai_socktype = SOCK_STREAM; + addrinfo* servinfo = NULL; + + // Use the getaddrinfo() to get a linked list of IP addresses for + // the given host name. + const int error_num = getaddrinfo( + host_name_.c_str(), port_num_.c_str(), &hints, &servinfo); + if (error_num != 0) { + GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: " + << gai_strerror(error_num); + } + + // Loop through all the results and connect to the first we can. + for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL; + cur_addr = cur_addr->ai_next) { + sockfd_ = socket( + cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol); + if (sockfd_ != -1) { + // Connect the client socket to the server socket. + if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) { + close(sockfd_); + sockfd_ = -1; + } + } + } + + freeaddrinfo(servinfo); // all done with this structure + + if (sockfd_ == -1) { + GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to " + << host_name_ << ":" << port_num_; + } +} + +// End of class Streaming Listener +#endif // GTEST_CAN_STREAM_RESULTS__ + +// class OsStackTraceGetter + +const char* const OsStackTraceGetterInterface::kElidedFramesMarker = + "... " GTEST_NAME_ " internal frames ..."; + +std::string OsStackTraceGetter::CurrentStackTrace(int max_depth, int skip_count) + GTEST_LOCK_EXCLUDED_(mutex_) { +#if GTEST_HAS_ABSL + std::string result; + + if (max_depth <= 0) { + return result; + } + + max_depth = std::min(max_depth, kMaxStackTraceDepth); + + std::vector raw_stack(max_depth); + // Skips the frames requested by the caller, plus this function. + const int raw_stack_size = + absl::GetStackTrace(&raw_stack[0], max_depth, skip_count + 1); + + void* caller_frame = nullptr; + { + MutexLock lock(&mutex_); + caller_frame = caller_frame_; + } + + for (int i = 0; i < raw_stack_size; ++i) { + if (raw_stack[i] == caller_frame && + !GTEST_FLAG(show_internal_stack_frames)) { + // Add a marker to the trace and stop adding frames. + absl::StrAppend(&result, kElidedFramesMarker, "\n"); + break; + } + + char tmp[1024]; + const char* symbol = "(unknown)"; + if (absl::Symbolize(raw_stack[i], tmp, sizeof(tmp))) { + symbol = tmp; + } + + char line[1024]; + snprintf(line, sizeof(line), " %p: %s\n", raw_stack[i], symbol); + result += line; + } + + return result; + +#else // !GTEST_HAS_ABSL + static_cast(max_depth); + static_cast(skip_count); + return ""; +#endif // GTEST_HAS_ABSL +} + +void OsStackTraceGetter::UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_) { +#if GTEST_HAS_ABSL + void* caller_frame = nullptr; + if (absl::GetStackTrace(&caller_frame, 1, 3) <= 0) { + caller_frame = nullptr; + } + + MutexLock lock(&mutex_); + caller_frame_ = caller_frame; +#endif // GTEST_HAS_ABSL +} + +// A helper class that creates the premature-exit file in its // constructor and deletes the file in its destructor. class ScopedPrematureExitFile { public: explicit ScopedPrematureExitFile(const char* premature_exit_filepath) - : premature_exit_filepath_(premature_exit_filepath) { + : premature_exit_filepath_(premature_exit_filepath ? + premature_exit_filepath : "") { // If a path to the premature-exit file is specified... - if (premature_exit_filepath != NULL && *premature_exit_filepath != '\0') { + if (!premature_exit_filepath_.empty()) { // create the file with a single "0" character in it. I/O // errors are ignored as there's nothing better we can do and we // don't want to fail the test because of this. @@ -5348,13 +5874,18 @@ class ScopedPrematureExitFile { } ~ScopedPrematureExitFile() { - if (premature_exit_filepath_ != NULL && *premature_exit_filepath_ != '\0') { - remove(premature_exit_filepath_); + if (!premature_exit_filepath_.empty()) { + int retval = remove(premature_exit_filepath_.c_str()); + if (retval) { + GTEST_LOG_(ERROR) << "Failed to remove premature exit filepath \"" + << premature_exit_filepath_ << "\" with error " + << retval; + } } } private: - const char* const premature_exit_filepath_; + const std::string premature_exit_filepath_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedPrematureExitFile); }; @@ -5445,7 +5976,7 @@ void TestEventListeners::SuppressEventForwarding() { // We don't protect this under mutex_ as a user is not supposed to // call this before main() starts, from which point on the return // value will never change. -UnitTest * UnitTest::GetInstance() { +UnitTest* UnitTest::GetInstance() { // When compiled with MSVC 7.1 in optimized mode, destroying the // UnitTest object upon exiting the program messes up the exit code, // causing successful tests to appear failed. We have to use a @@ -5624,6 +6155,11 @@ void UnitTest::AddTestPartResult( // when a failure happens and both the --gtest_break_on_failure and // the --gtest_catch_exceptions flags are specified. DebugBreak(); +#elif (!defined(__native_client__)) && \ + ((defined(__clang__) || defined(__GNUC__)) && \ + (defined(__x86_64__) || defined(__i386__))) + // with clang/gcc we can achieve the same effect on x86 by invoking int3 + asm("int3"); #else // Dereference NULL through a volatile pointer to prevent the compiler // from removing. We use this rather than abort() or __builtin_trap() for @@ -5691,7 +6227,7 @@ int UnitTest::Run() { // used for the duration of the program. impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); -#if GTEST_HAS_SEH +#if GTEST_OS_WINDOWS // Either the user wants Google Test to catch exceptions thrown by the // tests or this is executing in the context of death test child // process. In either case the user does not want to see pop-up dialogs @@ -5720,7 +6256,7 @@ int UnitTest::Run() { // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. // Users of prior VC versions shall suffer the agony and pain of // clicking through the countless debug dialogs. - // TODO(vladl@google.com): find a way to suppress the abort dialog() in the + // FIXME: find a way to suppress the abort dialog() in the // debug mode when compiled with VC 7.1 or lower. if (!GTEST_FLAG(break_on_failure)) _set_abort_behavior( @@ -5728,7 +6264,7 @@ int UnitTest::Run() { _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. # endif } -#endif // GTEST_HAS_SEH +#endif // GTEST_OS_WINDOWS return internal::HandleExceptionsInMethodIfSupported( impl(), @@ -5761,7 +6297,6 @@ const TestInfo* UnitTest::current_test_info() const // Returns the random seed used at the start of the current test run. int UnitTest::random_seed() const { return impl_->random_seed(); } -#if GTEST_HAS_PARAM_TEST // Returns ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. internal::ParameterizedTestCaseRegistry& @@ -5769,7 +6304,6 @@ internal::ParameterizedTestCaseRegistry& GTEST_LOCK_EXCLUDED_(mutex_) { return impl_->parameterized_test_registry(); } -#endif // GTEST_HAS_PARAM_TEST // Creates an empty UnitTest. UnitTest::UnitTest() { @@ -5808,10 +6342,8 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) &default_global_test_part_result_reporter_), per_thread_test_part_result_reporter_( &default_per_thread_test_part_result_reporter_), -#if GTEST_HAS_PARAM_TEST parameterized_test_registry_(), parameterized_tests_registered_(false), -#endif // GTEST_HAS_PARAM_TEST last_death_test_case_(-1), current_test_case_(NULL), current_test_info_(NULL), @@ -5878,10 +6410,12 @@ void UnitTestImpl::ConfigureXmlOutput() { if (output_format == "xml") { listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); + } else if (output_format == "json") { + listeners()->SetDefaultXmlGenerator(new JsonUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); } else if (output_format != "") { - printf("WARNING: unrecognized output format \"%s\" ignored.\n", - output_format.c_str()); - fflush(stdout); + GTEST_LOG_(WARNING) << "WARNING: unrecognized output format \"" + << output_format << "\" ignored."; } } @@ -5896,9 +6430,8 @@ void UnitTestImpl::ConfigureStreamingOutput() { listeners()->Append(new StreamingListener(target.substr(0, pos), target.substr(pos+1))); } else { - printf("WARNING: unrecognized streaming target \"%s\" ignored.\n", - target.c_str()); - fflush(stdout); + GTEST_LOG_(WARNING) << "unrecognized streaming target \"" << target + << "\" ignored."; } } } @@ -5937,6 +6470,13 @@ void UnitTestImpl::PostFlagParsingInit() { // Configures listeners for streaming test results to the specified server. ConfigureStreamingOutput(); #endif // GTEST_CAN_STREAM_RESULTS_ + +#if GTEST_HAS_ABSL + if (GTEST_FLAG(install_failure_signal_handler)) { + absl::FailureSignalHandlerOptions options; + absl::InstallFailureSignalHandler(options); + } +#endif // GTEST_HAS_ABSL } } @@ -5980,11 +6520,11 @@ TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) { // Can we find a TestCase with the given name? - const std::vector::const_iterator test_case = - std::find_if(test_cases_.begin(), test_cases_.end(), + const std::vector::const_reverse_iterator test_case = + std::find_if(test_cases_.rbegin(), test_cases_.rend(), TestCaseNameIs(test_case_name)); - if (test_case != test_cases_.end()) + if (test_case != test_cases_.rend()) return *test_case; // No. Let's create one. @@ -6025,13 +6565,8 @@ static void TearDownEnvironment(Environment* env) { env->TearDown(); } // All other functions called from RunAllTests() may safely assume that // parameterized tests are ready to be counted and run. bool UnitTestImpl::RunAllTests() { - // Makes sure InitGoogleTest() was called. - if (!GTestIsInitialized()) { - printf("%s", - "\nThis test program did NOT call ::testing::InitGoogleTest " - "before calling RUN_ALL_TESTS(). Please fix it.\n"); - return false; - } + // True iff Google Test is initialized before RUN_ALL_TESTS() is called. + const bool gtest_is_initialized_before_run_all_tests = GTestIsInitialized(); // Do not run any test if the --help flag was specified. if (g_help_flag) @@ -6159,6 +6694,20 @@ bool UnitTestImpl::RunAllTests() { repeater->OnTestProgramEnd(*parent_); + if (!gtest_is_initialized_before_run_all_tests) { + ColoredPrintf( + COLOR_RED, + "\nIMPORTANT NOTICE - DO NOT IGNORE:\n" + "This test program did NOT call " GTEST_INIT_GOOGLE_TEST_NAME_ + "() before calling RUN_ALL_TESTS(). This is INVALID. Soon " GTEST_NAME_ + " will start to enforce the valid usage. " + "Please fix it ASAP, or IT WILL START TO FAIL.\n"); // NOLINT +#if GTEST_FOR_GOOGLE_ + ColoredPrintf(COLOR_RED, + "For more details, see http://wiki/Main/ValidGUnitMain.\n"); +#endif // GTEST_FOR_GOOGLE_ + } + return !failed; } @@ -6260,8 +6809,8 @@ bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { // each TestCase and TestInfo object. // If shard_tests == true, further filters tests based on sharding // variables in the environment - see -// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. -// Returns the number of tests that should run. +// https://github.com/google/googletest/blob/master/googletest/docs/advanced.md +// . Returns the number of tests that should run. int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? Int32FromEnvOrDie(kTestTotalShards, -1) : -1; @@ -6306,10 +6855,11 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && matches_filter; - const bool is_selected = is_runnable && - (shard_tests == IGNORE_SHARDING_PROTOCOL || - ShouldRunTestOnShard(total_shards, shard_index, - num_runnable_tests)); + const bool is_in_another_shard = + shard_tests != IGNORE_SHARDING_PROTOCOL && + !ShouldRunTestOnShard(total_shards, shard_index, num_runnable_tests); + test_info->is_in_another_shard_ = is_in_another_shard; + const bool is_selected = is_runnable && !is_in_another_shard; num_runnable_tests += is_runnable; num_selected_tests += is_selected; @@ -6364,7 +6914,7 @@ void UnitTestImpl::ListTestsMatchingFilter() { // We print the type parameter on a single line to make // the output easy to parse by a program. PrintOnOneLine(test_case->type_param(), kMaxParamLength); - } + } printf("\n"); } printf(" %s", test_info->name()); @@ -6379,6 +6929,23 @@ void UnitTestImpl::ListTestsMatchingFilter() { } } fflush(stdout); + const std::string& output_format = UnitTestOptions::GetOutputFormat(); + if (output_format == "xml" || output_format == "json") { + FILE* fileout = OpenFileForWriting( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()); + std::stringstream stream; + if (output_format == "xml") { + XmlUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()) + .PrintXmlTestsList(&stream, test_cases_); + } else if (output_format == "json") { + JsonUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()) + .PrintJsonTestList(&stream, test_cases_); + } + fprintf(fileout, "%s", StringStreamToString(&stream).c_str()); + fclose(fileout); + } } // Sets the OS stack trace getter. @@ -6409,11 +6976,15 @@ OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { return os_stack_trace_getter_; } -// Returns the TestResult for the test that's currently running, or -// the TestResult for the ad hoc test if no test is running. +// Returns the most specific TestResult currently running. TestResult* UnitTestImpl::current_test_result() { - return current_test_info_ ? - &(current_test_info_->result_) : &ad_hoc_test_result_; + if (current_test_info_ != NULL) { + return ¤t_test_info_->result_; + } + if (current_test_case_ != NULL) { + return ¤t_test_case_->ad_hoc_test_result_; + } + return &ad_hoc_test_result_; } // Shuffles all test cases, and the tests within each test case, @@ -6494,9 +7065,8 @@ bool SkipPrefix(const char* prefix, const char** pstr) { // part can be omitted. // // Returns the value of the flag, or NULL if the parsing failed. -static const char* ParseFlagValue(const char* str, - const char* flag, - bool def_optional) { +static const char* ParseFlagValue(const char* str, const char* flag, + bool def_optional) { // str and flag must not be NULL. if (str == NULL || flag == NULL) return NULL; @@ -6566,7 +7136,8 @@ bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. -static bool ParseStringFlag(const char* str, const char* flag, std::string* value) { +template +static bool ParseStringFlag(const char* str, const char* flag, String* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); @@ -6602,7 +7173,7 @@ static bool HasGoogleTestFlagPrefix(const char* str) { // @Y changes the color to yellow. // @D changes to the default terminal text color. // -// TODO(wan@google.com): Write tests for this once we add stdout +// FIXME: Write tests for this once we add stdout // capturing to Google Test. static void PrintColorEncoded(const char* str) { GTestColor color = COLOR_DEFAULT; // The current color. @@ -6674,24 +7245,25 @@ static const char kColorEncodedHelpMessage[] = " Enable/disable colored output. The default is @Gauto@D.\n" " -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" " Don't print the elapsed time of each test.\n" -" @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" +" @G--" GTEST_FLAG_PREFIX_ "output=@Y(@Gjson@Y|@Gxml@Y)[@G:@YDIRECTORY_PATH@G" GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" -" Generate an XML report in the given directory or with the given file\n" -" name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" -#if GTEST_CAN_STREAM_RESULTS_ +" Generate a JSON or XML report in the given directory or with the given\n" +" file name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" +# if GTEST_CAN_STREAM_RESULTS_ " @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" " Stream test results to the given server.\n" -#endif // GTEST_CAN_STREAM_RESULTS_ +# endif // GTEST_CAN_STREAM_RESULTS_ "\n" "Assertion Behavior:\n" -#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +# if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" " Set the default death test style.\n" -#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +# endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" " Turn assertion failures into debugger break-points.\n" " @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" -" Turn assertion failures into C++ exceptions.\n" +" Turn assertion failures into C++ exceptions for use by an external\n" +" test framework.\n" " @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" " Do not report exceptions as test failures. Instead, allow them\n" " to crash the program or throw a pop-up (on Windows).\n" @@ -6727,6 +7299,7 @@ static bool ParseGoogleTestFlag(const char* const arg) { ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || + ParseBoolFlag(arg, kPrintUTF8Flag, >EST_FLAG(print_utf8)) || ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || @@ -6742,11 +7315,8 @@ static bool ParseGoogleTestFlag(const char* const arg) { static void LoadFlagsFromFile(const std::string& path) { FILE* flagfile = posix::FOpen(path.c_str(), "r"); if (!flagfile) { - fprintf(stderr, - "Unable to open file \"%s\"\n", - GTEST_FLAG(flagfile).c_str()); - fflush(stderr); - exit(EXIT_FAILURE); + GTEST_LOG_(FATAL) << "Unable to open file \"" << GTEST_FLAG(flagfile) + << "\""; } std::string contents(ReadEntireFile(flagfile)); posix::FClose(flagfile); @@ -6820,6 +7390,17 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { // other parts of Google Test. void ParseGoogleTestFlagsOnly(int* argc, char** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); + + // Fix the value of *_NSGetArgc() on macOS, but iff + // *_NSGetArgv() == argv + // Only applicable to char** version of argv +#if GTEST_OS_MAC +#ifndef GTEST_OS_IOS + if (*_NSGetArgv() == argv) { + *_NSGetArgc() = *argc; + } +#endif +#endif } void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); @@ -6841,6 +7422,10 @@ void InitGoogleTestImpl(int* argc, CharType** argv) { g_argvs.push_back(StreamableToString(argv[i])); } +#if GTEST_HAS_ABSL + absl::InitializeSymbolizer(g_argvs[0].c_str()); +#endif // GTEST_HAS_ABSL + ParseGoogleTestFlagsOnly(argc, argv); GetUnitTestImpl()->PostFlagParsingInit(); } @@ -6874,6 +7459,47 @@ void InitGoogleTest(int* argc, wchar_t** argv) { #endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) } +std::string TempDir() { +#if defined(GTEST_CUSTOM_TEMPDIR_FUNCTION_) + return GTEST_CUSTOM_TEMPDIR_FUNCTION_(); +#endif + +#if GTEST_OS_WINDOWS_MOBILE + return "\\temp\\"; +#elif GTEST_OS_WINDOWS + const char* temp_dir = internal::posix::GetEnv("TEMP"); + if (temp_dir == NULL || temp_dir[0] == '\0') + return "\\temp\\"; + else if (temp_dir[strlen(temp_dir) - 1] == '\\') + return temp_dir; + else + return std::string(temp_dir) + "\\"; +#elif GTEST_OS_LINUX_ANDROID + return "/sdcard/"; +#else + return "/tmp/"; +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Class ScopedTrace + +// Pushes the given source file location and message onto a per-thread +// trace stack maintained by Google Test. +void ScopedTrace::PushTrace(const char* file, int line, std::string message) { + internal::TraceInfo trace; + trace.file = file; + trace.line = line; + trace.message.swap(message); + + UnitTest::GetInstance()->PushGTestTrace(trace); +} + +// Pops the info pushed by the c'tor. +ScopedTrace::~ScopedTrace() + GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { + UnitTest::GetInstance()->PopGTestTrace(); +} + } // namespace testing // Copyright 2005, Google Inc. // All rights reserved. @@ -6903,8 +7529,7 @@ void InitGoogleTest(int* argc, wchar_t** argv) { // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) + // // This file implements death tests. @@ -6936,23 +7561,27 @@ void InitGoogleTest(int* argc, wchar_t** argv) { # include # endif // GTEST_OS_QNX -#endif // GTEST_HAS_DEATH_TEST +# if GTEST_OS_FUCHSIA +# include +# include +# include +# include +# include +# endif // GTEST_OS_FUCHSIA +#endif // GTEST_HAS_DEATH_TEST -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick exists to -// prevent the accidental inclusion of gtest-internal-inl.h in the -// user's code. -#define GTEST_IMPLEMENTATION_ 1 -#undef GTEST_IMPLEMENTATION_ namespace testing { // Constants. // The default death test style. -static const char kDefaultDeathTestStyle[] = "fast"; +// +// This is defined in internal/gtest-port.h as "fast", but can be overridden by +// a definition in internal/custom/gtest-port.h. The recommended value, which is +// used internally at Google, is "threadsafe". +static const char kDefaultDeathTestStyle[] = GTEST_DEFAULT_DEATH_TEST_STYLE; GTEST_DEFINE_string_( death_test_style, @@ -6992,7 +7621,7 @@ namespace internal { // Valid only for fast death tests. Indicates the code is running in the // child process of a fast style death test. -# if !GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA static bool g_in_fast_death_test_child = false; # endif @@ -7002,10 +7631,10 @@ static bool g_in_fast_death_test_child = false; // tests. IMPORTANT: This is an internal utility. Using it may break the // implementation of death tests. User code MUST NOT use it. bool InDeathTestChild() { -# if GTEST_OS_WINDOWS +# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA - // On Windows, death tests are thread-safe regardless of the value of the - // death_test_style flag. + // On Windows and Fuchsia, death tests are thread-safe regardless of the value + // of the death_test_style flag. return !GTEST_FLAG(internal_run_death_test).empty(); # else @@ -7025,7 +7654,7 @@ ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { // ExitedWithCode function-call operator. bool ExitedWithCode::operator()(int exit_status) const { -# if GTEST_OS_WINDOWS +# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA return exit_status == exit_code_; @@ -7033,10 +7662,10 @@ bool ExitedWithCode::operator()(int exit_status) const { return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; -# endif // GTEST_OS_WINDOWS +# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA } -# if !GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // KilledBySignal constructor. KilledBySignal::KilledBySignal(int signum) : signum_(signum) { } @@ -7053,7 +7682,7 @@ bool KilledBySignal::operator()(int exit_status) const { # endif // defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; } -# endif // !GTEST_OS_WINDOWS +# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA namespace internal { @@ -7064,7 +7693,7 @@ namespace internal { static std::string ExitSummary(int exit_code) { Message m; -# if GTEST_OS_WINDOWS +# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA m << "Exited with exit status " << exit_code; @@ -7080,7 +7709,7 @@ static std::string ExitSummary(int exit_code) { m << " (core dumped)"; } # endif -# endif // GTEST_OS_WINDOWS +# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA return m.GetString(); } @@ -7091,7 +7720,7 @@ bool ExitedUnsuccessfully(int exit_status) { return !ExitedWithCode(0)(exit_status); } -# if !GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // Generates a textual failure message when a death test finds more than // one thread running, or cannot determine the number of threads, prior // to executing the given statement. It is the responsibility of the @@ -7100,13 +7729,19 @@ static std::string DeathTestThreadWarning(size_t thread_count) { Message msg; msg << "Death tests use fork(), which is unsafe particularly" << " in a threaded context. For this test, " << GTEST_NAME_ << " "; - if (thread_count == 0) + if (thread_count == 0) { msg << "couldn't detect the number of threads."; - else + } else { msg << "detected " << thread_count << " threads."; + } + msg << " See " + "https://github.com/google/googletest/blob/master/googletest/docs/" + "advanced.md#death-tests-and-threads" + << " for more explanation and suggested solutions, especially if" + << " this is the last message you see before your test times out."; return msg.GetString(); } -# endif // !GTEST_OS_WINDOWS +# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // Flag characters for reporting a death test that did not die. static const char kDeathTestLived = 'L'; @@ -7114,6 +7749,13 @@ static const char kDeathTestReturned = 'R'; static const char kDeathTestThrew = 'T'; static const char kDeathTestInternalError = 'I'; +#if GTEST_OS_FUCHSIA + +// File descriptor used for the pipe in the child process. +static const int kFuchsiaReadPipeFd = 3; + +#endif + // An enumeration describing all of the possible ways that a death test can // conclude. DIED means that the process died while executing the test // code; LIVED means that process lived beyond the end of the test code; @@ -7121,7 +7763,7 @@ static const char kDeathTestInternalError = 'I'; // statement, which is not allowed; THREW means that the test statement // returned control by throwing an exception. IN_PROGRESS means the test // has not yet concluded. -// TODO(vladl@google.com): Unify names and possibly values for +// FIXME: Unify names and possibly values for // AbortReason, DeathTestOutcome, and flag characters above. enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; @@ -7434,7 +8076,12 @@ bool DeathTestImpl::Passed(bool status_ok) { break; case DIED: if (status_ok) { +# if GTEST_USES_PCRE + // PCRE regexes support embedded NULs. + const bool matched = RE::PartialMatch(error_message, *regex()); +# else const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); +# endif // GTEST_USES_PCRE if (matched) { success = true; } else { @@ -7650,7 +8297,200 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { set_spawned(true); return OVERSEE_TEST; } -# else // We are not on Windows. + +# elif GTEST_OS_FUCHSIA + +class FuchsiaDeathTest : public DeathTestImpl { + public: + FuchsiaDeathTest(const char* a_statement, + const RE* a_regex, + const char* file, + int line) + : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} + virtual ~FuchsiaDeathTest() { + zx_status_t status = zx_handle_close(child_process_); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + status = zx_handle_close(port_); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + } + + // All of these virtual functions are inherited from DeathTest. + virtual int Wait(); + virtual TestRole AssumeRole(); + + private: + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; + + zx_handle_t child_process_ = ZX_HANDLE_INVALID; + zx_handle_t port_ = ZX_HANDLE_INVALID; +}; + +// Utility class for accumulating command-line arguments. +class Arguments { + public: + Arguments() { + args_.push_back(NULL); + } + + ~Arguments() { + for (std::vector::iterator i = args_.begin(); i != args_.end(); + ++i) { + free(*i); + } + } + void AddArgument(const char* argument) { + args_.insert(args_.end() - 1, posix::StrDup(argument)); + } + + template + void AddArguments(const ::std::vector& arguments) { + for (typename ::std::vector::const_iterator i = arguments.begin(); + i != arguments.end(); + ++i) { + args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); + } + } + char* const* Argv() { + return &args_[0]; + } + + int size() { + return args_.size() - 1; + } + + private: + std::vector args_; +}; + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int FuchsiaDeathTest::Wait() { + if (!spawned()) + return 0; + + // Register to wait for the child process to terminate. + zx_status_t status_zx; + status_zx = zx_object_wait_async(child_process_, + port_, + 0 /* key */, + ZX_PROCESS_TERMINATED, + ZX_WAIT_ASYNC_ONCE); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + // Wait for it to terminate, or an exception to be received. + zx_port_packet_t packet; + status_zx = zx_port_wait(port_, ZX_TIME_INFINITE, &packet); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + if (ZX_PKT_IS_EXCEPTION(packet.type)) { + // Process encountered an exception. Kill it directly rather than letting + // other handlers process the event. + status_zx = zx_task_kill(child_process_); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + // Now wait for |child_process_| to terminate. + zx_signals_t signals = 0; + status_zx = zx_object_wait_one( + child_process_, ZX_PROCESS_TERMINATED, ZX_TIME_INFINITE, &signals); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + GTEST_DEATH_TEST_CHECK_(signals & ZX_PROCESS_TERMINATED); + } else { + // Process terminated. + GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type)); + GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_PROCESS_TERMINATED); + } + + ReadAndInterpretStatusByte(); + + zx_info_process_t buffer; + status_zx = zx_object_get_info( + child_process_, + ZX_INFO_PROCESS, + &buffer, + sizeof(buffer), + nullptr, + nullptr); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + GTEST_DEATH_TEST_CHECK_(buffer.exited); + set_status(buffer.return_code); + return status(); +} + +// The AssumeRole process for a Fuchsia death test. It creates a child +// process with the same executable as the current process to run the +// death test. The child process is given the --gtest_filter and +// --gtest_internal_run_death_test flags such that it knows to run the +// current death test only. +DeathTest::TestRole FuchsiaDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != NULL) { + // ParseInternalRunDeathTestFlag() has performed all the necessary + // processing. + set_write_fd(kFuchsiaReadPipeFd); + return EXECUTE_TEST; + } + + CaptureStderr(); + // Flush the log buffers since the log streams are shared with the child. + FlushInfoLog(); + + // Build the child process command line. + const std::string filter_flag = + std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + + info->test_case_name() + "." + info->name(); + const std::string internal_flag = + std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + + file_ + "|" + + StreamableToString(line_) + "|" + + StreamableToString(death_test_index); + Arguments args; + args.AddArguments(GetInjectableArgvs()); + args.AddArgument(filter_flag.c_str()); + args.AddArgument(internal_flag.c_str()); + + // Build the pipe for communication with the child. + zx_status_t status; + zx_handle_t child_pipe_handle; + uint32_t type; + status = fdio_pipe_half(&child_pipe_handle, &type); + GTEST_DEATH_TEST_CHECK_(status >= 0); + set_read_fd(status); + + // Set the pipe handle for the child. + fdio_spawn_action_t add_handle_action = {}; + add_handle_action.action = FDIO_SPAWN_ACTION_ADD_HANDLE; + add_handle_action.h.id = PA_HND(type, kFuchsiaReadPipeFd); + add_handle_action.h.handle = child_pipe_handle; + + // Spawn the child process. + status = fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, + args.Argv()[0], args.Argv(), nullptr, 1, + &add_handle_action, &child_process_, nullptr); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + + // Create an exception port and attach it to the |child_process_|, to allow + // us to suppress the system default exception handler from firing. + status = zx_port_create(0, &port_); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + status = zx_task_bind_exception_port( + child_process_, port_, 0 /* key */, 0 /*options */); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + + set_spawned(true); + return OVERSEE_TEST; +} + +#else // We are neither on Windows, nor on Fuchsia. // ForkingDeathTest provides implementations for most of the abstract // methods of the DeathTest interface. Only the AssumeRole method is @@ -7754,11 +8594,10 @@ class ExecDeathTest : public ForkingDeathTest { ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } virtual TestRole AssumeRole(); private: - static ::std::vector - GetArgvsForDeathTestChildProcess() { - ::std::vector args = GetInjectableArgvs(); + static ::std::vector GetArgvsForDeathTestChildProcess() { + ::std::vector args = GetInjectableArgvs(); # if defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) - ::std::vector extra_args = + ::std::vector extra_args = GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_(); args.insert(args.end(), extra_args.begin(), extra_args.end()); # endif // defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) @@ -7857,6 +8696,7 @@ static int ExecDeathTestChildMain(void* child_arg) { } # endif // !GTEST_OS_QNX +# if GTEST_HAS_CLONE // Two utility routines that together determine the direction the stack // grows. // This could be accomplished more elegantly by a single recursive @@ -7866,13 +8706,14 @@ static int ExecDeathTestChildMain(void* child_arg) { // GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining // StackLowerThanAddress into StackGrowsDown, which then doesn't give // correct answer. -void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_; -void StackLowerThanAddress(const void* ptr, bool* result) { +static void StackLowerThanAddress(const void* ptr, + bool* result) GTEST_NO_INLINE_; +static void StackLowerThanAddress(const void* ptr, bool* result) { int dummy; *result = (&dummy < ptr); } -#if GTEST_HAS_CLONE +// Make sure AddressSanitizer does not tamper with the stack here. GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ static bool StackGrowsDown() { int dummy; @@ -7880,7 +8721,7 @@ static bool StackGrowsDown() { StackLowerThanAddress(&dummy, &result); return result; } -#endif +# endif // GTEST_HAS_CLONE // Spawns a child process with the same executable as the current process in // a thread-safe manner and instructs it to run the death test. The @@ -8066,11 +8907,19 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, } # if GTEST_OS_WINDOWS + if (GTEST_FLAG(death_test_style) == "threadsafe" || GTEST_FLAG(death_test_style) == "fast") { *test = new WindowsDeathTest(statement, regex, file, line); } +# elif GTEST_OS_FUCHSIA + + if (GTEST_FLAG(death_test_style) == "threadsafe" || + GTEST_FLAG(death_test_style) == "fast") { + *test = new FuchsiaDeathTest(statement, regex, file, line); + } + # else if (GTEST_FLAG(death_test_style) == "threadsafe") { @@ -8095,7 +8944,7 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, // Recreates the pipe and event handles from the provided parameters, // signals the event, and returns a file descriptor wrapped around the pipe // handle. This function is called in the child process only. -int GetStatusFileDescriptor(unsigned int parent_process_id, +static int GetStatusFileDescriptor(unsigned int parent_process_id, size_t write_handle_as_size_t, size_t event_handle_as_size_t) { AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, @@ -8106,7 +8955,7 @@ int GetStatusFileDescriptor(unsigned int parent_process_id, StreamableToString(parent_process_id)); } - // TODO(vladl@google.com): Replace the following check with a + // FIXME: Replace the following check with a // compile-time assertion when available. GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); @@ -8114,7 +8963,7 @@ int GetStatusFileDescriptor(unsigned int parent_process_id, reinterpret_cast(write_handle_as_size_t); HANDLE dup_write_handle; - // The newly initialized handle is accessible only in in the parent + // The newly initialized handle is accessible only in the parent // process. To obtain one accessible within the child, we need to use // DuplicateHandle. if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, @@ -8174,6 +9023,7 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { int write_fd = -1; # if GTEST_OS_WINDOWS + unsigned int parent_process_id = 0; size_t write_handle_as_size_t = 0; size_t event_handle_as_size_t = 0; @@ -8190,6 +9040,16 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { write_fd = GetStatusFileDescriptor(parent_process_id, write_handle_as_size_t, event_handle_as_size_t); + +# elif GTEST_OS_FUCHSIA + + if (fields.size() != 3 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index)) { + DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + + GTEST_FLAG(internal_run_death_test)); + } + # else if (fields.size() != 4 @@ -8238,8 +9098,6 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Authors: keith.ray@gmail.com (Keith Ray) #include @@ -8257,6 +9115,7 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { # include // Some Linux distributions define PATH_MAX here. #endif // GTEST_OS_WINDOWS_MOBILE + #if GTEST_OS_WINDOWS # define GTEST_PATH_MAX_ _MAX_PATH #elif defined(PATH_MAX) @@ -8267,7 +9126,6 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { # define GTEST_PATH_MAX_ _POSIX_PATH_MAX #endif // GTEST_OS_WINDOWS - namespace testing { namespace internal { @@ -8462,7 +9320,7 @@ bool FilePath::DirectoryExists() const { // root directory per disk drive.) bool FilePath::IsRootDirectory() const { #if GTEST_OS_WINDOWS - // TODO(wan@google.com): on Windows a network share like + // FIXME: on Windows a network share like // \\server\share can be a root directory, although it cannot be the // current directory. Handle this properly. return pathname_.length() == 3 && IsAbsolutePath(); @@ -8562,7 +9420,7 @@ FilePath FilePath::RemoveTrailingPathSeparator() const { // Removes any redundant separators that might be in the pathname. // For example, "bar///foo" becomes "bar/foo". Does not eliminate other // redundancies that might be in a pathname involving "." or "..". -// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share). +// FIXME: handle Windows network shares (e.g. \\server\share). void FilePath::Normalize() { if (pathname_.c_str() == NULL) { pathname_ = ""; @@ -8623,8 +9481,7 @@ void FilePath::Normalize() { // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan) + #include @@ -8659,14 +9516,11 @@ void FilePath::Normalize() { # include #endif // GTEST_OS_AIX +#if GTEST_OS_FUCHSIA +# include +# include +#endif // GTEST_OS_FUCHSIA -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick exists to -// prevent the accidental inclusion of gtest-internal-inl.h in the -// user's code. -#define GTEST_IMPLEMENTATION_ 1 -#undef GTEST_IMPLEMENTATION_ namespace testing { namespace internal { @@ -8684,7 +9538,7 @@ const int kStdErrFileno = STDERR_FILENO; namespace { template -T ReadProcFileField(const string& filename, int field) { +T ReadProcFileField(const std::string& filename, int field) { std::string dummy; std::ifstream file(filename.c_str()); while (field-- > 0) { @@ -8698,7 +9552,7 @@ T ReadProcFileField(const string& filename, int field) { // Returns the number of active threads, or 0 when there is an error. size_t GetThreadCount() { - const string filename = + const std::string filename = (Message() << "/proc/" << getpid() << "/stat").GetString(); return ReadProcFileField(filename, 19); } @@ -8755,6 +9609,25 @@ size_t GetThreadCount() { } } +#elif GTEST_OS_FUCHSIA + +size_t GetThreadCount() { + int dummy_buffer; + size_t avail; + zx_status_t status = zx_object_get_info( + zx_process_self(), + ZX_INFO_PROCESS_THREADS, + &dummy_buffer, + 0, + nullptr, + &avail); + if (status == ZX_OK) { + return avail; + } else { + return 0; + } +} + #else size_t GetThreadCount() { @@ -8837,9 +9710,9 @@ Mutex::Mutex() Mutex::~Mutex() { // Static mutexes are leaked intentionally. It is not thread-safe to try // to clean them up. - // TODO(yukawa): Switch to Slim Reader/Writer (SRW) Locks, which requires + // FIXME: Switch to Slim Reader/Writer (SRW) Locks, which requires // nothing to clean it up but is available only on Vista and later. - // http://msdn.microsoft.com/en-us/library/windows/desktop/aa904937.aspx + // https://docs.microsoft.com/en-us/windows/desktop/Sync/slim-reader-writer--srw--locks if (type_ == kDynamic) { ::DeleteCriticalSection(critical_section_); delete critical_section_; @@ -8870,6 +9743,43 @@ void Mutex::AssertHeld() { << "The current thread is not holding the mutex @" << this; } +namespace { + +// Use the RAII idiom to flag mem allocs that are intentionally never +// deallocated. The motivation is to silence the false positive mem leaks +// that are reported by the debug version of MS's CRT which can only detect +// if an alloc is missing a matching deallocation. +// Example: +// MemoryIsNotDeallocated memory_is_not_deallocated; +// critical_section_ = new CRITICAL_SECTION; +// +class MemoryIsNotDeallocated +{ + public: + MemoryIsNotDeallocated() : old_crtdbg_flag_(0) { +#ifdef _MSC_VER + old_crtdbg_flag_ = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + // Set heap allocation block type to _IGNORE_BLOCK so that MS debug CRT + // doesn't report mem leak if there's no matching deallocation. + _CrtSetDbgFlag(old_crtdbg_flag_ & ~_CRTDBG_ALLOC_MEM_DF); +#endif // _MSC_VER + } + + ~MemoryIsNotDeallocated() { +#ifdef _MSC_VER + // Restore the original _CRTDBG_ALLOC_MEM_DF flag + _CrtSetDbgFlag(old_crtdbg_flag_); +#endif // _MSC_VER + } + + private: + int old_crtdbg_flag_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MemoryIsNotDeallocated); +}; + +} // namespace + // Initializes owner_thread_id_ and critical_section_ in static mutexes. void Mutex::ThreadSafeLazyInit() { // Dynamic mutexes are initialized in the constructor. @@ -8880,7 +9790,11 @@ void Mutex::ThreadSafeLazyInit() { // If critical_section_init_phase_ was 0 before the exchange, we // are the first to test it and need to perform the initialization. owner_thread_id_ = 0; - critical_section_ = new CRITICAL_SECTION; + { + // Use RAII to flag that following mem alloc is never deallocated. + MemoryIsNotDeallocated memory_is_not_deallocated; + critical_section_ = new CRITICAL_SECTION; + } ::InitializeCriticalSection(critical_section_); // Updates the critical_section_init_phase_ to 2 to signal // initialization complete. @@ -8919,7 +9833,7 @@ class ThreadWithParamSupport : public ThreadWithParamBase { Notification* thread_can_start) { ThreadMainParam* param = new ThreadMainParam(runnable, thread_can_start); DWORD thread_id; - // TODO(yukawa): Consider to use _beginthreadex instead. + // FIXME: Consider to use _beginthreadex instead. HANDLE thread_handle = ::CreateThread( NULL, // Default security. 0, // Default stack size. @@ -9087,7 +10001,7 @@ class ThreadLocalRegistryImpl { FALSE, thread_id); GTEST_CHECK_(thread != NULL); - // We need to to pass a valid thread ID pointer into CreateThread for it + // We need to pass a valid thread ID pointer into CreateThread for it // to work correctly under Win98. DWORD watcher_thread_id; HANDLE watcher_thread = ::CreateThread( @@ -9122,7 +10036,8 @@ class ThreadLocalRegistryImpl { // Returns map of thread local instances. static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() { mutex_.AssertHeld(); - static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals; + MemoryIsNotDeallocated memory_is_not_deallocated; + static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals(); return map; } @@ -9262,7 +10177,7 @@ bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { } // Helper function used by ValidateRegex() to format error messages. -std::string FormatRegexSyntaxError(const char* regex, int index) { +static std::string FormatRegexSyntaxError(const char* regex, int index) { return (Message() << "Syntax error at index " << index << " in simple regular expression \"" << regex << "\": ").GetString(); } @@ -9271,7 +10186,7 @@ std::string FormatRegexSyntaxError(const char* regex, int index) { // otherwise returns true. bool ValidateRegex(const char* regex) { if (regex == NULL) { - // TODO(wan@google.com): fix the source file location in the + // FIXME: fix the source file location in the // assertion failures to match where the regex is used in user // code. ADD_FAILURE() << "NULL is not a valid simple regular expression."; @@ -9514,9 +10429,10 @@ GTestLog::~GTestLog() { posix::Abort(); } } + // Disable Microsoft deprecation warnings for POSIX functions called from // this class (creat, dup, dup2, and close) -GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) +GTEST_DISABLE_MSC_DEPRECATED_PUSH_() #if GTEST_HAS_STREAM_REDIRECTION @@ -9600,13 +10516,14 @@ class CapturedStream { GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); }; -GTEST_DISABLE_MSC_WARNINGS_POP_() +GTEST_DISABLE_MSC_DEPRECATED_POP_() static CapturedStream* g_captured_stderr = NULL; static CapturedStream* g_captured_stdout = NULL; // Starts capturing an output stream (stdout/stderr). -static void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { +static void CaptureStream(int fd, const char* stream_name, + CapturedStream** stream) { if (*stream != NULL) { GTEST_LOG_(FATAL) << "Only one " << stream_name << " capturer can exist at a time."; @@ -9646,23 +10563,9 @@ std::string GetCapturedStderr() { #endif // GTEST_HAS_STREAM_REDIRECTION -std::string TempDir() { -#if GTEST_OS_WINDOWS_MOBILE - return "\\temp\\"; -#elif GTEST_OS_WINDOWS - const char* temp_dir = posix::GetEnv("TEMP"); - if (temp_dir == NULL || temp_dir[0] == '\0') - return "\\temp\\"; - else if (temp_dir[strlen(temp_dir) - 1] == '\\') - return temp_dir; - else - return std::string(temp_dir) + "\\"; -#elif GTEST_OS_LINUX_ANDROID - return "/sdcard/"; -#else - return "/tmp/"; -#endif // GTEST_OS_WINDOWS_MOBILE -} + + + size_t GetFileSize(FILE* file) { fseek(file, 0, SEEK_END); @@ -9692,22 +10595,36 @@ std::string ReadEntireFile(FILE* file) { } #if GTEST_HAS_DEATH_TEST +static const std::vector* g_injected_test_argvs = NULL; // Owned. -static const ::std::vector* g_injected_test_argvs = - NULL; // Owned. - -void SetInjectableArgvs(const ::std::vector* argvs) { - if (g_injected_test_argvs != argvs) - delete g_injected_test_argvs; - g_injected_test_argvs = argvs; -} - -const ::std::vector& GetInjectableArgvs() { +std::vector GetInjectableArgvs() { if (g_injected_test_argvs != NULL) { return *g_injected_test_argvs; } return GetArgvs(); } + +void SetInjectableArgvs(const std::vector* new_argvs) { + if (g_injected_test_argvs != new_argvs) delete g_injected_test_argvs; + g_injected_test_argvs = new_argvs; +} + +void SetInjectableArgvs(const std::vector& new_argvs) { + SetInjectableArgvs( + new std::vector(new_argvs.begin(), new_argvs.end())); +} + +#if GTEST_HAS_GLOBAL_STRING +void SetInjectableArgvs(const std::vector< ::string>& new_argvs) { + SetInjectableArgvs( + new std::vector(new_argvs.begin(), new_argvs.end())); +} +#endif // GTEST_HAS_GLOBAL_STRING + +void ClearInjectableArgvs() { + delete g_injected_test_argvs; + g_injected_test_argvs = NULL; +} #endif // GTEST_HAS_DEATH_TEST #if GTEST_OS_WINDOWS_MOBILE @@ -9782,11 +10699,12 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value) { bool BoolFromGTestEnv(const char* flag, bool default_value) { #if defined(GTEST_GET_BOOL_FROM_ENV_) return GTEST_GET_BOOL_FROM_ENV_(flag, default_value); -#endif // defined(GTEST_GET_BOOL_FROM_ENV_) +#else const std::string env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); return string_value == NULL ? default_value : strcmp(string_value, "0") != 0; +#endif // defined(GTEST_GET_BOOL_FROM_ENV_) } // Reads and returns a 32-bit integer stored in the environment @@ -9795,7 +10713,7 @@ bool BoolFromGTestEnv(const char* flag, bool default_value) { Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { #if defined(GTEST_GET_INT32_FROM_ENV_) return GTEST_GET_INT32_FROM_ENV_(flag, default_value); -#endif // defined(GTEST_GET_INT32_FROM_ENV_) +#else const std::string env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); if (string_value == NULL) { @@ -9813,37 +10731,36 @@ Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { } return result; +#endif // defined(GTEST_GET_INT32_FROM_ENV_) +} + +// As a special case for the 'output' flag, if GTEST_OUTPUT is not +// set, we look for XML_OUTPUT_FILE, which is set by the Bazel build +// system. The value of XML_OUTPUT_FILE is a filename without the +// "xml:" prefix of GTEST_OUTPUT. +// Note that this is meant to be called at the call site so it does +// not check that the flag is 'output' +// In essence this checks an env variable called XML_OUTPUT_FILE +// and if it is set we prepend "xml:" to its value, if it not set we return "" +std::string OutputFlagAlsoCheckEnvVar(){ + std::string default_value_for_output_flag = ""; + const char* xml_output_file_env = posix::GetEnv("XML_OUTPUT_FILE"); + if (NULL != xml_output_file_env) { + default_value_for_output_flag = std::string("xml:") + xml_output_file_env; + } + return default_value_for_output_flag; } // Reads and returns the string environment variable corresponding to // the given flag; if it's not set, returns default_value. -std::string StringFromGTestEnv(const char* flag, const char* default_value) { +const char* StringFromGTestEnv(const char* flag, const char* default_value) { #if defined(GTEST_GET_STRING_FROM_ENV_) return GTEST_GET_STRING_FROM_ENV_(flag, default_value); -#endif // defined(GTEST_GET_STRING_FROM_ENV_) +#else const std::string env_var = FlagToEnvVar(flag); - const char* value = posix::GetEnv(env_var.c_str()); - if (value != NULL) { - return value; - } - - // As a special case for the 'output' flag, if GTEST_OUTPUT is not - // set, we look for XML_OUTPUT_FILE, which is set by the Bazel build - // system. The value of XML_OUTPUT_FILE is a filename without the - // "xml:" prefix of GTEST_OUTPUT. - // - // The net priority order after flag processing is thus: - // --gtest_output command line flag - // GTEST_OUTPUT environment variable - // XML_OUTPUT_FILE environment variable - // 'default_value' - if (strcmp(flag, "output") == 0) { - value = posix::GetEnv("XML_OUTPUT_FILE"); - if (value != NULL) { - return std::string("xml:") + value; - } - } - return default_value; + const char* const value = posix::GetEnv(env_var.c_str()); + return value == NULL ? default_value : value; +#endif // defined(GTEST_GET_STRING_FROM_ENV_) } } // namespace internal @@ -9876,10 +10793,9 @@ std::string StringFromGTestEnv(const char* flag, const char* default_value) { // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan) -// Google Test - The Google C++ Testing Framework + +// Google Test - The Google C++ Testing and Mocking Framework // // This file implements a universal value printer that can print a // value of any type T: @@ -9892,8 +10808,8 @@ std::string StringFromGTestEnv(const char* flag, const char* default_value) { // or void PrintTo(const Foo&, ::std::ostream*) in the namespace that // defines Foo. -#include #include +#include #include #include // NOLINT #include @@ -9937,7 +10853,7 @@ void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, // If the object size is bigger than kThreshold, we'll have to omit // some details by printing only the first and the last kChunkSize // bytes. - // TODO(wan): let the user control the threshold using a flag. + // FIXME: let the user control the threshold using a flag. if (count < kThreshold) { PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); } else { @@ -10028,7 +10944,10 @@ static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { *os << static_cast(c); return kAsIs; } else { - *os << "\\x" + String::FormatHexInt(static_cast(c)); + ostream::fmtflags flags = os->flags(); + *os << "\\x" << std::hex << std::uppercase + << static_cast(static_cast(c)); + os->flags(flags); return kHexEscape; } } @@ -10107,11 +11026,12 @@ template GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ -static void PrintCharsAsStringTo( +static CharFormat PrintCharsAsStringTo( const CharType* begin, size_t len, ostream* os) { const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\""; *os << kQuoteBegin; bool is_previous_hex = false; + CharFormat print_format = kAsIs; for (size_t index = 0; index < len; ++index) { const CharType cur = begin[index]; if (is_previous_hex && IsXDigit(cur)) { @@ -10121,8 +11041,13 @@ static void PrintCharsAsStringTo( *os << "\" " << kQuoteBegin; } is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape; + // Remember if any characters required hex escaping. + if (is_previous_hex) { + print_format = kHexEscape; + } } *os << "\""; + return print_format; } // Prints a (const) char/wchar_t array of 'len' elements, starting at address @@ -10192,15 +11117,90 @@ void PrintTo(const wchar_t* s, ostream* os) { } #endif // wchar_t is native +namespace { + +bool ContainsUnprintableControlCodes(const char* str, size_t length) { + const unsigned char *s = reinterpret_cast(str); + + for (size_t i = 0; i < length; i++) { + unsigned char ch = *s++; + if (std::iscntrl(ch)) { + switch (ch) { + case '\t': + case '\n': + case '\r': + break; + default: + return true; + } + } + } + return false; +} + +bool IsUTF8TrailByte(unsigned char t) { return 0x80 <= t && t<= 0xbf; } + +bool IsValidUTF8(const char* str, size_t length) { + const unsigned char *s = reinterpret_cast(str); + + for (size_t i = 0; i < length;) { + unsigned char lead = s[i++]; + + if (lead <= 0x7f) { + continue; // single-byte character (ASCII) 0..7F + } + if (lead < 0xc2) { + return false; // trail byte or non-shortest form + } else if (lead <= 0xdf && (i + 1) <= length && IsUTF8TrailByte(s[i])) { + ++i; // 2-byte character + } else if (0xe0 <= lead && lead <= 0xef && (i + 2) <= length && + IsUTF8TrailByte(s[i]) && + IsUTF8TrailByte(s[i + 1]) && + // check for non-shortest form and surrogate + (lead != 0xe0 || s[i] >= 0xa0) && + (lead != 0xed || s[i] < 0xa0)) { + i += 2; // 3-byte character + } else if (0xf0 <= lead && lead <= 0xf4 && (i + 3) <= length && + IsUTF8TrailByte(s[i]) && + IsUTF8TrailByte(s[i + 1]) && + IsUTF8TrailByte(s[i + 2]) && + // check for non-shortest form + (lead != 0xf0 || s[i] >= 0x90) && + (lead != 0xf4 || s[i] < 0x90)) { + i += 3; // 4-byte character + } else { + return false; + } + } + return true; +} + +void ConditionalPrintAsText(const char* str, size_t length, ostream* os) { + if (!ContainsUnprintableControlCodes(str, length) && + IsValidUTF8(str, length)) { + *os << "\n As Text: \"" << str << "\""; + } +} + +} // anonymous namespace + // Prints a ::string object. #if GTEST_HAS_GLOBAL_STRING void PrintStringTo(const ::string& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); + if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) { + if (GTEST_FLAG(print_utf8)) { + ConditionalPrintAsText(s.data(), s.size(), os); + } + } } #endif // GTEST_HAS_GLOBAL_STRING void PrintStringTo(const ::std::string& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); + if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) { + if (GTEST_FLAG(print_utf8)) { + ConditionalPrintAsText(s.data(), s.size(), os); + } + } } // Prints a ::wstring object. @@ -10247,19 +11247,10 @@ void PrintWideStringTo(const ::std::wstring& s, ostream* os) { // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: mheule@google.com (Markus Heule) -// -// The Google C++ Testing Framework (Google Test) +// +// The Google C++ Testing and Mocking Framework (Google Test) -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick exists to -// prevent the accidental inclusion of gtest-internal-inl.h in the -// user's code. -#define GTEST_IMPLEMENTATION_ 1 -#undef GTEST_IMPLEMENTATION_ namespace testing { @@ -10355,8 +11346,8 @@ void HasNewFatalFailureHelper::ReportTestPartResult( // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Author: wan@google.com (Zhanyong Wan) + + namespace testing { diff --git a/modules/videoio/src/cap_msmf.cpp b/modules/videoio/src/cap_msmf.cpp index 863f46bc8989..a540238d2361 100644 --- a/modules/videoio/src/cap_msmf.cpp +++ b/modules/videoio/src/cap_msmf.cpp @@ -616,7 +616,7 @@ class SourceReaderCB : public IMFSourceReaderCallback { public: SourceReaderCB() : - m_nRefCount(1), m_hEvent(CreateEvent(NULL, FALSE, FALSE, NULL)), m_bEOS(FALSE), m_hrStatus(S_OK), m_dwStreamIndex(0) + m_nRefCount(0), m_hEvent(CreateEvent(NULL, FALSE, FALSE, NULL)), m_bEOS(FALSE), m_hrStatus(S_OK), m_reader(NULL), m_dwStreamIndex(0) { } @@ -677,7 +677,7 @@ class SourceReaderCB : public IMFSourceReaderCallback BOOL m_bEOS; HRESULT m_hrStatus; - _ComPtr m_reader; + IMFSourceReader *m_reader; DWORD m_dwStreamIndex; _ComPtr m_lastSample; }; @@ -1140,7 +1140,7 @@ bool CvCapture_MSMF::grabFrame() if (!reader->m_reader) { // Initiate capturing with async callback - reader->m_reader = videoFileSource; + reader->m_reader = videoFileSource.Get(); reader->m_dwStreamIndex = dwStreamIndex; if (FAILED(hr = videoFileSource->ReadSample(dwStreamIndex, 0, NULL, NULL, NULL, NULL))) { diff --git a/modules/videoio/src/cap_v4l.cpp b/modules/videoio/src/cap_v4l.cpp index 524fc0d35ebc..e0077c684510 100644 --- a/modules/videoio/src/cap_v4l.cpp +++ b/modules/videoio/src/cap_v4l.cpp @@ -513,9 +513,11 @@ static void v4l2_scan_controls(CvCaptureCAM_V4L* capture) for (ctrl_id = V4L2_CID_PRIVATE_BASE;;ctrl_id++) { + errno = 0; + v4l2_control_range(capture, ctrl_id); - if (errno == EINVAL) + if (errno) break; } diff --git a/platforms/linux/gnu.toolchain.cmake b/platforms/linux/gnu.toolchain.cmake index fc53dbf9f11e..cba08e7fbbf4 100644 --- a/platforms/linux/gnu.toolchain.cmake +++ b/platforms/linux/gnu.toolchain.cmake @@ -56,8 +56,6 @@ else() endmacro() endif() # IN_TRY_COMPILE -set(CMAKE_SKIP_RPATH TRUE) - if(NOT CMAKE_FIND_ROOT_PATH_MODE_LIBRARY) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) endif() diff --git a/samples/cpp/CMakeLists.txt b/samples/cpp/CMakeLists.txt index a96b9e6ad833..d12cc9d7d626 100644 --- a/samples/cpp/CMakeLists.txt +++ b/samples/cpp/CMakeLists.txt @@ -36,9 +36,6 @@ endif() if(NOT BUILD_opencv_viz OR NOT VTK_USE_FILE) ocv_list_filterout(cpp_samples "/viz/") endif() -if(NOT HAVE_IPP_A) - ocv_list_filterout(cpp_samples "/ippasync/") -endif() ocv_list_filterout(cpp_samples "real_time_pose_estimation/") foreach(sample_filename ${cpp_samples}) if(sample_filename MATCHES "/viz/") diff --git a/samples/cpp/tutorial_code/ImgProc/motion_deblur_filter/motion_deblur_filter.cpp b/samples/cpp/tutorial_code/ImgProc/motion_deblur_filter/motion_deblur_filter.cpp new file mode 100755 index 000000000000..f1ea892c89d3 --- /dev/null +++ b/samples/cpp/tutorial_code/ImgProc/motion_deblur_filter/motion_deblur_filter.cpp @@ -0,0 +1,184 @@ +/** +* @brief You will learn how to recover an image with motion blur distortion using a Wiener filter +* @author Karpushin Vladislav, karpushin@ngs.ru, https://github.com/VladKarpushin +*/ +#include +#include "opencv2/imgproc.hpp" +#include "opencv2/imgcodecs.hpp" + +using namespace cv; +using namespace std; + +void help(); +void calcPSF(Mat& outputImg, Size filterSize, int len, double theta); +void fftshift(const Mat& inputImg, Mat& outputImg); +void filter2DFreq(const Mat& inputImg, Mat& outputImg, const Mat& H); +void calcWnrFilter(const Mat& input_h_PSF, Mat& output_G, double nsr); +void edgetaper(const Mat& inputImg, Mat& outputImg, double gamma = 5.0, double beta = 0.2); + +const String keys = +"{help h usage ? | | print this message }" +"{image |input.png | input image name }" +"{LEN |125 | length of a motion }" +"{THETA |0 | angle of a motion in degrees }" +"{SNR |700 | signal to noise ratio }" +; + +int main(int argc, char *argv[]) +{ + help(); + CommandLineParser parser(argc, argv, keys); + if (parser.has("help")) + { + parser.printMessage(); + return 0; + } + + int LEN = parser.get("LEN"); + double THETA = parser.get("THETA"); + int snr = parser.get("SNR"); + string strInFileName = parser.get("image"); + + if (!parser.check()) + { + parser.printErrors(); + return 0; + } + + Mat imgIn; + imgIn = imread(strInFileName, IMREAD_GRAYSCALE); + if (imgIn.empty()) //check whether the image is loaded or not + { + cout << "ERROR : Image cannot be loaded..!!" << endl; + return -1; + } + + Mat imgOut; + +//! [main] + // it needs to process even image only + Rect roi = Rect(0, 0, imgIn.cols & -2, imgIn.rows & -2); + + //Hw calculation (start) + Mat Hw, h; + calcPSF(h, roi.size(), LEN, THETA); + calcWnrFilter(h, Hw, 1.0 / double(snr)); + //Hw calculation (stop) + + imgIn.convertTo(imgIn, CV_32F); + edgetaper(imgIn, imgIn); + + // filtering (start) + filter2DFreq(imgIn(roi), imgOut, Hw); + // filtering (stop) +//! [main] + + imgOut.convertTo(imgOut, CV_8U); + normalize(imgOut, imgOut, 0, 255, NORM_MINMAX); + imwrite("result.jpg", imgOut); + return 0; +} + +void help() +{ + cout << "2018-08-14" << endl; + cout << "Motion_deblur_v2" << endl; + cout << "You will learn how to recover an image with motion blur distortion using a Wiener filter" << endl; +} + +//! [calcPSF] +void calcPSF(Mat& outputImg, Size filterSize, int len, double theta) +{ + Mat h(filterSize, CV_32F, Scalar(0)); + Point point(filterSize.width / 2, filterSize.height / 2); + ellipse(h, point, Size(0, cvRound(float(len) / 2.0)), 90.0 - theta, 0, 360, Scalar(255), FILLED); + Scalar summa = sum(h); + outputImg = h / summa[0]; +} +//! [calcPSF] + +//! [fftshift] +void fftshift(const Mat& inputImg, Mat& outputImg) +{ + outputImg = inputImg.clone(); + int cx = outputImg.cols / 2; + int cy = outputImg.rows / 2; + Mat q0(outputImg, Rect(0, 0, cx, cy)); + Mat q1(outputImg, Rect(cx, 0, cx, cy)); + Mat q2(outputImg, Rect(0, cy, cx, cy)); + Mat q3(outputImg, Rect(cx, cy, cx, cy)); + Mat tmp; + q0.copyTo(tmp); + q3.copyTo(q0); + tmp.copyTo(q3); + q1.copyTo(tmp); + q2.copyTo(q1); + tmp.copyTo(q2); +} +//! [fftshift] + +//! [filter2DFreq] +void filter2DFreq(const Mat& inputImg, Mat& outputImg, const Mat& H) +{ + Mat planes[2] = { Mat_(inputImg.clone()), Mat::zeros(inputImg.size(), CV_32F) }; + Mat complexI; + merge(planes, 2, complexI); + dft(complexI, complexI, DFT_SCALE); + + Mat planesH[2] = { Mat_(H.clone()), Mat::zeros(H.size(), CV_32F) }; + Mat complexH; + merge(planesH, 2, complexH); + Mat complexIH; + mulSpectrums(complexI, complexH, complexIH, 0); + + idft(complexIH, complexIH); + split(complexIH, planes); + outputImg = planes[0]; +} +//! [filter2DFreq] + +//! [calcWnrFilter] +void calcWnrFilter(const Mat& input_h_PSF, Mat& output_G, double nsr) +{ + Mat h_PSF_shifted; + fftshift(input_h_PSF, h_PSF_shifted); + Mat planes[2] = { Mat_(h_PSF_shifted.clone()), Mat::zeros(h_PSF_shifted.size(), CV_32F) }; + Mat complexI; + merge(planes, 2, complexI); + dft(complexI, complexI); + split(complexI, planes); + Mat denom; + pow(abs(planes[0]), 2, denom); + denom += nsr; + divide(planes[0], denom, output_G); +} +//! [calcWnrFilter] + +//! [edgetaper] +void edgetaper(const Mat& inputImg, Mat& outputImg, double gamma, double beta) +{ + int Nx = inputImg.cols; + int Ny = inputImg.rows; + Mat w1(1, Nx, CV_32F, Scalar(0)); + Mat w2(Ny, 1, CV_32F, Scalar(0)); + + float* p1 = w1.ptr(0); + float* p2 = w2.ptr(0); + float dx = float(2.0 * CV_PI / Nx); + float x = float(-CV_PI); + for (int i = 0; i < Nx; i++) + { + p1[i] = float(0.5 * (tanh((x + gamma / 2) / beta) - tanh((x - gamma / 2) / beta))); + x += dx; + } + float dy = float(2.0 * CV_PI / Ny); + float y = float(-CV_PI); + for (int i = 0; i < Ny; i++) + { + p2[i] = float(0.5 * (tanh((y + gamma / 2) / beta) - tanh((y - gamma / 2) / beta))); + y += dy; + } + Mat w = w2 * w1; + multiply(inputImg, w, outputImg); +} +//! [edgetaper] diff --git a/samples/cpp/tutorial_code/core/ippasync/ippasync_sample.cpp b/samples/cpp/tutorial_code/core/ippasync/ippasync_sample.cpp deleted file mode 100644 index 0a25f15d125b..000000000000 --- a/samples/cpp/tutorial_code/core/ippasync/ippasync_sample.cpp +++ /dev/null @@ -1,168 +0,0 @@ -#include - -#include "opencv2/core/utility.hpp" -#include "opencv2/imgproc.hpp" -#include "opencv2/highgui.hpp" -#include "cvconfig.h" - -using namespace std; -using namespace cv; - -#ifdef HAVE_IPP_A -#include "opencv2/core/ippasync.hpp" - -#define CHECK_STATUS(STATUS, NAME)\ - if(STATUS!=HPP_STATUS_NO_ERROR){ printf("%s error %d\n", NAME, STATUS);\ - if (virtMatrix) {hppStatus delSts = hppiDeleteVirtualMatrices(accel, virtMatrix); CHECK_DEL_STATUS(delSts,"hppiDeleteVirtualMatrices");}\ - if (accel) {hppStatus delSts = hppDeleteInstance(accel); CHECK_DEL_STATUS(delSts, "hppDeleteInstance");}\ - return -1;} - -#define CHECK_DEL_STATUS(STATUS, NAME)\ - if(STATUS!=HPP_STATUS_NO_ERROR){ printf("%s error %d\n", NAME, STATUS); return -1;} - -#endif - -static void help() -{ - printf("\nThis program shows how to use the conversion for IPP Async.\n" -"This example uses the Sobel filter.\n" -"You can use cv::Sobel or hppiSobel.\n" -"Usage: \n" -"./ipp_async_sobel [--camera]=, \n" -" [--file_name]=\n" -" [--accel]=\n\n"); -} - -const char* keys = -{ - "{c camera | | use camera or not}" - "{fn file_name|../data/baboon.jpg | image file }" - "{a accel |auto | accelerator type: auto (default), cpu, gpu}" -}; - -//this is a sample for hppiSobel functions -int main(int argc, const char** argv) -{ - help(); - - VideoCapture cap; - CommandLineParser parser(argc, argv, keys); - Mat image, gray, result; - -#ifdef HAVE_IPP_A - - hppiMatrix* src,* dst; - hppAccel accel = 0; - hppAccelType accelType; - hppStatus sts; - hppiVirtualMatrix * virtMatrix; - - bool useCamera = parser.has("camera"); - string file = parser.get("file_name"); - string sAccel = parser.get("accel"); - - parser.printMessage(); - - if( useCamera ) - { - printf("used camera\n"); - cap.open(0); - } - else - { - printf("used image %s\n", file.c_str()); - cap.open(file.c_str()); - } - - if( !cap.isOpened() ) - { - printf("can not open camera or video file\n"); - return -1; - } - - accelType = sAccel == "cpu" ? HPP_ACCEL_TYPE_CPU: - sAccel == "gpu" ? HPP_ACCEL_TYPE_GPU: - HPP_ACCEL_TYPE_ANY; - - //Create accelerator instance - sts = hppCreateInstance(accelType, 0, &accel); - CHECK_STATUS(sts, "hppCreateInstance"); - - accelType = hppQueryAccelType(accel); - - sAccel = accelType == HPP_ACCEL_TYPE_CPU ? "cpu": - accelType == HPP_ACCEL_TYPE_GPU ? "gpu": - accelType == HPP_ACCEL_TYPE_GPU_VIA_DX9 ? "gpu dx9": "?"; - - printf("accelType %s\n", sAccel.c_str()); - - virtMatrix = hppiCreateVirtualMatrices(accel, 1); - - for(;;) - { - cap >> image; - if(image.empty()) - break; - - cvtColor( image, gray, COLOR_BGR2GRAY ); - - result.create( image.rows, image.cols, CV_8U); - - double execTime = (double)getTickCount(); - - //convert Mat to hppiMatrix - src = hpp::getHpp(gray,accel); - dst = hpp::getHpp(result,accel); - - sts = hppiSobel(accel,src, HPP_MASK_SIZE_3X3,HPP_NORM_L1,virtMatrix[0]); - CHECK_STATUS(sts,"hppiSobel"); - - sts = hppiConvert(accel, virtMatrix[0], 0, HPP_RND_MODE_NEAR, dst, HPP_DATA_TYPE_8U); - CHECK_STATUS(sts,"hppiConvert"); - - // Wait for tasks to complete - sts = hppWait(accel, HPP_TIME_OUT_INFINITE); - CHECK_STATUS(sts, "hppWait"); - - execTime = ((double)getTickCount() - execTime)*1000./getTickFrequency(); - - printf("Time : %0.3fms\n", execTime); - - imshow("image", image); - imshow("rez", result); - - waitKey(15); - - sts = hppiFreeMatrix(src); - CHECK_DEL_STATUS(sts,"hppiFreeMatrix"); - - sts = hppiFreeMatrix(dst); - CHECK_DEL_STATUS(sts,"hppiFreeMatrix"); - - } - - if (!useCamera) - waitKey(0); - - if (virtMatrix) - { - sts = hppiDeleteVirtualMatrices(accel, virtMatrix); - CHECK_DEL_STATUS(sts,"hppiDeleteVirtualMatrices"); - } - - if (accel) - { - sts = hppDeleteInstance(accel); - CHECK_DEL_STATUS(sts, "hppDeleteInstance"); - } - - printf("SUCCESS\n"); - -#else - - printf("IPP Async not supported\n"); - -#endif - - return 0; -} diff --git a/samples/dnn/object_detection.py b/samples/dnn/object_detection.py index 329c349e4919..76c33f8e3b62 100644 --- a/samples/dnn/object_detection.py +++ b/samples/dnn/object_detection.py @@ -3,6 +3,10 @@ import sys import numpy as np +from tf_text_graph_common import readTextMessage +from tf_text_graph_ssd import createSSDGraph +from tf_text_graph_faster_rcnn import createFasterRCNNGraph + backends = (cv.dnn.DNN_BACKEND_DEFAULT, cv.dnn.DNN_BACKEND_HALIDE, cv.dnn.DNN_BACKEND_INFERENCE_ENGINE, cv.dnn.DNN_BACKEND_OPENCV) targets = (cv.dnn.DNN_TARGET_CPU, cv.dnn.DNN_TARGET_OPENCL, cv.dnn.DNN_TARGET_OPENCL_FP16, cv.dnn.DNN_TARGET_MYRIAD) @@ -11,11 +15,15 @@ parser.add_argument('--model', required=True, help='Path to a binary file of model contains trained weights. ' 'It could be a file with extensions .caffemodel (Caffe), ' - '.pb (TensorFlow), .t7 or .net (Torch), .weights (Darknet)') + '.pb (TensorFlow), .t7 or .net (Torch), .weights (Darknet), .bin (OpenVINO)') parser.add_argument('--config', help='Path to a text file of model contains network configuration. ' - 'It could be a file with extensions .prototxt (Caffe), .pbtxt (TensorFlow), .cfg (Darknet)') -parser.add_argument('--framework', choices=['caffe', 'tensorflow', 'torch', 'darknet'], + 'It could be a file with extensions .prototxt (Caffe), .pbtxt or .config (TensorFlow), .cfg (Darknet), .xml (OpenVINO)') +parser.add_argument('--out_tf_graph', default='graph.pbtxt', + help='For models from TensorFlow Object Detection API, you may ' + 'pass a .config file which was used for training through --config ' + 'argument. This way an additional .pbtxt file with TensorFlow graph will be created.') +parser.add_argument('--framework', choices=['caffe', 'tensorflow', 'torch', 'darknet', 'dldt'], help='Optional name of an origin framework of the model. ' 'Detect it automatically if it does not set.') parser.add_argument('--classes', help='Optional path to a text file with names of classes to label detected objects.') @@ -46,6 +54,20 @@ '%d: VPU' % targets) args = parser.parse_args() +# If config specified, try to load it as TensorFlow Object Detection API's pipeline. +config = readTextMessage(args.config) +if 'model' in config: + print('TensorFlow Object Detection API config detected') + if 'ssd' in config['model'][0]: + print('Preparing text graph representation for SSD model: ' + args.out_tf_graph) + createSSDGraph(args.model, args.config, args.out_tf_graph) + args.config = args.out_tf_graph + elif 'faster_rcnn' in config['model'][0]: + print('Preparing text graph representation for Faster-RCNN model: ' + args.out_tf_graph) + createFasterRCNNGraph(args.model, args.config, args.out_tf_graph) + args.config = args.out_tf_graph + + # Load names of classes classes = None if args.classes: @@ -142,8 +164,8 @@ def drawPred(classId, conf, left, top, right, bottom): center_y = int(detection[1] * frameHeight) width = int(detection[2] * frameWidth) height = int(detection[3] * frameHeight) - left = center_x - width / 2 - top = center_y - height / 2 + left = int(center_x - width / 2) + top = int(center_y - height / 2) classIds.append(classId) confidences.append(float(confidence)) boxes.append([left, top, width, height]) diff --git a/samples/dnn/tf_text_graph_common.py b/samples/dnn/tf_text_graph_common.py index 061718e7a019..d4d202e68297 100644 --- a/samples/dnn/tf_text_graph_common.py +++ b/samples/dnn/tf_text_graph_common.py @@ -1,8 +1,86 @@ -import tensorflow as tf -from tensorflow.core.framework.node_def_pb2 import NodeDef -from google.protobuf import text_format +def tokenize(s): + tokens = [] + token = "" + isString = False + isComment = False + for symbol in s: + isComment = (isComment and symbol != '\n') or (not isString and symbol == '#') + if isComment: + continue -def tensorMsg(values): + if symbol == ' ' or symbol == '\t' or symbol == '\r' or symbol == '\'' or \ + symbol == '\n' or symbol == ':' or symbol == '\"' or symbol == ';' or \ + symbol == ',': + + if (symbol == '\"' or symbol == '\'') and isString: + tokens.append(token) + token = "" + else: + if isString: + token += symbol + elif token: + tokens.append(token) + token = "" + isString = (symbol == '\"' or symbol == '\'') ^ isString; + + elif symbol == '{' or symbol == '}' or symbol == '[' or symbol == ']': + if token: + tokens.append(token) + token = "" + tokens.append(symbol) + else: + token += symbol + if token: + tokens.append(token) + return tokens + + +def parseMessage(tokens, idx): + msg = {} + assert(tokens[idx] == '{') + + isArray = False + while True: + if not isArray: + idx += 1 + if idx < len(tokens): + fieldName = tokens[idx] + else: + return None + if fieldName == '}': + break + + idx += 1 + fieldValue = tokens[idx] + + if fieldValue == '{': + embeddedMsg, idx = parseMessage(tokens, idx) + if fieldName in msg: + msg[fieldName].append(embeddedMsg) + else: + msg[fieldName] = [embeddedMsg] + elif fieldValue == '[': + isArray = True + elif fieldValue == ']': + isArray = False + else: + if fieldName in msg: + msg[fieldName].append(fieldValue) + else: + msg[fieldName] = [fieldValue] + return msg, idx + + +def readTextMessage(filePath): + with open(filePath, 'rt') as f: + content = f.read() + + tokens = tokenize('{' + content + '}') + msg = parseMessage(tokens, 0) + return msg[0] if msg else {} + + +def listToTensor(values): if all([isinstance(v, float) for v in values]): dtype = 'DT_FLOAT' field = 'float_val' @@ -12,16 +90,25 @@ def tensorMsg(values): else: raise Exception('Wrong values types') - msg = 'tensor { dtype: ' + dtype + ' tensor_shape { dim { size: %d } }' % len(values) - for value in values: - msg += '%s: %s ' % (field, str(value)) - return msg + '}' + msg = { + 'tensor': { + 'dtype': dtype, + 'tensor_shape': { + 'dim': { + 'size': len(values) + } + } + } + } + msg['tensor'][field] = values + return msg + def addConstNode(name, values, graph_def): node = NodeDef() node.name = name node.op = 'Const' - text_format.Merge(tensorMsg(values), node.attr["value"]) + node.addAttr('value', values) graph_def.node.extend([node]) @@ -29,13 +116,13 @@ def addSlice(inp, out, begins, sizes, graph_def): beginsNode = NodeDef() beginsNode.name = out + '/begins' beginsNode.op = 'Const' - text_format.Merge(tensorMsg(begins), beginsNode.attr["value"]) + beginsNode.addAttr('value', begins) graph_def.node.extend([beginsNode]) sizesNode = NodeDef() sizesNode.name = out + '/sizes' sizesNode.op = 'Const' - text_format.Merge(tensorMsg(sizes), sizesNode.attr["value"]) + sizesNode.addAttr('value', sizes) graph_def.node.extend([sizesNode]) sliced = NodeDef() @@ -51,7 +138,7 @@ def addReshape(inp, out, shape, graph_def): shapeNode = NodeDef() shapeNode.name = out + '/shape' shapeNode.op = 'Const' - text_format.Merge(tensorMsg(shape), shapeNode.attr["value"]) + shapeNode.addAttr('value', shape) graph_def.node.extend([shapeNode]) reshape = NodeDef() @@ -66,7 +153,7 @@ def addSoftMax(inp, out, graph_def): softmax = NodeDef() softmax.name = out softmax.op = 'Softmax' - text_format.Merge('i: -1', softmax.attr['axis']) + softmax.addAttr('axis', -1) softmax.input.append(inp) graph_def.node.extend([softmax]) @@ -79,6 +166,103 @@ def addFlatten(inp, out, graph_def): graph_def.node.extend([flatten]) +class NodeDef: + def __init__(self): + self.input = [] + self.name = "" + self.op = "" + self.attr = {} + + def addAttr(self, key, value): + assert(not key in self.attr) + if isinstance(value, bool): + self.attr[key] = {'b': value} + elif isinstance(value, int): + self.attr[key] = {'i': value} + elif isinstance(value, float): + self.attr[key] = {'f': value} + elif isinstance(value, str): + self.attr[key] = {'s': value} + elif isinstance(value, list): + self.attr[key] = listToTensor(value) + else: + raise Exception('Unknown type of attribute ' + key) + + def Clear(self): + self.input = [] + self.name = "" + self.op = "" + self.attr = {} + + +class GraphDef: + def __init__(self): + self.node = [] + + def save(self, filePath): + with open(filePath, 'wt') as f: + + def printAttr(d, indent): + indent = ' ' * indent + for key, value in sorted(d.items(), key=lambda x:x[0].lower()): + value = value if isinstance(value, list) else [value] + for v in value: + if isinstance(v, dict): + f.write(indent + key + ' {\n') + printAttr(v, len(indent) + 2) + f.write(indent + '}\n') + else: + isString = False + if isinstance(v, str) and not v.startswith('DT_'): + try: + float(v) + except: + isString = True + + if isinstance(v, bool): + printed = 'true' if v else 'false' + elif v == 'true' or v == 'false': + printed = 'true' if v == 'true' else 'false' + elif isString: + printed = '\"%s\"' % v + else: + printed = str(v) + f.write(indent + key + ': ' + printed + '\n') + + for node in self.node: + f.write('node {\n') + f.write(' name: \"%s\"\n' % node.name) + f.write(' op: \"%s\"\n' % node.op) + for inp in node.input: + f.write(' input: \"%s\"\n' % inp) + for key, value in sorted(node.attr.items(), key=lambda x:x[0].lower()): + f.write(' attr {\n') + f.write(' key: \"%s\"\n' % key) + f.write(' value {\n') + printAttr(value, 6) + f.write(' }\n') + f.write(' }\n') + f.write('}\n') + + +def parseTextGraph(filePath): + msg = readTextMessage(filePath) + + graph = GraphDef() + for node in msg['node']: + graphNode = NodeDef() + graphNode.name = node['name'][0] + graphNode.op = node['op'][0] + graphNode.input = node['input'] if 'input' in node else [] + + if 'attr' in node: + for attr in node['attr']: + graphNode.attr[attr['key'][0]] = attr['value'][0] + + graph.node.append(graphNode) + return graph + + # Removes Identity nodes def removeIdentity(graph_def): identities = {} diff --git a/samples/dnn/tf_text_graph_faster_rcnn.py b/samples/dnn/tf_text_graph_faster_rcnn.py index d18d82bfae98..368edaa6fa59 100644 --- a/samples/dnn/tf_text_graph_faster_rcnn.py +++ b/samples/dnn/tf_text_graph_faster_rcnn.py @@ -1,212 +1,228 @@ import argparse import numpy as np -import tensorflow as tf - -from tensorflow.core.framework.node_def_pb2 import NodeDef -from tensorflow.tools.graph_transforms import TransformGraph -from google.protobuf import text_format - +import cv2 as cv from tf_text_graph_common import * -parser = argparse.ArgumentParser(description='Run this script to get a text graph of ' - 'SSD model from TensorFlow Object Detection API. ' - 'Then pass it with .pb file to cv::dnn::readNetFromTensorflow function.') -parser.add_argument('--input', required=True, help='Path to frozen TensorFlow graph.') -parser.add_argument('--output', required=True, help='Path to output text graph.') -parser.add_argument('--num_classes', default=90, type=int, help='Number of trained classes.') -parser.add_argument('--scales', default=[0.25, 0.5, 1.0, 2.0], type=float, nargs='+', - help='Hyper-parameter of grid_anchor_generator from a config file.') -parser.add_argument('--aspect_ratios', default=[0.5, 1.0, 2.0], type=float, nargs='+', - help='Hyper-parameter of grid_anchor_generator from a config file.') -parser.add_argument('--features_stride', default=16, type=float, nargs='+', - help='Hyper-parameter from a config file.') -args = parser.parse_args() - -scopesToKeep = ('FirstStageFeatureExtractor', 'Conv', - 'FirstStageBoxPredictor/BoxEncodingPredictor', - 'FirstStageBoxPredictor/ClassPredictor', - 'CropAndResize', - 'MaxPool2D', - 'SecondStageFeatureExtractor', - 'SecondStageBoxPredictor', - 'image_tensor') - -scopesToIgnore = ('FirstStageFeatureExtractor/Assert', - 'FirstStageFeatureExtractor/Shape', - 'FirstStageFeatureExtractor/strided_slice', - 'FirstStageFeatureExtractor/GreaterEqual', - 'FirstStageFeatureExtractor/LogicalAnd') - -# Read the graph. -with tf.gfile.FastGFile(args.input, 'rb') as f: - graph_def = tf.GraphDef() - graph_def.ParseFromString(f.read()) - -removeIdentity(graph_def) - -def to_remove(name, op): - return name.startswith(scopesToIgnore) or not name.startswith(scopesToKeep) - -removeUnusedNodesAndAttrs(to_remove, graph_def) - - -# Connect input node to the first layer -assert(graph_def.node[0].op == 'Placeholder') -graph_def.node[1].input.insert(0, graph_def.node[0].name) - -# Temporarily remove top nodes. -topNodes = [] -while True: - node = graph_def.node.pop() - topNodes.append(node) - if node.op == 'CropAndResize': - break - -addReshape('FirstStageBoxPredictor/ClassPredictor/BiasAdd', - 'FirstStageBoxPredictor/ClassPredictor/reshape_1', [0, -1, 2], graph_def) - -addSoftMax('FirstStageBoxPredictor/ClassPredictor/reshape_1', - 'FirstStageBoxPredictor/ClassPredictor/softmax', graph_def) # Compare with Reshape_4 - -addFlatten('FirstStageBoxPredictor/ClassPredictor/softmax', - 'FirstStageBoxPredictor/ClassPredictor/softmax/flatten', graph_def) - -# Compare with FirstStageBoxPredictor/BoxEncodingPredictor/BiasAdd -addFlatten('FirstStageBoxPredictor/BoxEncodingPredictor/BiasAdd', - 'FirstStageBoxPredictor/BoxEncodingPredictor/flatten', graph_def) - -proposals = NodeDef() -proposals.name = 'proposals' # Compare with ClipToWindow/Gather/Gather (NOTE: normalized) -proposals.op = 'PriorBox' -proposals.input.append('FirstStageBoxPredictor/BoxEncodingPredictor/BiasAdd') -proposals.input.append(graph_def.node[0].name) # image_tensor - -text_format.Merge('b: false', proposals.attr["flip"]) -text_format.Merge('b: true', proposals.attr["clip"]) -text_format.Merge('f: %f' % args.features_stride, proposals.attr["step"]) -text_format.Merge('f: 0.0', proposals.attr["offset"]) -text_format.Merge(tensorMsg([0.1, 0.1, 0.2, 0.2]), proposals.attr["variance"]) - -widths = [] -heights = [] -for a in args.aspect_ratios: - for s in args.scales: - ar = np.sqrt(a) - heights.append((args.features_stride**2) * s / ar) - widths.append((args.features_stride**2) * s * ar) - -text_format.Merge(tensorMsg(widths), proposals.attr["width"]) -text_format.Merge(tensorMsg(heights), proposals.attr["height"]) - -graph_def.node.extend([proposals]) - -# Compare with Reshape_5 -detectionOut = NodeDef() -detectionOut.name = 'detection_out' -detectionOut.op = 'DetectionOutput' - -detectionOut.input.append('FirstStageBoxPredictor/BoxEncodingPredictor/flatten') -detectionOut.input.append('FirstStageBoxPredictor/ClassPredictor/softmax/flatten') -detectionOut.input.append('proposals') - -text_format.Merge('i: 2', detectionOut.attr['num_classes']) -text_format.Merge('b: true', detectionOut.attr['share_location']) -text_format.Merge('i: 0', detectionOut.attr['background_label_id']) -text_format.Merge('f: 0.7', detectionOut.attr['nms_threshold']) -text_format.Merge('i: 6000', detectionOut.attr['top_k']) -text_format.Merge('s: "CENTER_SIZE"', detectionOut.attr['code_type']) -text_format.Merge('i: 100', detectionOut.attr['keep_top_k']) -text_format.Merge('b: false', detectionOut.attr['clip']) - -graph_def.node.extend([detectionOut]) - -addConstNode('clip_by_value/lower', [0.0], graph_def) -addConstNode('clip_by_value/upper', [1.0], graph_def) - -clipByValueNode = NodeDef() -clipByValueNode.name = 'detection_out/clip_by_value' -clipByValueNode.op = 'ClipByValue' -clipByValueNode.input.append('detection_out') -clipByValueNode.input.append('clip_by_value/lower') -clipByValueNode.input.append('clip_by_value/upper') -graph_def.node.extend([clipByValueNode]) - -# Save as text. -for node in reversed(topNodes): - graph_def.node.extend([node]) - -addSoftMax('SecondStageBoxPredictor/Reshape_1', 'SecondStageBoxPredictor/Reshape_1/softmax', graph_def) - -addSlice('SecondStageBoxPredictor/Reshape_1/softmax', - 'SecondStageBoxPredictor/Reshape_1/slice', - [0, 0, 1], [-1, -1, -1], graph_def) - -addReshape('SecondStageBoxPredictor/Reshape_1/slice', - 'SecondStageBoxPredictor/Reshape_1/Reshape', [1, -1], graph_def) - -# Replace Flatten subgraph onto a single node. -for i in reversed(range(len(graph_def.node))): - if graph_def.node[i].op == 'CropAndResize': - graph_def.node[i].input.insert(1, 'detection_out/clip_by_value') - - if graph_def.node[i].name == 'SecondStageBoxPredictor/Reshape': - addConstNode('SecondStageBoxPredictor/Reshape/shape2', [1, -1, 4], graph_def) - - graph_def.node[i].input.pop() - graph_def.node[i].input.append('SecondStageBoxPredictor/Reshape/shape2') - - if graph_def.node[i].name in ['SecondStageBoxPredictor/Flatten/flatten/Shape', - 'SecondStageBoxPredictor/Flatten/flatten/strided_slice', - 'SecondStageBoxPredictor/Flatten/flatten/Reshape/shape']: - del graph_def.node[i] - -for node in graph_def.node: - if node.name == 'SecondStageBoxPredictor/Flatten/flatten/Reshape': - node.op = 'Flatten' - node.input.pop() - - if node.name in ['FirstStageBoxPredictor/BoxEncodingPredictor/Conv2D', - 'SecondStageBoxPredictor/BoxEncodingPredictor/MatMul']: - text_format.Merge('b: true', node.attr["loc_pred_transposed"]) - -################################################################################ -### Postprocessing -################################################################################ -addSlice('detection_out/clip_by_value', 'detection_out/slice', [0, 0, 0, 3], [-1, -1, -1, 4], graph_def) - -variance = NodeDef() -variance.name = 'proposals/variance' -variance.op = 'Const' -text_format.Merge(tensorMsg([0.1, 0.1, 0.2, 0.2]), variance.attr["value"]) -graph_def.node.extend([variance]) - -varianceEncoder = NodeDef() -varianceEncoder.name = 'variance_encoded' -varianceEncoder.op = 'Mul' -varianceEncoder.input.append('SecondStageBoxPredictor/Reshape') -varianceEncoder.input.append(variance.name) -text_format.Merge('i: 2', varianceEncoder.attr["axis"]) -graph_def.node.extend([varianceEncoder]) - -addReshape('detection_out/slice', 'detection_out/slice/reshape', [1, 1, -1], graph_def) -addFlatten('variance_encoded', 'variance_encoded/flatten', graph_def) - -detectionOut = NodeDef() -detectionOut.name = 'detection_out_final' -detectionOut.op = 'DetectionOutput' - -detectionOut.input.append('variance_encoded/flatten') -detectionOut.input.append('SecondStageBoxPredictor/Reshape_1/Reshape') -detectionOut.input.append('detection_out/slice/reshape') - -text_format.Merge('i: %d' % args.num_classes, detectionOut.attr['num_classes']) -text_format.Merge('b: false', detectionOut.attr['share_location']) -text_format.Merge('i: %d' % (args.num_classes + 1), detectionOut.attr['background_label_id']) -text_format.Merge('f: 0.6', detectionOut.attr['nms_threshold']) -text_format.Merge('s: "CENTER_SIZE"', detectionOut.attr['code_type']) -text_format.Merge('i: 100', detectionOut.attr['keep_top_k']) -text_format.Merge('b: true', detectionOut.attr['clip']) -text_format.Merge('b: true', detectionOut.attr['variance_encoded_in_target']) -graph_def.node.extend([detectionOut]) - -tf.train.write_graph(graph_def, "", args.output, as_text=True) + +def createFasterRCNNGraph(modelPath, configPath, outputPath): + scopesToKeep = ('FirstStageFeatureExtractor', 'Conv', + 'FirstStageBoxPredictor/BoxEncodingPredictor', + 'FirstStageBoxPredictor/ClassPredictor', + 'CropAndResize', + 'MaxPool2D', + 'SecondStageFeatureExtractor', + 'SecondStageBoxPredictor', + 'Preprocessor/sub', + 'Preprocessor/mul', + 'image_tensor') + + scopesToIgnore = ('FirstStageFeatureExtractor/Assert', + 'FirstStageFeatureExtractor/Shape', + 'FirstStageFeatureExtractor/strided_slice', + 'FirstStageFeatureExtractor/GreaterEqual', + 'FirstStageFeatureExtractor/LogicalAnd') + + # Load a config file. + config = readTextMessage(configPath) + config = config['model'][0]['faster_rcnn'][0] + num_classes = int(config['num_classes'][0]) + + grid_anchor_generator = config['first_stage_anchor_generator'][0]['grid_anchor_generator'][0] + scales = [float(s) for s in grid_anchor_generator['scales']] + aspect_ratios = [float(ar) for ar in grid_anchor_generator['aspect_ratios']] + width_stride = float(grid_anchor_generator['width_stride'][0]) + height_stride = float(grid_anchor_generator['height_stride'][0]) + features_stride = float(config['feature_extractor'][0]['first_stage_features_stride'][0]) + + print('Number of classes: %d' % num_classes) + print('Scales: %s' % str(scales)) + print('Aspect ratios: %s' % str(aspect_ratios)) + print('Width stride: %f' % width_stride) + print('Height stride: %f' % height_stride) + print('Features stride: %f' % features_stride) + + # Read the graph. + cv.dnn.writeTextGraph(modelPath, outputPath) + graph_def = parseTextGraph(outputPath) + + removeIdentity(graph_def) + + def to_remove(name, op): + return name.startswith(scopesToIgnore) or not name.startswith(scopesToKeep) + + removeUnusedNodesAndAttrs(to_remove, graph_def) + + + # Connect input node to the first layer + assert(graph_def.node[0].op == 'Placeholder') + graph_def.node[1].input.insert(0, graph_def.node[0].name) + + # Temporarily remove top nodes. + topNodes = [] + while True: + node = graph_def.node.pop() + topNodes.append(node) + if node.op == 'CropAndResize': + break + + addReshape('FirstStageBoxPredictor/ClassPredictor/BiasAdd', + 'FirstStageBoxPredictor/ClassPredictor/reshape_1', [0, -1, 2], graph_def) + + addSoftMax('FirstStageBoxPredictor/ClassPredictor/reshape_1', + 'FirstStageBoxPredictor/ClassPredictor/softmax', graph_def) # Compare with Reshape_4 + + addFlatten('FirstStageBoxPredictor/ClassPredictor/softmax', + 'FirstStageBoxPredictor/ClassPredictor/softmax/flatten', graph_def) + + # Compare with FirstStageBoxPredictor/BoxEncodingPredictor/BiasAdd + addFlatten('FirstStageBoxPredictor/BoxEncodingPredictor/BiasAdd', + 'FirstStageBoxPredictor/BoxEncodingPredictor/flatten', graph_def) + + proposals = NodeDef() + proposals.name = 'proposals' # Compare with ClipToWindow/Gather/Gather (NOTE: normalized) + proposals.op = 'PriorBox' + proposals.input.append('FirstStageBoxPredictor/BoxEncodingPredictor/BiasAdd') + proposals.input.append(graph_def.node[0].name) # image_tensor + + proposals.addAttr('flip', False) + proposals.addAttr('clip', True) + proposals.addAttr('step', features_stride) + proposals.addAttr('offset', 0.0) + proposals.addAttr('variance', [0.1, 0.1, 0.2, 0.2]) + + widths = [] + heights = [] + for a in aspect_ratios: + for s in scales: + ar = np.sqrt(a) + heights.append((height_stride**2) * s / ar) + widths.append((width_stride**2) * s * ar) + + proposals.addAttr('width', widths) + proposals.addAttr('height', heights) + + graph_def.node.extend([proposals]) + + # Compare with Reshape_5 + detectionOut = NodeDef() + detectionOut.name = 'detection_out' + detectionOut.op = 'DetectionOutput' + + detectionOut.input.append('FirstStageBoxPredictor/BoxEncodingPredictor/flatten') + detectionOut.input.append('FirstStageBoxPredictor/ClassPredictor/softmax/flatten') + detectionOut.input.append('proposals') + + detectionOut.addAttr('num_classes', 2) + detectionOut.addAttr('share_location', True) + detectionOut.addAttr('background_label_id', 0) + detectionOut.addAttr('nms_threshold', 0.7) + detectionOut.addAttr('top_k', 6000) + detectionOut.addAttr('code_type', "CENTER_SIZE") + detectionOut.addAttr('keep_top_k', 100) + detectionOut.addAttr('clip', False) + + graph_def.node.extend([detectionOut]) + + addConstNode('clip_by_value/lower', [0.0], graph_def) + addConstNode('clip_by_value/upper', [1.0], graph_def) + + clipByValueNode = NodeDef() + clipByValueNode.name = 'detection_out/clip_by_value' + clipByValueNode.op = 'ClipByValue' + clipByValueNode.input.append('detection_out') + clipByValueNode.input.append('clip_by_value/lower') + clipByValueNode.input.append('clip_by_value/upper') + graph_def.node.extend([clipByValueNode]) + + # Save as text. + for node in reversed(topNodes): + graph_def.node.extend([node]) + + addSoftMax('SecondStageBoxPredictor/Reshape_1', 'SecondStageBoxPredictor/Reshape_1/softmax', graph_def) + + addSlice('SecondStageBoxPredictor/Reshape_1/softmax', + 'SecondStageBoxPredictor/Reshape_1/slice', + [0, 0, 1], [-1, -1, -1], graph_def) + + addReshape('SecondStageBoxPredictor/Reshape_1/slice', + 'SecondStageBoxPredictor/Reshape_1/Reshape', [1, -1], graph_def) + + # Replace Flatten subgraph onto a single node. + for i in reversed(range(len(graph_def.node))): + if graph_def.node[i].op == 'CropAndResize': + graph_def.node[i].input.insert(1, 'detection_out/clip_by_value') + + if graph_def.node[i].name == 'SecondStageBoxPredictor/Reshape': + addConstNode('SecondStageBoxPredictor/Reshape/shape2', [1, -1, 4], graph_def) + + graph_def.node[i].input.pop() + graph_def.node[i].input.append('SecondStageBoxPredictor/Reshape/shape2') + + if graph_def.node[i].name in ['SecondStageBoxPredictor/Flatten/flatten/Shape', + 'SecondStageBoxPredictor/Flatten/flatten/strided_slice', + 'SecondStageBoxPredictor/Flatten/flatten/Reshape/shape']: + del graph_def.node[i] + + for node in graph_def.node: + if node.name == 'SecondStageBoxPredictor/Flatten/flatten/Reshape': + node.op = 'Flatten' + node.input.pop() + + if node.name in ['FirstStageBoxPredictor/BoxEncodingPredictor/Conv2D', + 'SecondStageBoxPredictor/BoxEncodingPredictor/MatMul']: + node.addAttr('loc_pred_transposed', True) + + ################################################################################ + ### Postprocessing + ################################################################################ + addSlice('detection_out/clip_by_value', 'detection_out/slice', [0, 0, 0, 3], [-1, -1, -1, 4], graph_def) + + variance = NodeDef() + variance.name = 'proposals/variance' + variance.op = 'Const' + variance.addAttr('value', [0.1, 0.1, 0.2, 0.2]) + graph_def.node.extend([variance]) + + varianceEncoder = NodeDef() + varianceEncoder.name = 'variance_encoded' + varianceEncoder.op = 'Mul' + varianceEncoder.input.append('SecondStageBoxPredictor/Reshape') + varianceEncoder.input.append(variance.name) + varianceEncoder.addAttr('axis', 2) + graph_def.node.extend([varianceEncoder]) + + addReshape('detection_out/slice', 'detection_out/slice/reshape', [1, 1, -1], graph_def) + addFlatten('variance_encoded', 'variance_encoded/flatten', graph_def) + + detectionOut = NodeDef() + detectionOut.name = 'detection_out_final' + detectionOut.op = 'DetectionOutput' + + detectionOut.input.append('variance_encoded/flatten') + detectionOut.input.append('SecondStageBoxPredictor/Reshape_1/Reshape') + detectionOut.input.append('detection_out/slice/reshape') + + detectionOut.addAttr('num_classes', num_classes) + detectionOut.addAttr('share_location', False) + detectionOut.addAttr('background_label_id', num_classes + 1) + detectionOut.addAttr('nms_threshold', 0.6) + detectionOut.addAttr('code_type', "CENTER_SIZE") + detectionOut.addAttr('keep_top_k', 100) + detectionOut.addAttr('clip', True) + detectionOut.addAttr('variance_encoded_in_target', True) + graph_def.node.extend([detectionOut]) + + # Save as text. + graph_def.save(outputPath) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Run this script to get a text graph of ' + 'Faster-RCNN model from TensorFlow Object Detection API. ' + 'Then pass it with .pb file to cv::dnn::readNetFromTensorflow function.') + parser.add_argument('--input', required=True, help='Path to frozen TensorFlow graph.') + parser.add_argument('--output', required=True, help='Path to output text graph.') + parser.add_argument('--config', required=True, help='Path to a *.config file is used for training.') + args = parser.parse_args() + + createFasterRCNNGraph(args.input, args.config, args.output) diff --git a/samples/dnn/tf_text_graph_mask_rcnn.py b/samples/dnn/tf_text_graph_mask_rcnn.py index 4c6997f9308c..b80a0fc4dfcc 100644 --- a/samples/dnn/tf_text_graph_mask_rcnn.py +++ b/samples/dnn/tf_text_graph_mask_rcnn.py @@ -1,11 +1,6 @@ import argparse import numpy as np -import tensorflow as tf - -from tensorflow.core.framework.node_def_pb2 import NodeDef -from tensorflow.tools.graph_transforms import TransformGraph -from google.protobuf import text_format - +import cv2 as cv from tf_text_graph_common import * parser = argparse.ArgumentParser(description='Run this script to get a text graph of ' @@ -13,13 +8,7 @@ 'Then pass it with .pb file to cv::dnn::readNetFromTensorflow function.') parser.add_argument('--input', required=True, help='Path to frozen TensorFlow graph.') parser.add_argument('--output', required=True, help='Path to output text graph.') -parser.add_argument('--num_classes', default=90, type=int, help='Number of trained classes.') -parser.add_argument('--scales', default=[0.25, 0.5, 1.0, 2.0], type=float, nargs='+', - help='Hyper-parameter of grid_anchor_generator from a config file.') -parser.add_argument('--aspect_ratios', default=[0.5, 1.0, 2.0], type=float, nargs='+', - help='Hyper-parameter of grid_anchor_generator from a config file.') -parser.add_argument('--features_stride', default=16, type=float, nargs='+', - help='Hyper-parameter from a config file.') +parser.add_argument('--config', required=True, help='Path to a *.config file is used for training.') args = parser.parse_args() scopesToKeep = ('FirstStageFeatureExtractor', 'Conv', @@ -39,11 +28,28 @@ 'FirstStageFeatureExtractor/GreaterEqual', 'FirstStageFeatureExtractor/LogicalAnd') +# Load a config file. +config = readTextMessage(args.config) +config = config['model'][0]['faster_rcnn'][0] +num_classes = int(config['num_classes'][0]) + +grid_anchor_generator = config['first_stage_anchor_generator'][0]['grid_anchor_generator'][0] +scales = [float(s) for s in grid_anchor_generator['scales']] +aspect_ratios = [float(ar) for ar in grid_anchor_generator['aspect_ratios']] +width_stride = float(grid_anchor_generator['width_stride'][0]) +height_stride = float(grid_anchor_generator['height_stride'][0]) +features_stride = float(config['feature_extractor'][0]['first_stage_features_stride'][0]) + +print('Number of classes: %d' % num_classes) +print('Scales: %s' % str(scales)) +print('Aspect ratios: %s' % str(aspect_ratios)) +print('Width stride: %f' % width_stride) +print('Height stride: %f' % height_stride) +print('Features stride: %f' % features_stride) # Read the graph. -with tf.gfile.FastGFile(args.input, 'rb') as f: - graph_def = tf.GraphDef() - graph_def.ParseFromString(f.read()) +cv.dnn.writeTextGraph(args.input, args.output) +graph_def = parseTextGraph(args.output) removeIdentity(graph_def) @@ -87,22 +93,22 @@ def to_remove(name, op): proposals.input.append('FirstStageBoxPredictor/BoxEncodingPredictor/BiasAdd') proposals.input.append(graph_def.node[0].name) # image_tensor -text_format.Merge('b: false', proposals.attr["flip"]) -text_format.Merge('b: true', proposals.attr["clip"]) -text_format.Merge('f: %f' % args.features_stride, proposals.attr["step"]) -text_format.Merge('f: 0.0', proposals.attr["offset"]) -text_format.Merge(tensorMsg([0.1, 0.1, 0.2, 0.2]), proposals.attr["variance"]) +proposals.addAttr('flip', False) +proposals.addAttr('clip', True) +proposals.addAttr('step', features_stride) +proposals.addAttr('offset', 0.0) +proposals.addAttr('variance', [0.1, 0.1, 0.2, 0.2]) widths = [] heights = [] -for a in args.aspect_ratios: - for s in args.scales: +for a in aspect_ratios: + for s in scales: ar = np.sqrt(a) - heights.append((args.features_stride**2) * s / ar) - widths.append((args.features_stride**2) * s * ar) + heights.append((features_stride**2) * s / ar) + widths.append((features_stride**2) * s * ar) -text_format.Merge(tensorMsg(widths), proposals.attr["width"]) -text_format.Merge(tensorMsg(heights), proposals.attr["height"]) +proposals.addAttr('width', widths) +proposals.addAttr('height', heights) graph_def.node.extend([proposals]) @@ -115,14 +121,14 @@ def to_remove(name, op): detectionOut.input.append('FirstStageBoxPredictor/ClassPredictor/softmax/flatten') detectionOut.input.append('proposals') -text_format.Merge('i: 2', detectionOut.attr['num_classes']) -text_format.Merge('b: true', detectionOut.attr['share_location']) -text_format.Merge('i: 0', detectionOut.attr['background_label_id']) -text_format.Merge('f: 0.7', detectionOut.attr['nms_threshold']) -text_format.Merge('i: 6000', detectionOut.attr['top_k']) -text_format.Merge('s: "CENTER_SIZE"', detectionOut.attr['code_type']) -text_format.Merge('i: 100', detectionOut.attr['keep_top_k']) -text_format.Merge('b: true', detectionOut.attr['clip']) +detectionOut.addAttr('num_classes', 2) +detectionOut.addAttr('share_location', True) +detectionOut.addAttr('background_label_id', 0) +detectionOut.addAttr('nms_threshold', 0.7) +detectionOut.addAttr('top_k', 6000) +detectionOut.addAttr('code_type', "CENTER_SIZE") +detectionOut.addAttr('keep_top_k', 100) +detectionOut.addAttr('clip', True) graph_def.node.extend([detectionOut]) @@ -171,7 +177,7 @@ def to_remove(name, op): if node.name in ['FirstStageBoxPredictor/BoxEncodingPredictor/Conv2D', 'SecondStageBoxPredictor/BoxEncodingPredictor/MatMul']: - text_format.Merge('b: true', node.attr["loc_pred_transposed"]) + node.addAttr('loc_pred_transposed', True) ################################################################################ ### Postprocessing @@ -181,7 +187,7 @@ def to_remove(name, op): variance = NodeDef() variance.name = 'proposals/variance' variance.op = 'Const' -text_format.Merge(tensorMsg([0.1, 0.1, 0.2, 0.2]), variance.attr["value"]) +variance.addAttr('value', [0.1, 0.1, 0.2, 0.2]) graph_def.node.extend([variance]) varianceEncoder = NodeDef() @@ -189,7 +195,7 @@ def to_remove(name, op): varianceEncoder.op = 'Mul' varianceEncoder.input.append('SecondStageBoxPredictor/Reshape') varianceEncoder.input.append(variance.name) -text_format.Merge('i: 2', varianceEncoder.attr["axis"]) +varianceEncoder.addAttr('axis', 2) graph_def.node.extend([varianceEncoder]) addReshape('detection_out/slice', 'detection_out/slice/reshape', [1, 1, -1], graph_def) @@ -203,16 +209,16 @@ def to_remove(name, op): detectionOut.input.append('SecondStageBoxPredictor/Reshape_1/Reshape') detectionOut.input.append('detection_out/slice/reshape') -text_format.Merge('i: %d' % args.num_classes, detectionOut.attr['num_classes']) -text_format.Merge('b: false', detectionOut.attr['share_location']) -text_format.Merge('i: %d' % (args.num_classes + 1), detectionOut.attr['background_label_id']) -text_format.Merge('f: 0.6', detectionOut.attr['nms_threshold']) -text_format.Merge('s: "CENTER_SIZE"', detectionOut.attr['code_type']) -text_format.Merge('i: 100', detectionOut.attr['keep_top_k']) -text_format.Merge('b: true', detectionOut.attr['clip']) -text_format.Merge('b: true', detectionOut.attr['variance_encoded_in_target']) -text_format.Merge('f: 0.3', detectionOut.attr['confidence_threshold']) -text_format.Merge('b: false', detectionOut.attr['group_by_classes']) +detectionOut.addAttr('num_classes', num_classes) +detectionOut.addAttr('share_location', False) +detectionOut.addAttr('background_label_id', num_classes + 1) +detectionOut.addAttr('nms_threshold', 0.6) +detectionOut.addAttr('code_type', "CENTER_SIZE") +detectionOut.addAttr('keep_top_k',100) +detectionOut.addAttr('clip', True) +detectionOut.addAttr('variance_encoded_in_target', True) +detectionOut.addAttr('confidence_threshold', 0.3) +detectionOut.addAttr('group_by_classes', False) graph_def.node.extend([detectionOut]) for node in reversed(topNodes): @@ -227,4 +233,5 @@ def to_remove(name, op): graph_def.node[-1].op = 'Sigmoid' graph_def.node[-1].input.pop() -tf.train.write_graph(graph_def, "", args.output, as_text=True) +# Save as text. +graph_def.save(args.output) diff --git a/samples/dnn/tf_text_graph_ssd.py b/samples/dnn/tf_text_graph_ssd.py index 0d4a41f34a20..eb4b33042cb9 100644 --- a/samples/dnn/tf_text_graph_ssd.py +++ b/samples/dnn/tf_text_graph_ssd.py @@ -9,252 +9,269 @@ # deep learning network trained in TensorFlow Object Detection API. # Then you can import it with a binary frozen graph (.pb) using readNetFromTensorflow() function. # See details and examples on the following wiki page: https://github.com/opencv/opencv/wiki/TensorFlow-Object-Detection-API -import tensorflow as tf import argparse from math import sqrt -from tensorflow.core.framework.node_def_pb2 import NodeDef -from tensorflow.tools.graph_transforms import TransformGraph -from google.protobuf import text_format +import cv2 as cv from tf_text_graph_common import * -parser = argparse.ArgumentParser(description='Run this script to get a text graph of ' - 'SSD model from TensorFlow Object Detection API. ' - 'Then pass it with .pb file to cv::dnn::readNetFromTensorflow function.') -parser.add_argument('--input', required=True, help='Path to frozen TensorFlow graph.') -parser.add_argument('--output', required=True, help='Path to output text graph.') -parser.add_argument('--num_classes', default=90, type=int, help='Number of trained classes.') -parser.add_argument('--min_scale', default=0.2, type=float, help='Hyper-parameter of ssd_anchor_generator from config file.') -parser.add_argument('--max_scale', default=0.95, type=float, help='Hyper-parameter of ssd_anchor_generator from config file.') -parser.add_argument('--num_layers', default=6, type=int, help='Hyper-parameter of ssd_anchor_generator from config file.') -parser.add_argument('--aspect_ratios', default=[1.0, 2.0, 0.5, 3.0, 0.333], type=float, nargs='+', - help='Hyper-parameter of ssd_anchor_generator from config file.') -parser.add_argument('--image_width', default=300, type=int, help='Training images width.') -parser.add_argument('--image_height', default=300, type=int, help='Training images height.') -parser.add_argument('--not_reduce_boxes_in_lowest_layer', default=False, action='store_true', - help='A boolean to indicate whether the fixed 3 boxes per ' - 'location is used in the lowest achors generation layer.') -parser.add_argument('--box_predictor', default='convolutional', type=str, - choices=['convolutional', 'weight_shared_convolutional']) -args = parser.parse_args() - -# Nodes that should be kept. -keepOps = ['Conv2D', 'BiasAdd', 'Add', 'Relu6', 'Placeholder', 'FusedBatchNorm', - 'DepthwiseConv2dNative', 'ConcatV2', 'Mul', 'MaxPool', 'AvgPool', 'Identity'] - -# Node with which prefixes should be removed -prefixesToRemove = ('MultipleGridAnchorGenerator/', 'Postprocessor/', 'Preprocessor/') - -# Read the graph. -with tf.gfile.FastGFile(args.input, 'rb') as f: - graph_def = tf.GraphDef() - graph_def.ParseFromString(f.read()) - -inpNames = ['image_tensor'] -outNames = ['num_detections', 'detection_scores', 'detection_boxes', 'detection_classes'] -graph_def = TransformGraph(graph_def, inpNames, outNames, ['sort_by_execution_order']) - -def getUnconnectedNodes(): - unconnected = [] - for node in graph_def.node: - unconnected.append(node.name) - for inp in node.input: - if inp in unconnected: - unconnected.remove(inp) - return unconnected - - -# Detect unfused batch normalization nodes and fuse them. -def fuse_batch_normalization(): - # Add_0 <-- moving_variance, add_y - # Rsqrt <-- Add_0 - # Mul_0 <-- Rsqrt, gamma - # Mul_1 <-- input, Mul_0 - # Mul_2 <-- moving_mean, Mul_0 - # Sub_0 <-- beta, Mul_2 - # Add_1 <-- Mul_1, Sub_0 - nodesMap = {node.name: node for node in graph_def.node} - subgraph = ['Add', - ['Mul', 'input', ['Mul', ['Rsqrt', ['Add', 'moving_variance', 'add_y']], 'gamma']], - ['Sub', 'beta', ['Mul', 'moving_mean', 'Mul_0']]] - def checkSubgraph(node, targetNode, inputs, fusedNodes): - op = targetNode[0] - if node.op == op and (len(node.input) >= len(targetNode) - 1): - fusedNodes.append(node) - for i, inpOp in enumerate(targetNode[1:]): - if isinstance(inpOp, list): - if not node.input[i] in nodesMap or \ - not checkSubgraph(nodesMap[node.input[i]], inpOp, inputs, fusedNodes): - return False +def createSSDGraph(modelPath, configPath, outputPath): + # Nodes that should be kept. + keepOps = ['Conv2D', 'BiasAdd', 'Add', 'Relu6', 'Placeholder', 'FusedBatchNorm', + 'DepthwiseConv2dNative', 'ConcatV2', 'Mul', 'MaxPool', 'AvgPool', 'Identity', + 'Sub'] + + # Node with which prefixes should be removed + prefixesToRemove = ('MultipleGridAnchorGenerator/', 'Postprocessor/', 'Preprocessor/map') + + # Load a config file. + config = readTextMessage(configPath) + config = config['model'][0]['ssd'][0] + num_classes = int(config['num_classes'][0]) + + ssd_anchor_generator = config['anchor_generator'][0]['ssd_anchor_generator'][0] + min_scale = float(ssd_anchor_generator['min_scale'][0]) + max_scale = float(ssd_anchor_generator['max_scale'][0]) + num_layers = int(ssd_anchor_generator['num_layers'][0]) + aspect_ratios = [float(ar) for ar in ssd_anchor_generator['aspect_ratios']] + reduce_boxes_in_lowest_layer = True + if 'reduce_boxes_in_lowest_layer' in ssd_anchor_generator: + reduce_boxes_in_lowest_layer = ssd_anchor_generator['reduce_boxes_in_lowest_layer'][0] == 'true' + + fixed_shape_resizer = config['image_resizer'][0]['fixed_shape_resizer'][0] + image_width = int(fixed_shape_resizer['width'][0]) + image_height = int(fixed_shape_resizer['height'][0]) + + box_predictor = 'convolutional' if 'convolutional_box_predictor' in config['box_predictor'][0] else 'weight_shared_convolutional' + + print('Number of classes: %d' % num_classes) + print('Number of layers: %d' % num_layers) + print('Scale: [%f-%f]' % (min_scale, max_scale)) + print('Aspect ratios: %s' % str(aspect_ratios)) + print('Reduce boxes in the lowest layer: %s' % str(reduce_boxes_in_lowest_layer)) + print('box predictor: %s' % box_predictor) + print('Input image size: %dx%d' % (image_width, image_height)) + + # Read the graph. + cv.dnn.writeTextGraph(modelPath, outputPath) + graph_def = parseTextGraph(outputPath) + + inpNames = ['image_tensor'] + outNames = ['num_detections', 'detection_scores', 'detection_boxes', 'detection_classes'] + + def getUnconnectedNodes(): + unconnected = [] + for node in graph_def.node: + unconnected.append(node.name) + for inp in node.input: + if inp in unconnected: + unconnected.remove(inp) + return unconnected + + + # Detect unfused batch normalization nodes and fuse them. + def fuse_batch_normalization(): + # Add_0 <-- moving_variance, add_y + # Rsqrt <-- Add_0 + # Mul_0 <-- Rsqrt, gamma + # Mul_1 <-- input, Mul_0 + # Mul_2 <-- moving_mean, Mul_0 + # Sub_0 <-- beta, Mul_2 + # Add_1 <-- Mul_1, Sub_0 + nodesMap = {node.name: node for node in graph_def.node} + subgraph = ['Add', + ['Mul', 'input', ['Mul', ['Rsqrt', ['Add', 'moving_variance', 'add_y']], 'gamma']], + ['Sub', 'beta', ['Mul', 'moving_mean', 'Mul_0']]] + def checkSubgraph(node, targetNode, inputs, fusedNodes): + op = targetNode[0] + if node.op == op and (len(node.input) >= len(targetNode) - 1): + fusedNodes.append(node) + for i, inpOp in enumerate(targetNode[1:]): + if isinstance(inpOp, list): + if not node.input[i] in nodesMap or \ + not checkSubgraph(nodesMap[node.input[i]], inpOp, inputs, fusedNodes): + return False + else: + inputs[inpOp] = node.input[i] + + return True + else: + return False + + nodesToRemove = [] + for node in graph_def.node: + inputs = {} + fusedNodes = [] + if checkSubgraph(node, subgraph, inputs, fusedNodes): + name = node.name + node.Clear() + node.name = name + node.op = 'FusedBatchNorm' + node.input.append(inputs['input']) + node.input.append(inputs['gamma']) + node.input.append(inputs['beta']) + node.input.append(inputs['moving_mean']) + node.input.append(inputs['moving_variance']) + node.addAttr('epsilon', 0.001) + nodesToRemove += fusedNodes[1:] + for node in nodesToRemove: + graph_def.node.remove(node) + + fuse_batch_normalization() + + removeIdentity(graph_def) + + def to_remove(name, op): + return (not op in keepOps) or name.startswith(prefixesToRemove) + + removeUnusedNodesAndAttrs(to_remove, graph_def) + + + # Connect input node to the first layer + assert(graph_def.node[0].op == 'Placeholder') + # assert(graph_def.node[1].op == 'Conv2D') + weights = graph_def.node[1].input[0] + for i in range(len(graph_def.node[1].input)): + graph_def.node[1].input.pop() + graph_def.node[1].input.append(graph_def.node[0].name) + graph_def.node[1].input.append(weights) + + # Create SSD postprocessing head ############################################### + + # Concatenate predictions of classes, predictions of bounding boxes and proposals. + def addConcatNode(name, inputs, axisNodeName): + concat = NodeDef() + concat.name = name + concat.op = 'ConcatV2' + for inp in inputs: + concat.input.append(inp) + concat.input.append(axisNodeName) + graph_def.node.extend([concat]) + + addConstNode('concat/axis_flatten', [-1], graph_def) + addConstNode('PriorBox/concat/axis', [-2], graph_def) + + for label in ['ClassPredictor', 'BoxEncodingPredictor' if box_predictor is 'convolutional' else 'BoxPredictor']: + concatInputs = [] + for i in range(num_layers): + # Flatten predictions + flatten = NodeDef() + if box_predictor is 'convolutional': + inpName = 'BoxPredictor_%d/%s/BiasAdd' % (i, label) + else: + if i == 0: + inpName = 'WeightSharedConvolutionalBoxPredictor/%s/BiasAdd' % label else: - inputs[inpOp] = node.input[i] + inpName = 'WeightSharedConvolutionalBoxPredictor_%d/%s/BiasAdd' % (i, label) + flatten.input.append(inpName) + flatten.name = inpName + '/Flatten' + flatten.op = 'Flatten' - return True - else: - return False + concatInputs.append(flatten.name) + graph_def.node.extend([flatten]) + addConcatNode('%s/concat' % label, concatInputs, 'concat/axis_flatten') - nodesToRemove = [] + idx = 0 for node in graph_def.node: - inputs = {} - fusedNodes = [] - if checkSubgraph(node, subgraph, inputs, fusedNodes): - name = node.name - node.Clear() - node.name = name - node.op = 'FusedBatchNorm' - node.input.append(inputs['input']) - node.input.append(inputs['gamma']) - node.input.append(inputs['beta']) - node.input.append(inputs['moving_mean']) - node.input.append(inputs['moving_variance']) - text_format.Merge('f: 0.001', node.attr["epsilon"]) - nodesToRemove += fusedNodes[1:] - for node in nodesToRemove: - graph_def.node.remove(node) - -fuse_batch_normalization() - -removeIdentity(graph_def) - -def to_remove(name, op): - return (not op in keepOps) or name.startswith(prefixesToRemove) - -removeUnusedNodesAndAttrs(to_remove, graph_def) - - -# Connect input node to the first layer -assert(graph_def.node[0].op == 'Placeholder') -# assert(graph_def.node[1].op == 'Conv2D') -weights = graph_def.node[1].input[0] -for i in range(len(graph_def.node[1].input)): - graph_def.node[1].input.pop() -graph_def.node[1].input.append(graph_def.node[0].name) -graph_def.node[1].input.append(weights) - -# Create SSD postprocessing head ############################################### - -# Concatenate predictions of classes, predictions of bounding boxes and proposals. -def addConcatNode(name, inputs, axisNodeName): - concat = NodeDef() - concat.name = name - concat.op = 'ConcatV2' - for inp in inputs: - concat.input.append(inp) - concat.input.append(axisNodeName) - graph_def.node.extend([concat]) - -addConstNode('concat/axis_flatten', [-1], graph_def) -addConstNode('PriorBox/concat/axis', [-2], graph_def) - -for label in ['ClassPredictor', 'BoxEncodingPredictor' if args.box_predictor is 'convolutional' else 'BoxPredictor']: - concatInputs = [] - for i in range(args.num_layers): - # Flatten predictions - flatten = NodeDef() - if args.box_predictor is 'convolutional': - inpName = 'BoxPredictor_%d/%s/BiasAdd' % (i, label) + if node.name == ('BoxPredictor_%d/BoxEncodingPredictor/Conv2D' % idx) or \ + node.name == ('WeightSharedConvolutionalBoxPredictor_%d/BoxPredictor/Conv2D' % idx) or \ + node.name == 'WeightSharedConvolutionalBoxPredictor/BoxPredictor/Conv2D': + node.addAttr('loc_pred_transposed', True) + idx += 1 + assert(idx == num_layers) + + # Add layers that generate anchors (bounding boxes proposals). + scales = [min_scale + (max_scale - min_scale) * i / (num_layers - 1) + for i in range(num_layers)] + [1.0] + + priorBoxes = [] + for i in range(num_layers): + priorBox = NodeDef() + priorBox.name = 'PriorBox_%d' % i + priorBox.op = 'PriorBox' + if box_predictor is 'convolutional': + priorBox.input.append('BoxPredictor_%d/BoxEncodingPredictor/BiasAdd' % i) else: if i == 0: - inpName = 'WeightSharedConvolutionalBoxPredictor/%s/BiasAdd' % label + priorBox.input.append('WeightSharedConvolutionalBoxPredictor/BoxPredictor/Conv2D') else: - inpName = 'WeightSharedConvolutionalBoxPredictor_%d/%s/BiasAdd' % (i, label) - flatten.input.append(inpName) - flatten.name = inpName + '/Flatten' - flatten.op = 'Flatten' - - concatInputs.append(flatten.name) - graph_def.node.extend([flatten]) - addConcatNode('%s/concat' % label, concatInputs, 'concat/axis_flatten') - -idx = 0 -for node in graph_def.node: - if node.name == ('BoxPredictor_%d/BoxEncodingPredictor/Conv2D' % idx) or \ - node.name == ('WeightSharedConvolutionalBoxPredictor_%d/BoxPredictor/Conv2D' % idx) or \ - node.name == 'WeightSharedConvolutionalBoxPredictor/BoxPredictor/Conv2D': - text_format.Merge('b: true', node.attr["loc_pred_transposed"]) - idx += 1 -assert(idx == args.num_layers) - -# Add layers that generate anchors (bounding boxes proposals). -scales = [args.min_scale + (args.max_scale - args.min_scale) * i / (args.num_layers - 1) - for i in range(args.num_layers)] + [1.0] - -priorBoxes = [] -for i in range(args.num_layers): - priorBox = NodeDef() - priorBox.name = 'PriorBox_%d' % i - priorBox.op = 'PriorBox' - if args.box_predictor is 'convolutional': - priorBox.input.append('BoxPredictor_%d/BoxEncodingPredictor/BiasAdd' % i) - else: - if i == 0: - priorBox.input.append('WeightSharedConvolutionalBoxPredictor/BoxPredictor/Conv2D') - else: - priorBox.input.append('WeightSharedConvolutionalBoxPredictor_%d/BoxPredictor/BiasAdd' % i) - priorBox.input.append(graph_def.node[0].name) # image_tensor + priorBox.input.append('WeightSharedConvolutionalBoxPredictor_%d/BoxPredictor/BiasAdd' % i) + priorBox.input.append(graph_def.node[0].name) # image_tensor - text_format.Merge('b: false', priorBox.attr["flip"]) - text_format.Merge('b: false', priorBox.attr["clip"]) + priorBox.addAttr('flip', False) + priorBox.addAttr('clip', False) - if i == 0 and not args.not_reduce_boxes_in_lowest_layer: - widths = [0.1, args.min_scale * sqrt(2.0), args.min_scale * sqrt(0.5)] - heights = [0.1, args.min_scale / sqrt(2.0), args.min_scale / sqrt(0.5)] + if i == 0 and reduce_boxes_in_lowest_layer: + widths = [0.1, min_scale * sqrt(2.0), min_scale * sqrt(0.5)] + heights = [0.1, min_scale / sqrt(2.0), min_scale / sqrt(0.5)] + else: + widths = [scales[i] * sqrt(ar) for ar in aspect_ratios] + heights = [scales[i] / sqrt(ar) for ar in aspect_ratios] + + widths += [sqrt(scales[i] * scales[i + 1])] + heights += [sqrt(scales[i] * scales[i + 1])] + widths = [w * image_width for w in widths] + heights = [h * image_height for h in heights] + priorBox.addAttr('width', widths) + priorBox.addAttr('height', heights) + priorBox.addAttr('variance', [0.1, 0.1, 0.2, 0.2]) + + graph_def.node.extend([priorBox]) + priorBoxes.append(priorBox.name) + + addConcatNode('PriorBox/concat', priorBoxes, 'concat/axis_flatten') + + # Sigmoid for classes predictions and DetectionOutput layer + sigmoid = NodeDef() + sigmoid.name = 'ClassPredictor/concat/sigmoid' + sigmoid.op = 'Sigmoid' + sigmoid.input.append('ClassPredictor/concat') + graph_def.node.extend([sigmoid]) + + detectionOut = NodeDef() + detectionOut.name = 'detection_out' + detectionOut.op = 'DetectionOutput' + + if box_predictor == 'convolutional': + detectionOut.input.append('BoxEncodingPredictor/concat') else: - widths = [scales[i] * sqrt(ar) for ar in args.aspect_ratios] - heights = [scales[i] / sqrt(ar) for ar in args.aspect_ratios] - - widths += [sqrt(scales[i] * scales[i + 1])] - heights += [sqrt(scales[i] * scales[i + 1])] - widths = [w * args.image_width for w in widths] - heights = [h * args.image_height for h in heights] - text_format.Merge(tensorMsg(widths), priorBox.attr["width"]) - text_format.Merge(tensorMsg(heights), priorBox.attr["height"]) - text_format.Merge(tensorMsg([0.1, 0.1, 0.2, 0.2]), priorBox.attr["variance"]) - - graph_def.node.extend([priorBox]) - priorBoxes.append(priorBox.name) - -addConcatNode('PriorBox/concat', priorBoxes, 'concat/axis_flatten') - -# Sigmoid for classes predictions and DetectionOutput layer -sigmoid = NodeDef() -sigmoid.name = 'ClassPredictor/concat/sigmoid' -sigmoid.op = 'Sigmoid' -sigmoid.input.append('ClassPredictor/concat') -graph_def.node.extend([sigmoid]) - -detectionOut = NodeDef() -detectionOut.name = 'detection_out' -detectionOut.op = 'DetectionOutput' - -if args.box_predictor == 'convolutional': - detectionOut.input.append('BoxEncodingPredictor/concat') -else: - detectionOut.input.append('BoxPredictor/concat') -detectionOut.input.append(sigmoid.name) -detectionOut.input.append('PriorBox/concat') - -text_format.Merge('i: %d' % (args.num_classes + 1), detectionOut.attr['num_classes']) -text_format.Merge('b: true', detectionOut.attr['share_location']) -text_format.Merge('i: 0', detectionOut.attr['background_label_id']) -text_format.Merge('f: 0.6', detectionOut.attr['nms_threshold']) -text_format.Merge('i: 100', detectionOut.attr['top_k']) -text_format.Merge('s: "CENTER_SIZE"', detectionOut.attr['code_type']) -text_format.Merge('i: 100', detectionOut.attr['keep_top_k']) -text_format.Merge('f: 0.01', detectionOut.attr['confidence_threshold']) - -graph_def.node.extend([detectionOut]) - -while True: - unconnectedNodes = getUnconnectedNodes() - unconnectedNodes.remove(detectionOut.name) - if not unconnectedNodes: - break - - for name in unconnectedNodes: - for i in range(len(graph_def.node)): - if graph_def.node[i].name == name: - del graph_def.node[i] - break - -# Save as text. -tf.train.write_graph(graph_def, "", args.output, as_text=True) + detectionOut.input.append('BoxPredictor/concat') + detectionOut.input.append(sigmoid.name) + detectionOut.input.append('PriorBox/concat') + + detectionOut.addAttr('num_classes', num_classes + 1) + detectionOut.addAttr('share_location', True) + detectionOut.addAttr('background_label_id', 0) + detectionOut.addAttr('nms_threshold', 0.6) + detectionOut.addAttr('top_k', 100) + detectionOut.addAttr('code_type', "CENTER_SIZE") + detectionOut.addAttr('keep_top_k', 100) + detectionOut.addAttr('confidence_threshold', 0.01) + + graph_def.node.extend([detectionOut]) + + while True: + unconnectedNodes = getUnconnectedNodes() + unconnectedNodes.remove(detectionOut.name) + if not unconnectedNodes: + break + + for name in unconnectedNodes: + for i in range(len(graph_def.node)): + if graph_def.node[i].name == name: + del graph_def.node[i] + break + + # Save as text. + graph_def.save(outputPath) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Run this script to get a text graph of ' + 'SSD model from TensorFlow Object Detection API. ' + 'Then pass it with .pb file to cv::dnn::readNetFromTensorflow function.') + parser.add_argument('--input', required=True, help='Path to frozen TensorFlow graph.') + parser.add_argument('--output', required=True, help='Path to output text graph.') + parser.add_argument('--config', required=True, help='Path to a *.config file is used for training.') + args = parser.parse_args() + + createSSDGraph(args.input, args.config, args.output) diff --git a/samples/gpu/CMakeLists.txt b/samples/gpu/CMakeLists.txt index 0a3a2d0531e5..1c65145aca09 100644 --- a/samples/gpu/CMakeLists.txt +++ b/samples/gpu/CMakeLists.txt @@ -30,6 +30,9 @@ if(NOT BUILD_EXAMPLES OR NOT OCV_DEPENDENCIES_FOUND) endif() project(gpu_samples) +if(HAVE_CUDA OR CUDA_FOUND) + add_definitions(-DHAVE_CUDA=1) +endif() if(COMMAND ocv_warnings_disable) ocv_warnings_disable(CMAKE_CXX_FLAGS -Wsuggest-override -Winconsistent-missing-override) endif() diff --git a/samples/gpu/cascadeclassifier_nvidia_api.cpp b/samples/gpu/cascadeclassifier_nvidia_api.cpp index f3d58cae5a81..c932411eda8a 100644 --- a/samples/gpu/cascadeclassifier_nvidia_api.cpp +++ b/samples/gpu/cascadeclassifier_nvidia_api.cpp @@ -2,7 +2,6 @@ #pragma warning( disable : 4201 4408 4127 4100) #endif -#include "opencv2/cvconfig.h" #include #include #include diff --git a/samples/gpu/multi.cpp b/samples/gpu/multi.cpp index c3aac72d50c4..c3ef9b964143 100644 --- a/samples/gpu/multi.cpp +++ b/samples/gpu/multi.cpp @@ -7,29 +7,14 @@ #endif #include -#include "opencv2/cvconfig.h" #include "opencv2/core.hpp" #include "opencv2/cudaarithm.hpp" -#ifdef HAVE_TBB -# include "tbb/tbb.h" -# include "tbb/task.h" -# undef min -# undef max -#endif - -#if !defined(HAVE_CUDA) || !defined(HAVE_TBB) +#if !defined(HAVE_CUDA) int main() { -#if !defined(HAVE_CUDA) - std::cout << "CUDA support is required (CMake key 'WITH_CUDA' must be true).\n"; -#endif - -#if !defined(HAVE_TBB) - std::cout << "TBB support is required (CMake key 'WITH_TBB' must be true).\n"; -#endif - + std::cout << "CUDA support is required (OpenCV CMake parameter 'WITH_CUDA' must be true)." << std::endl; return 0; } @@ -39,7 +24,14 @@ using namespace std; using namespace cv; using namespace cv::cuda; -struct Worker { void operator()(int device_id) const; }; +struct Worker : public cv::ParallelLoopBody +{ + void operator()(const Range& r) const CV_OVERRIDE + { + for (int i = r.start; i < r.end; ++i) { this->operator()(i); } + } + void operator()(int device_id) const; +}; int main() { @@ -64,8 +56,8 @@ int main() } // Execute calculation in two threads using two GPUs - int devices[] = {0, 1}; - tbb::parallel_do(devices, devices + 2, Worker()); + cv::Range devices(0, 2); + cv::parallel_for_(devices, Worker(), devices.size()); return 0; } diff --git a/samples/gpu/opticalflow_nvidia_api.cpp b/samples/gpu/opticalflow_nvidia_api.cpp index a60a7a8b46f0..0d924ec85e7f 100644 --- a/samples/gpu/opticalflow_nvidia_api.cpp +++ b/samples/gpu/opticalflow_nvidia_api.cpp @@ -9,7 +9,6 @@ #include #include -#include "cvconfig.h" #include #include #include "opencv2/core/cuda.hpp" diff --git a/samples/opengl/opengl_interop.cpp b/samples/opengl/opengl_interop.cpp index 1d606f13fe1e..87f1f9593990 100644 --- a/samples/opengl/opengl_interop.cpp +++ b/samples/opengl/opengl_interop.cpp @@ -360,7 +360,7 @@ class GLWinApp : public WinApp if (m_demo_processing) { // blur texture image with OpenCV on CPU - cv::blur(m, m, cv::Size(15, 15), cv::Point(-7, -7)); + cv::blur(m, m, cv::Size(15, 15)); } if (do_buffer) @@ -385,7 +385,7 @@ class GLWinApp : public WinApp if (m_demo_processing) { // blur texture image with OpenCV on GPU with OpenCL - cv::blur(u, u, cv::Size(15, 15), cv::Point(-7, -7)); + cv::blur(u, u, cv::Size(15, 15)); } if (do_buffer) diff --git a/samples/va_intel/display.cpp.inc b/samples/va_intel/display.cpp.inc index 56e71d26e2f2..6fd3e0cbf0f0 100644 --- a/samples/va_intel/display.cpp.inc +++ b/samples/va_intel/display.cpp.inc @@ -7,8 +7,6 @@ #include #include -#include "cvconfig.h" - #include # include diff --git a/samples/va_intel/va_intel_interop.cpp b/samples/va_intel/va_intel_interop.cpp index 8fa2c54f6f84..770e9dbf4121 100644 --- a/samples/va_intel/va_intel_interop.cpp +++ b/samples/va_intel/va_intel_interop.cpp @@ -45,7 +45,6 @@ #include "opencv2/imgproc.hpp" #include "opencv2/highgui.hpp" #include "opencv2/core/va_intel.hpp" -#include "cvconfig.h" #define CHECK_VASTATUS(_status,_func) \ if (_status != VA_STATUS_SUCCESS) \ @@ -65,15 +64,9 @@ class CmdlineParser void usage() { fprintf(stderr, -#if defined(HAVE_VA_INTEL) "Usage: va_intel_interop [-f] infile outfile1 outfile2\n\n" "Interop ON/OFF version\n\n" "where: -f option indicates interop is off (fallback mode); interop is on by default\n" -#elif defined(HAVE_VA) - "Usage: va_intel_interop infile outfile1 outfile2\n\n" - "Interop OFF only version\n\n" - "where:\n" -#endif //HAVE_VA_INTEL / HAVE_VA " infile is to be existing, contains input image data (bmp, jpg, png, tiff, etc)\n" " outfile1 is to be created, contains original surface data (NV12)\n" " outfile2 is to be created, contains processed surface data (NV12)\n"); @@ -84,20 +77,14 @@ class CmdlineParser int n = 0; for (int i = 0; i < _fnNumFiles; ++i) m_files[i] = 0; -#if defined(HAVE_VA_INTEL) m_interop = true; -#elif defined(HAVE_VA) - m_interop = false; -#endif //HAVE_VA_INTEL / HAVE_VA for (int i = 1; i < m_argc; ++i) { const char *arg = m_argv[i]; if (arg[0] == '-') // option { -#if defined(HAVE_VA_INTEL) if (!strcmp(arg, "-f")) m_interop = false; -#endif //HAVE_VA_INTEL } else // parameter {