From 20b3756d376824a1a525fc6c7d78e0ab9c5296f6 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sat, 23 May 2020 11:15:47 +0200 Subject: [PATCH 1/2] Make sure we don't use C++14 accidentally. --- setup.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/setup.py b/setup.py index 6d16fe3fac6b..de8976cb70d2 100644 --- a/setup.py +++ b/setup.py @@ -181,6 +181,14 @@ def build_extensions(self): env = self.add_optimization_flags() for package in good_packages: package.do_custom_build(env) + # Make sure we don't accidentally use too modern C++ constructs, even + # though modern compilers default to enabling them. Enabling this for + # a single platform is enough; also only do this for C++-only + # extensions as clang refuses to compile C/ObjC with -std=c++11. + if sys.platform != "win32": + for ext in self.distribution.ext_modules[:]: + if not any(src.endswith((".c", ".m")) for src in ext.sources): + ext.extra_compile_args.append("-std=c++11") return super().build_extensions() def build_extension(self, ext): From 9644a9c710f534faf5193f17ac1a77aa70e914a4 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sat, 23 May 2020 11:09:09 +0200 Subject: [PATCH 2/2] Dedupe some C++ templates. --- src/_image_resample.h | 345 ++++++++++------------------------------- src/_image_wrapper.cpp | 89 ++++------- 2 files changed, 113 insertions(+), 321 deletions(-) diff --git a/src/_image_resample.h b/src/_image_resample.h index 99cedd9b2c93..10763fb01d37 100644 --- a/src/_image_resample.h +++ b/src/_image_resample.h @@ -500,240 +500,58 @@ typedef enum { } interpolation_e; -template -class type_mapping; +// T is rgba if and only if it has an T::r field. +template struct is_grayscale : std::true_type {}; +template struct is_grayscale : std::false_type {}; -template <> class type_mapping +template +struct type_mapping { - public: - typedef agg::rgba8 color_type; - typedef fixed_blender_rgba_plain blender_type; - typedef fixed_blender_rgba_pre pre_blender_type; - typedef agg::pixfmt_alpha_blend_rgba pixfmt_type; - typedef agg::pixfmt_alpha_blend_rgba pixfmt_pre_type; - - template - struct span_gen_affine_type - { - typedef agg::span_image_resample_rgba_affine type; - }; - - template - struct span_gen_filter_type - { - typedef agg::span_image_filter_rgba type; - }; - - template - struct span_gen_nn_type - { - typedef agg::span_image_filter_rgba_nn type; - }; -}; - - -template <> class type_mapping -{ - public: - typedef agg::rgba16 color_type; - typedef fixed_blender_rgba_plain blender_type; - typedef fixed_blender_rgba_pre pre_blender_type; - typedef agg::pixfmt_alpha_blend_rgba pixfmt_type; - typedef agg::pixfmt_alpha_blend_rgba pixfmt_pre_type; - - template - struct span_gen_affine_type - { - typedef agg::span_image_resample_rgba_affine type; - }; - - template - struct span_gen_filter_type - { - typedef agg::span_image_filter_rgba type; - }; - - template - struct span_gen_nn_type - { - typedef agg::span_image_filter_rgba_nn type; - }; -}; - - -template <> class type_mapping -{ - public: - typedef agg::rgba32 color_type; - typedef agg::blender_rgba_plain blender_type; - typedef agg::blender_rgba_pre pre_blender_type; - typedef agg::pixfmt_alpha_blend_rgba pixfmt_type; - typedef agg::pixfmt_alpha_blend_rgba pixfmt_pre_type; - - template - struct span_gen_affine_type - { - typedef agg::span_image_resample_rgba_affine type; - }; - - template - struct span_gen_filter_type - { - typedef agg::span_image_filter_rgba type; - }; - - template - struct span_gen_nn_type - { - typedef agg::span_image_filter_rgba_nn type; - }; + using blender_type = typename std::conditional< + is_grayscale::value, + agg::blender_gray, + typename std::conditional< + std::is_same::value, + fixed_blender_rgba_plain, + agg::blender_rgba_plain + >::type + >::type; + using pixfmt_type = typename std::conditional< + is_grayscale::value, + agg::pixfmt_alpha_blend_gray, + agg::pixfmt_alpha_blend_rgba + >::type; + using pixfmt_pre_type = typename std::conditional< + is_grayscale::value, + pixfmt_type, + agg::pixfmt_alpha_blend_rgba< + typename std::conditional< + std::is_same::value, + fixed_blender_rgba_pre, + agg::blender_rgba_pre + >::type, + agg::rendering_buffer> + >::type; + template using span_gen_affine_type = typename std::conditional< + is_grayscale::value, + agg::span_image_resample_gray_affine, + agg::span_image_resample_rgba_affine + >::type; + template using span_gen_filter_type = typename std::conditional< + is_grayscale::value, + agg::span_image_filter_gray, + agg::span_image_filter_rgba + >::type; + template using span_gen_nn_type = typename std::conditional< + is_grayscale::value, + agg::span_image_filter_gray_nn, + agg::span_image_filter_rgba_nn + >::type; }; -template <> class type_mapping -{ - public: - typedef agg::rgba64 color_type; - typedef agg::blender_rgba_plain blender_type; - typedef agg::blender_rgba_pre pre_blender_type; - typedef agg::pixfmt_alpha_blend_rgba pixfmt_type; - typedef agg::pixfmt_alpha_blend_rgba pixfmt_pre_type; - - template - struct span_gen_affine_type - { - typedef agg::span_image_resample_rgba_affine type; - }; - - template - struct span_gen_filter_type - { - typedef agg::span_image_filter_rgba type; - }; - - template - struct span_gen_nn_type - { - typedef agg::span_image_filter_rgba_nn type; - }; -}; - - -template <> class type_mapping -{ - public: - typedef agg::gray64 color_type; - typedef agg::blender_gray blender_type; - typedef agg::pixfmt_alpha_blend_gray pixfmt_type; - typedef pixfmt_type pixfmt_pre_type; - - template - struct span_gen_affine_type - { - typedef agg::span_image_resample_gray_affine type; - }; - - template - struct span_gen_filter_type - { - typedef agg::span_image_filter_gray type; - }; - - template - struct span_gen_nn_type - { - typedef agg::span_image_filter_gray_nn type; - }; -}; - - -template <> class type_mapping -{ - public: - typedef agg::gray32 color_type; - typedef agg::blender_gray blender_type; - typedef agg::pixfmt_alpha_blend_gray pixfmt_type; - typedef pixfmt_type pixfmt_pre_type; - - template - struct span_gen_affine_type - { - typedef agg::span_image_resample_gray_affine type; - }; - - template - struct span_gen_filter_type - { - typedef agg::span_image_filter_gray type; - }; - - template - struct span_gen_nn_type - { - typedef agg::span_image_filter_gray_nn type; - }; -}; - - -template <> class type_mapping -{ - public: - typedef agg::gray16 color_type; - typedef agg::blender_gray blender_type; - typedef agg::pixfmt_alpha_blend_gray pixfmt_type; - typedef pixfmt_type pixfmt_pre_type; - - template - struct span_gen_affine_type - { - typedef agg::span_image_resample_gray_affine type; - }; - - template - struct span_gen_filter_type - { - typedef agg::span_image_filter_gray type; - }; - - template - struct span_gen_nn_type - { - typedef agg::span_image_filter_gray_nn type; - }; -}; - - -template <> class type_mapping -{ - public: - typedef agg::gray8 color_type; - typedef agg::blender_gray blender_type; - typedef agg::pixfmt_alpha_blend_gray pixfmt_type; - typedef pixfmt_type pixfmt_pre_type; - - template - struct span_gen_affine_type - { - typedef agg::span_image_resample_gray_affine type; - }; - - template - struct span_gen_filter_type - { - typedef agg::span_image_filter_gray type; - }; - - template - struct span_gen_nn_type - { - typedef agg::span_image_filter_gray_nn type; - }; -}; - - - -template +template class span_conv_alpha { public: @@ -882,29 +700,34 @@ static void get_filter(const resample_params_t ¶ms, } -template +template void resample( - const T *input, int in_width, int in_height, - T *output, int out_width, int out_height, + const void *input, int in_width, int in_height, + void *output, int out_width, int out_height, resample_params_t ¶ms) { - typedef type_mapping type_mapping_t; + using type_mapping_t = type_mapping; - typedef typename type_mapping_t::pixfmt_type input_pixfmt_t; - typedef typename type_mapping_t::pixfmt_type output_pixfmt_t; + using input_pixfmt_t = typename type_mapping_t::pixfmt_type; + using output_pixfmt_t = typename type_mapping_t::pixfmt_type; - typedef agg::renderer_base renderer_t; - typedef agg::rasterizer_scanline_aa rasterizer_t; + using renderer_t = agg::renderer_base; + using rasterizer_t = agg::rasterizer_scanline_aa; - typedef agg::wrap_mode_reflect reflect_t; - typedef agg::image_accessor_wrap image_accessor_t; + using reflect_t = agg::wrap_mode_reflect; + using image_accessor_t = agg::image_accessor_wrap; - typedef agg::span_allocator span_alloc_t; - typedef span_conv_alpha span_conv_alpha_t; + using span_alloc_t = agg::span_allocator; + using span_conv_alpha_t = span_conv_alpha; - typedef agg::span_interpolator_linear<> affine_interpolator_t; - typedef agg::span_interpolator_adaptor, lookup_distortion> - arbitrary_interpolator_t; + using affine_interpolator_t = agg::span_interpolator_linear<>; + using arbitrary_interpolator_t = + agg::span_interpolator_adaptor, lookup_distortion>; + + size_t itemsize = sizeof(color_type); + if (is_grayscale::value) { + itemsize /= 2; // agg::grayXX includes an alpha channel which we don't have. + } if (params.interpolation != NEAREST && params.is_affine && @@ -922,14 +745,14 @@ void resample( span_conv_alpha_t conv_alpha(params.alpha); agg::rendering_buffer input_buffer; - input_buffer.attach((unsigned char *)input, in_width, in_height, - in_width * sizeof(T)); + input_buffer.attach( + (unsigned char *)input, in_width, in_height, in_width * itemsize); input_pixfmt_t input_pixfmt(input_buffer); image_accessor_t input_accessor(input_pixfmt); agg::rendering_buffer output_buffer; - output_buffer.attach((unsigned char *)output, out_width, out_height, - out_width * sizeof(T)); + output_buffer.attach( + (unsigned char *)output, out_width, out_height, out_width * itemsize); output_pixfmt_t output_pixfmt(output_buffer); renderer_t renderer(output_pixfmt); @@ -958,20 +781,18 @@ void resample( if (params.interpolation == NEAREST) { if (params.is_affine) { - typedef typename type_mapping_t::template span_gen_nn_type::type span_gen_t; - typedef agg::span_converter span_conv_t; - typedef agg::renderer_scanline_aa nn_renderer_t; - + using span_gen_t = typename type_mapping_t::template span_gen_nn_type; + using span_conv_t = agg::span_converter; + using nn_renderer_t = agg::renderer_scanline_aa; affine_interpolator_t interpolator(inverted); span_gen_t span_gen(input_accessor, interpolator); span_conv_t span_conv(span_gen, conv_alpha); nn_renderer_t nn_renderer(renderer, span_alloc, span_conv); agg::render_scanlines(rasterizer, scanline, nn_renderer); } else { - typedef typename type_mapping_t::template span_gen_nn_type::type span_gen_t; - typedef agg::span_converter span_conv_t; - typedef agg::renderer_scanline_aa nn_renderer_t; - + using span_gen_t = typename type_mapping_t::template span_gen_nn_type; + using span_conv_t = agg::span_converter; + using nn_renderer_t = agg::renderer_scanline_aa; lookup_distortion dist( params.transform_mesh, in_width, in_height, out_width, out_height); arbitrary_interpolator_t interpolator(inverted, dist); @@ -985,20 +806,18 @@ void resample( get_filter(params, filter); if (params.is_affine && params.resample) { - typedef typename type_mapping_t::template span_gen_affine_type::type span_gen_t; - typedef agg::span_converter span_conv_t; - typedef agg::renderer_scanline_aa int_renderer_t; - + using span_gen_t = typename type_mapping_t::template span_gen_affine_type; + using span_conv_t = agg::span_converter; + using int_renderer_t = agg::renderer_scanline_aa; affine_interpolator_t interpolator(inverted); span_gen_t span_gen(input_accessor, interpolator, filter); span_conv_t span_conv(span_gen, conv_alpha); int_renderer_t int_renderer(renderer, span_alloc, span_conv); agg::render_scanlines(rasterizer, scanline, int_renderer); } else { - typedef typename type_mapping_t::template span_gen_filter_type::type span_gen_t; - typedef agg::span_converter span_conv_t; - typedef agg::renderer_scanline_aa int_renderer_t; - + using span_gen_t = typename type_mapping_t::template span_gen_filter_type; + using span_conv_t = agg::span_converter; + using int_renderer_t = agg::renderer_scanline_aa; lookup_distortion dist( params.transform_mesh, in_width, in_height, out_width, out_height); arbitrary_interpolator_t interpolator(inverted, dist); diff --git a/src/_image_wrapper.cpp b/src/_image_wrapper.cpp index 5f797858b28f..c2dd57ab15f6 100644 --- a/src/_image_wrapper.cpp +++ b/src/_image_wrapper.cpp @@ -102,19 +102,6 @@ _get_transform_mesh(PyObject *py_affine, npy_intp *dims) } -template -static void -resample(PyArrayObject* input, PyArrayObject* output, resample_params_t params) -{ - Py_BEGIN_ALLOW_THREADS - resample( - (T*)PyArray_DATA(input), PyArray_DIM(input, 1), PyArray_DIM(input, 0), - (T*)PyArray_DATA(output), PyArray_DIM(output, 1), PyArray_DIM(output, 0), - params); - Py_END_ALLOW_THREADS -} - - static PyObject * image_resample(PyObject *self, PyObject* args, PyObject *kwargs) { @@ -127,6 +114,7 @@ image_resample(PyObject *self, PyObject* args, PyObject *kwargs) PyArrayObject *output = NULL; PyArrayObject *transform_mesh = NULL; int ndim; + int type; params.interpolation = NEAREST; params.transform_mesh = NULL; @@ -159,6 +147,7 @@ image_resample(PyObject *self, PyObject* args, PyObject *kwargs) goto error; } ndim = PyArray_NDIM(input); + type = PyArray_TYPE(input); if (!PyArray_Check(py_output)) { PyErr_SetString(PyExc_ValueError, "Output array must be a NumPy array"); @@ -181,7 +170,7 @@ image_resample(PyObject *self, PyObject* args, PyObject *kwargs) " respectively", PyArray_DIM(input, 2), PyArray_DIM(output, 2)); goto error; } - if (PyArray_TYPE(input) != PyArray_TYPE(output)) { + if (PyArray_TYPE(output) != type) { PyErr_SetString(PyExc_ValueError, "Mismatched types"); goto error; } @@ -221,50 +210,34 @@ image_resample(PyObject *self, PyObject* args, PyObject *kwargs) } } - if (ndim == 3) { - switch (PyArray_TYPE(input)) { - case NPY_UINT8: - case NPY_INT8: - resample(input, output, params); - break; - case NPY_UINT16: - case NPY_INT16: - resample(input, output, params); - break; - case NPY_FLOAT32: - resample(input, output, params); - break; - case NPY_FLOAT64: - resample(input, output, params); - break; - default: - PyErr_SetString( - PyExc_ValueError, - "arrays must be of dtype byte, short, float32 or float64"); - goto error; - } - } else { // ndim == 2 - switch (PyArray_TYPE(input)) { - case NPY_UINT8: - case NPY_INT8: - resample(input, output, params); - break; - case NPY_UINT16: - case NPY_INT16: - resample(input, output, params); - break; - case NPY_FLOAT32: - resample(input, output, params); - break; - case NPY_FLOAT64: - resample(input, output, params); - break; - default: - PyErr_SetString( - PyExc_ValueError, - "arrays must be of dtype byte, short, float32 or float64"); - goto error; - } + if (auto resampler = + (ndim == 2) ? ( + (type == NPY_UINT8) ? resample : + (type == NPY_INT8) ? resample : + (type == NPY_UINT16) ? resample : + (type == NPY_INT16) ? resample : + (type == NPY_FLOAT32) ? resample : + (type == NPY_FLOAT64) ? resample : + nullptr) : ( + // ndim == 3 + (type == NPY_UINT8) ? resample : + (type == NPY_INT8) ? resample : + (type == NPY_UINT16) ? resample : + (type == NPY_INT16) ? resample : + (type == NPY_FLOAT32) ? resample : + (type == NPY_FLOAT64) ? resample : + nullptr)) { + Py_BEGIN_ALLOW_THREADS + resampler( + PyArray_DATA(input), PyArray_DIM(input, 1), PyArray_DIM(input, 0), + PyArray_DATA(output), PyArray_DIM(output, 1), PyArray_DIM(output, 0), + params); + Py_END_ALLOW_THREADS + } else { + PyErr_SetString( + PyExc_ValueError, + "arrays must be of dtype byte, short, float32 or float64"); + goto error; } Py_DECREF(input);