Clase genérica de píxeles a alfa-mezcla perfectamente y convertir entre diferentes diseños de estructura de píxeles -- ++ campo con graphics campo con c++17 campo con vectorization campo con sse camp codereview Relacionados El problema

Generic pixel class to seamlessly alpha-blend and convert between different pixel structure layouts


3
vote

problema

Español

hace lo que dice en el título. Acabo de terminar esto y quería compartir con alguien.

Buscando posibles optimizaciones, errores (la mayor parte de ella se prueba para trabajar) o cualquier crítica constructiva.

  template<typename P> struct alignas(P) [[gnu::packed, gnu::may_alias]] pixel : public P {     template<typename> friend struct pixel;      using T = std::conditional_t<std::is_integral_v<typename P::T>, unsigned, typename P::T>;      template<std::size_t N, typename VT>     using V [[gnu::vector_size(N * sizeof(VT)), gnu::may_alias]] = VT;      constexpr pixel() noexcept = default;     template<typename U = P, typename PT = typename U::T, std::enable_if_t<pixel<U>::has_alpha(), bool> = { }>     constexpr pixel(T cr, T cg, T cb, T ca) noexcept : P { static_cast<PT>(cb), static_cast<PT>(cg), static_cast<PT>(cr), static_cast<PT>(ca) } { }     template<typename U = P, typename PT = typename U::T, std::enable_if_t<pixel<U>::has_alpha(), bool> = { } >     constexpr pixel(T cr, T cg, T cb) noexcept : P { static_cast<PT>(cb), static_cast<PT>(cg), static_cast<PT>(cr), U::ax } { }     template<typename U = P, typename PT = typename U::T, std::enable_if_t<not pixel<U>::has_alpha(), bool> = { } >     constexpr pixel(T cr, T cg, T cb, T) noexcept : P { static_cast<PT>(cb), static_cast<PT>(cg), static_cast<PT>(cr) } { }     template<typename U = P, typename PT = typename U::T, std::enable_if_t<not pixel<U>::has_alpha(), bool> = { } >     constexpr pixel(T cr, T cg, T cb) noexcept : P { static_cast<PT>(cb), static_cast<PT>(cg), static_cast<PT>(cr) } { }      constexpr pixel(const pixel& p) noexcept = default;     constexpr pixel(pixel&& p) noexcept = default;     constexpr pixel& operator=(const pixel&) noexcept = default;     constexpr pixel& operator=(pixel&&) noexcept = default;      template <typename U> constexpr operator pixel<U>() const noexcept { return cast_to<U>(); }      static constexpr bool has_alpha() { return P::ax > 0; }      template<typename U>     constexpr pixel& blend(const pixel<U>& other)     {         if constexpr (not pixel<U>::has_alpha())         {             *this = other.template cast_to<P>();         }         else if constexpr (sse and (std::is_floating_point_v<typename P::T> or std::is_floating_point_v<typename U::T>))         {             *this = m128(m128_blend<U>(m128(), other.m128()));             if constexpr (std::is_integral_v<typename U::T>) _mm_empty();         }         else if constexpr (mmx and std::is_integral_v<typename P::T> and std::is_integral_v<typename U::T>)         {             *this = m64(m64_blend<U>(m64(), other.m64()));         }         else         {             using VT = std::conditional_t<std::is_floating_point_v<typename P::T> or std::is_floating_point_v<typename U::T>, float, std::uint32_t>;             V<4, VT> src = other.template vector<VT>();             V<4, VT> dst = vector<VT>();             *this = vector<VT>(vector_blend<U, VT>(dst, src));         }         return *this;     }      template<typename U>     constexpr pixel& blend_straight(const pixel<U>& other)     {         if constexpr (not pixel<U>::has_alpha())         {             *this = other.template cast_to<P>();         }         else if constexpr (sse and (std::is_floating_point_v<typename P::T> or std::is_floating_point_v<typename U::T>))         {             *this = m128(m128_blend<U>(m128_premul(m128()), m128_premul(other.m128())));             if constexpr (std::is_integral_v<typename U::T>) _mm_empty();         }         else if constexpr (mmx and std::is_integral_v<typename P::T> and std::is_integral_v<typename U::T>)         {             *this = m64(m64_blend<U>(m64_premul(m64()), m64_premul(other.m64())));         }         else         {             using VT = std::conditional_t<std::is_floating_point_v<typename P::T> or std::is_floating_point_v<typename U::T>, float, std::uint32_t>;             V<4, VT> src = vector_premul<VT>(other.template vector<VT>());             V<4, VT> dst = vector_premul<VT>(vector<VT>());             *this = vector<VT>(vector_blend<U, VT>(dst, src));         }         return *this;     }      constexpr pixel& premultiply_alpha()     {         if constexpr (not has_alpha()) return *this;         if constexpr (sse and std::is_floating_point_v<typename P::T>) *this = m128(m128_premul(m128()));         else if constexpr (mmx and not std::is_floating_point_v<typename P::T>) *this = m64(m64_premul(m64()));         else         {             using VT = std::conditional_t<std::is_floating_point_v<typename P::T>, float, std::uint8_t>;             *this = vector<VT>(vector_premul<VT>(vector<VT>()));         }         return *this;     }  private:     template <typename U>     constexpr pixel<U> cast_to() const     {         constexpr bool not_constexpr = true;// not is_constexpr(this->b);         if constexpr (not_constexpr and sse and (std::is_floating_point_v<typename P::T> or std::is_floating_point_v<typename U::T>))         {             auto result = pixel<U>::m128(m128_cast_to<U>(m128()));             if constexpr (std::is_integral_v<typename P::T>) _mm_empty();             return result;         }         else if constexpr (not_constexpr and mmx and (sse or (std::is_integral_v<typename P::T> and std::is_integral_v<typename U::T>)))         {             return pixel<U>::m64(m64_cast_to<U>(m64()));         }         else         {             using VT = std::conditional_t<std::is_floating_point_v<typename P::T> or std::is_floating_point_v<typename U::T>, float, std::uint32_t>;             return pixel<U>::template vector<VT>(vector_cast_to<U, VT>(vector<VT>()));         }     }      static constexpr pixel m64(auto value) noexcept // V4HI     {         static_assert(not std::is_floating_point_v<typename P::T>);         auto v = _mm_packs_pu16(value, _mm_setzero_si64());         if constexpr (byte_aligned())         {             auto v2 = _mm_cvtsi64_si32(v);             pixel result { *reinterpret_cast<pixel*>(&v2) };             _mm_empty();             return result;         }         else         {             auto v2 = reinterpret_cast<V<8, byte>&>(v);             pixel result { v2[2], v2[1], v2[0], v2[3] };             _mm_empty();             return result;         }     }      constexpr __m64 m64() const noexcept    // V4HI     {         static_assert(not std::is_floating_point_v<typename P::T>);         __m64 v;         if constexpr (byte_aligned()) v = _mm_cvtsi32_si64(*reinterpret_cast<const int*>(this));         else if constexpr (has_alpha()) v = _mm_setr_pi8(this->b, this->g, this->r, this->a, 0, 0, 0, 0);         else v = _mm_setr_pi8(this->b, this->g, this->r, 0, 0, 0, 0, 0);         auto r = _mm_unpacklo_pi8(v, _mm_setzero_si64());         return r;     }      static constexpr pixel m128(__m128 value) noexcept  // V4SF     {         if constexpr (std::is_floating_point_v<typename P::T>) return *reinterpret_cast<pixel*>(&value);         else return m64(_mm_cvtps_pi16(value));     }      constexpr __m128 m128() const noexcept  // V4SF     {         if constexpr (std::is_floating_point_v<typename P::T>) return *reinterpret_cast<const __m128*>(this);         else return _mm_cvtpu16_ps(m64());     }      template<typename VT = std::uint16_t>     static constexpr pixel vector(V<4, VT> src) noexcept     {         if constexpr ((std::is_same_v<VT, float> and std::is_same_v<T, float>) or (sizeof(VT) == 1 and byte_aligned()))         {             return *reinterpret_cast<pixel*>(&src);         }         return pixel { static_cast<T>(src[2]), static_cast<T>(src[1]), static_cast<T>(src[0]), static_cast<T>(src[3]) };     }      template<typename VT = std::uint16_t>     constexpr V<4, VT> vector() const noexcept     {         V<4, VT> src;         if constexpr ((std::is_same_v<VT, float> and std::is_same_v<T, float>) or (sizeof(VT) == 1 and byte_aligned()))         {             src = *reinterpret_cast<const V<4, VT>*>(this);             if constexpr (has_alpha()) src = V<4, VT> { src[0], src[1], src[2], 1 };         }         else if constexpr (has_alpha()) src = V<4, VT> { static_cast<VT>(this->b), static_cast<VT>(this->g), static_cast<VT>(this->r), static_cast<VT>(this->a), };         else src = V<4, VT> { static_cast<VT>(this->b), static_cast<VT>(this->g), static_cast<VT>(this->r), 1 };         return src;     }      template <typename U>     static constexpr __m128 m128_cast_to(__m128 src) noexcept     {         constexpr __m128 cast = reinterpret_cast<__m128>(pixel<U>::template vector_max<float>(P::ax) * (1.0f / vector_max<float>(U::ax or 1.0f)));         src = _mm_mul_ps(src, cast);         if constexpr (pixel<U>::has_alpha() and not has_alpha()) src = _mm_setr_ps(src[0], src[1], src[2], static_cast<float>(U::ax));         return src;     }      template <typename U>     static constexpr __m64 m64_cast_to(__m64 src) noexcept     {         constexpr auto mullo = reinterpret_cast<__m64>(pixel<U>::template vector_max<std::uint16_t>());         constexpr auto mulhi = reinterpret_cast<__m64>(vector_max_reciprocal<17, std::uint16_t, 15>());         auto vector_max_contains = [](std::uint16_t value)         {             auto v = vector_max<std::uint16_t>();             for (auto i = 0; i < 4; ++i) if (v[i] == value) return true;             return false;         };          src = _mm_mullo_pi16(src, mullo);         auto dst = _mm_mulhi_pi16(src, mulhi);         dst = _mm_srli_pi16(_mm_adds_pu8(dst, _mm_set1_pi16(1)), 1);          if constexpr (vector_max_contains(1))         {             constexpr auto is1 = reinterpret_cast<__m64>(vector_max<std::uint16_t>() == 1);             auto v1 = _mm_and_si64(src, is1);             dst = _mm_or_si64(_mm_andnot_si64(is1, dst), v1);         }         if constexpr (vector_max_contains(3))         {             constexpr auto mulhi3 = reinterpret_cast<__m64>(vector_max_reciprocal<16, std::uint16_t, 15>());             constexpr auto is3 = reinterpret_cast<__m64>(vector_max<std::uint16_t>() == 3);             auto v3 = _mm_mulhi_pi16(_mm_and_si64(src, is3), mulhi3);             dst = _mm_or_si64(_mm_andnot_si64(is3, dst), v3);         }         if constexpr (pixel<U>::has_alpha() and not has_alpha()) dst = _mm_insert_pi16(dst, U::ax, 3);         return dst;     }      template <typename U, typename VT>     static constexpr V<4, VT> vector_cast_to(V<4, VT> src) noexcept     {         if constexpr (std::is_floating_point_v<VT>)         {             src *= pixel<U>::template vector_max<VT>(P::ax) * (1.0f / vector_max<VT>(U::ax or 1.0f));         }         else         {             constexpr auto rbits = (sizeof(VT) - 1) * 8;             src *= pixel<U>::template vector_max<VT>(P::ax | 1);             src *= vector_max_reciprocal<rbits, VT>(U::ax | 1);             src += 1 << (rbits - 1);             src >>= rbits;         }         if constexpr (has_alpha()) return src;         else return V<4, VT> { src[0], src[1], src[2], static_cast<VT>(U::ax) };     }      static constexpr __m128 m128_premul(__m128 src) noexcept     {         if constexpr (not has_alpha()) return src;         constexpr auto ax = reinterpret_cast<__m128>(1.0f / V<4, float> { P::ax, P::ax, P::ax, 1 });         auto srca = _mm_setr_ps(src[3], src[3], src[3], 1);         src = _mm_mul_ps(src, srca);         src = _mm_mul_ps(src, ax);         return src;     }      static constexpr __m64 m64_premul(__m64 src) noexcept     {         if constexpr (not has_alpha()) return src;         auto a = _mm_shuffle_pi16(src, shuffle_mask(3, 3, 3, 3));         src = _mm_mullo_pi16(src, a);         if constexpr (P::ax == 3)         {             constexpr auto ax = vector_reciprocal<16, std::uint16_t, 15>(P::ax);             src = _mm_mulhi_pi16(src, reinterpret_cast<__m64>(ax));         }         else if constexpr (P::ax > 3)         {             constexpr auto ax = vector_reciprocal<17, std::uint16_t, 15>(P::ax);             src = _mm_mulhi_pi16(src, reinterpret_cast<__m64>(ax));             src = _mm_srli_pi16(_mm_adds_pu8(src, _mm_set1_pi16(1)), 1);         }         src = _mm_insert_pi16(src, a[0], 3);         return src;     }      template <typename VT>     static constexpr V<4, VT> vector_premul(V<4, VT> src) noexcept     {         if constexpr (not has_alpha()) return src;         auto a = V<4, VT> { src[3], src[3], src[3], 1 };         if constexpr (std::is_floating_point_v<VT>)         {             constexpr auto ax = 1.0f / V<4, float> { P::ax, P::ax, P::ax, 1 };             src *= a * ax;         }         else         {             constexpr auto rbits = (sizeof(VT) - 1) * 8;             constexpr auto ax = vector_reciprocal<rbits, VT>(P::ax, P::ax, P::ax, 1);             src *= a;             src *= ax;             src += 1 << (rbits - 1);             src >>= rbits;         }         return src;     }      template <typename U>     constexpr __m128 m128_blend(__m128 dst, __m128 src)     {         constexpr auto ax = reinterpret_cast<__m128>(1.0f / V<4, float> { U::ax, U::ax, U::ax, U::ax });         auto a = _mm_sub_ps(_mm_set1_ps(U::ax), _mm_set1_ps(src[3]));          if constexpr (not std::is_same_v<P, U>) src = pixel<U>::template m128_cast_to<P>(src);         dst = _mm_mul_ps(dst, a);         dst = _mm_mul_ps(dst, ax);         dst = _mm_add_ps(dst, src);         return dst;     }      template <typename U>     constexpr __m64 m64_blend(__m64 dst, __m64 src)     {         //auto a = _mm_sub_pi16(_mm_set1_pi16(U::ax), _mm_shuffle_pi16(src, shuffle_mask(3, 3, 3, 3)));         auto a = _mm_set1_pi16(U::ax - reinterpret_cast<V<4, std::uint16_t>>(src)[3]);          if constexpr (not std::is_same_v<P, U>) src = pixel<U>::template m64_cast_to<P>(src);         dst = _mm_mullo_pi16(dst, a);         if constexpr (U::ax == 3)         {             constexpr auto ax = vector_reciprocal<16, std::uint16_t, 15>(U::ax);             dst = _mm_mulhi_pi16(dst, reinterpret_cast<__m64>(ax));         }         else if constexpr (U::ax != 1)         {             constexpr auto ax = vector_reciprocal<17, std::uint16_t, 15>(U::ax);             dst = _mm_mulhi_pi16(dst, reinterpret_cast<__m64>(ax));             dst = _mm_srli_pi16(_mm_adds_pu8(dst, _mm_set1_pi16(1)), 1);         }         dst = _mm_adds_pu16(dst, src);         return dst;     }      template <typename U, typename VT>     static constexpr V<4, VT> vector_blend(V<4, VT> dst, V<4, VT> src) noexcept     {         if constexpr (not std::is_same_v<P, U>) src = pixel<U>::template vector_cast_to<P, VT>(src);         if constexpr (std::is_floating_point_v<VT>)         {             constexpr auto ax = 1.0f / U::ax;             dst *= static_cast<VT>(U::ax - src[3]) * ax;             dst += src;         }         else         {             constexpr auto rbits = (sizeof(VT) - 1) * 8;             constexpr auto ax = vector_reciprocal<rbits, VT>(U::ax);             dst *= static_cast<VT>(U::ax - src[3]);             dst *= ax;             dst += 1 << (rbits - 1);             dst >>= rbits;             dst += src;         }         return dst;     }      template<std::size_t bits, typename VT = std::uint16_t, std::size_t maxbits = bits>     static constexpr auto vector_reciprocal(VT v0, VT v1, VT v2, VT v3) noexcept     {         auto r = [](VT v) -> VT { return std::min(((1ul << bits) + v - 1) / v, (1ul << maxbits) - 1); };         return V<4, VT> { r(v0), r(v1), r(v2), r(v3)};     }      template<std::size_t bits, typename VT = std::uint16_t, std::size_t maxbits = bits>     static constexpr auto vector_reciprocal(VT v0) noexcept     {         return vector_reciprocal<bits, VT, maxbits>(v0, v0, v0, v0);     }      template<typename VT = float>     static constexpr auto vector_max(VT noalpha = 1) noexcept     {         return V<4, VT> { P::bx, P::gx, P::rx, static_cast<VT>(has_alpha() ? P::ax : noalpha) };     }      template<std::size_t bits, typename VT = std::uint16_t, std::size_t maxbits = bits>     static constexpr auto vector_max_reciprocal(VT noalpha = 1) noexcept     {         return vector_reciprocal<bits, VT, maxbits>(P::bx, P::gx, P::rx, static_cast<VT>(has_alpha() ? P::ax : noalpha));     }      template<typename T> constexpr bool is_constexpr(T value) { return __builtin_constant_p(value); }     static constexpr auto shuffle_mask(int v0, int v1, int v2, int v3) noexcept { return (v0 & 3) | ((v1 & 3) << 2) | ((v2 & 3) << 4) | ((v3 & 3) << 6); }     static constexpr bool byte_aligned() noexcept { return P::byte_aligned; } };  struct alignas(0x10) bgra_ffff {     using T = float;     T b, g, r, a;      static constexpr T rx = 1.0f;     static constexpr T gx = 1.0f;     static constexpr T bx = 1.0f;     static constexpr T ax = 1.0f;     static constexpr bool byte_aligned = false; };  struct alignas(0x10) bgra_fff0 {     using T = float;     T b, g, r;     unsigned : sizeof(float);      static constexpr T rx = 1.0f;     static constexpr T gx = 1.0f;     static constexpr T bx = 1.0f;     static constexpr T ax = 0.0f;     static constexpr bool byte_aligned = false; };  struct alignas(4) bgra_8888 {     using T = std::uint8_t;     T b, g, r, a;      static constexpr T rx = 255;     static constexpr T gx = 255;     static constexpr T bx = 255;     static constexpr T ax = 255;     static constexpr bool byte_aligned = true; };  struct [[gnu::packed]] alignas(4) bgra_8880 {     using T = std::uint8_t;     T b, g, r;     T : 8;      static constexpr T rx = 255;     static constexpr T gx = 255;     static constexpr T bx = 255;     static constexpr T ax = 0;     static constexpr bool byte_aligned = true; };  struct [[gnu::packed]] bgr_8880 {     using T = std::uint8_t;     T b, g, r;      static constexpr T rx = 255;     static constexpr T gx = 255;     static constexpr T bx = 255;     static constexpr T ax = 0;     static constexpr bool byte_aligned = true; };  struct [[gnu::packed]] bgra_6668 {     using T = unsigned;     T b : 6, : 2;     T g : 6, : 2;     T r : 6, : 2;     T a : 8;      constexpr bgra_6668(T vb, T vg, T vr, T va) noexcept : b(vb), g(vg), r(vr), a(va) { }      static constexpr T rx = 63;     static constexpr T gx = 63;     static constexpr T bx = 63;     static constexpr T ax = 255;     static constexpr bool byte_aligned = true; };  struct alignas(2) [[gnu::packed]] bgr_5650 {     using T = unsigned;     T b : 5;     T g : 6;     T r : 5;      static constexpr T rx = 31;     static constexpr T gx = 63;     static constexpr T bx = 31;     static constexpr T ax = 0;     static constexpr bool byte_aligned = false; };  struct alignas(2) [[gnu::packed]] bgra_5551 {     using T = unsigned;     T b : 5;     T g : 5;     T r : 5;     T a : 1;      static constexpr T rx = 31;     static constexpr T gx = 31;     static constexpr T bx = 31;     static constexpr T ax = 1;     static constexpr bool byte_aligned = false; };  struct alignas(2) [[gnu::packed]] bgra_5550 {     using T = unsigned;     T b : 5;     T g : 5;     T r : 5;     T : 1;      static constexpr T rx = 31;     static constexpr T gx = 31;     static constexpr T bx = 31;     static constexpr T ax = 0;     static constexpr bool byte_aligned = false; };  struct alignas(2)[[gnu::packed]] bgra_4444 {     using T = unsigned;     T b : 4;     T g : 4;     T r : 4;     T a : 4;      static constexpr T rx = 15;     static constexpr T gx = 15;     static constexpr T bx = 15;     static constexpr T ax = 15;     static constexpr bool byte_aligned = false; };  struct [[gnu::packed]] bgr_2330 {     using T = unsigned;     T b : 2;     T g : 3;     T r : 3;      static constexpr T rx = 7;     static constexpr T gx = 7;     static constexpr T bx = 3;     static constexpr T ax = 0;     static constexpr bool byte_aligned = false; };  struct [[gnu::packed]] bgra_2321 {     using T = unsigned;     T b : 2;     T g : 3;     T r : 2;     T a : 1;      static constexpr T rx = 3;     static constexpr T gx = 7;     static constexpr T bx = 3;     static constexpr T ax = 1;     static constexpr bool byte_aligned = false; };  struct[[gnu::packed]] bgra_2222 {     using T = unsigned;     T b : 2;     T g : 2;     T r : 2;     T a : 2;      static constexpr T rx = 3;     static constexpr T gx = 3;     static constexpr T bx = 3;     static constexpr T ax = 3;     static constexpr bool byte_aligned = false; };  using pxf    = pixel<bgra_ffff>;     // floating-point for use with SSE using pxfn   = pixel<bgra_fff0>;     // floating-point, no alpha using px32a  = pixel<bgra_8888>;     // 24-bit, 8-bit alpha channel using px32n  = pixel<bgra_8880>;     // 24-bit, no alpha, 4 bytes wide using px24   = pixel<bgr_8880>;      // 24-bit, 3 bytes wide using px16   = pixel<bgr_5650>;      // 16-bit, typical 5:6:5 format using px16a  = pixel<bgra_5551>;     // 15-bit with 1-bit alpha using px16n  = pixel<bgra_5550>;     // 15-bit, no alpha, equal 5:5:5 format using px16aa = pixel<bgra_4444>;     // 12-bit, 4-bit alpha, equal 4:4:4 format using px8aa  = pixel<bgra_2222>;     // 6-bit 2:2:2, 2-bit alpha using px8a   = pixel<bgra_2321>;     // 7-bit 2:3:2, 1-bit alpha using px8n   = pixel<bgr_2330>;      // 8-bit 3:3:2, no alpha using pxvga  = pixel<bgra_6668>;     // VGA DAC palette format  static_assert(sizeof(pxf   ) == 16); static_assert(sizeof(pxfn  ) == 16); static_assert(sizeof(px32a ) ==  4); static_assert(sizeof(px32n ) ==  4); static_assert(sizeof(px24  ) ==  3); static_assert(sizeof(px16  ) ==  2); static_assert(sizeof(px16aa) ==  2); static_assert(sizeof(px16a ) ==  2); static_assert(sizeof(px16n ) ==  2); static_assert(sizeof(px8aa ) ==  1); static_assert(sizeof(px8a  ) ==  1); static_assert(sizeof(px8n  ) ==  1); static_assert(sizeof(pxvga ) ==  4);  inline auto generate_px8n_palette() {     std::vector<px32n> result;     result.reserve(256);     for (auto i = 0; i < 256; ++i)         result.emplace_back(reinterpret_cast<px8n&>(i));     return result; }   
Original en ingles

Does what it says in the title. I just finished this and wanted to share with someone.

Looking for possible optimizations, bugs (most of it is tested to work) or any constructive criticism.

template<typename P> struct alignas(P) [[gnu::packed, gnu::may_alias]] pixel : public P {     template<typename> friend struct pixel;      using T = std::conditional_t<std::is_integral_v<typename P::T>, unsigned, typename P::T>;      template<std::size_t N, typename VT>     using V [[gnu::vector_size(N * sizeof(VT)), gnu::may_alias]] = VT;      constexpr pixel() noexcept = default;     template<typename U = P, typename PT = typename U::T, std::enable_if_t<pixel<U>::has_alpha(), bool> = { }>     constexpr pixel(T cr, T cg, T cb, T ca) noexcept : P { static_cast<PT>(cb), static_cast<PT>(cg), static_cast<PT>(cr), static_cast<PT>(ca) } { }     template<typename U = P, typename PT = typename U::T, std::enable_if_t<pixel<U>::has_alpha(), bool> = { } >     constexpr pixel(T cr, T cg, T cb) noexcept : P { static_cast<PT>(cb), static_cast<PT>(cg), static_cast<PT>(cr), U::ax } { }     template<typename U = P, typename PT = typename U::T, std::enable_if_t<not pixel<U>::has_alpha(), bool> = { } >     constexpr pixel(T cr, T cg, T cb, T) noexcept : P { static_cast<PT>(cb), static_cast<PT>(cg), static_cast<PT>(cr) } { }     template<typename U = P, typename PT = typename U::T, std::enable_if_t<not pixel<U>::has_alpha(), bool> = { } >     constexpr pixel(T cr, T cg, T cb) noexcept : P { static_cast<PT>(cb), static_cast<PT>(cg), static_cast<PT>(cr) } { }      constexpr pixel(const pixel& p) noexcept = default;     constexpr pixel(pixel&& p) noexcept = default;     constexpr pixel& operator=(const pixel&) noexcept = default;     constexpr pixel& operator=(pixel&&) noexcept = default;      template <typename U> constexpr operator pixel<U>() const noexcept { return cast_to<U>(); }      static constexpr bool has_alpha() { return P::ax > 0; }      template<typename U>     constexpr pixel& blend(const pixel<U>& other)     {         if constexpr (not pixel<U>::has_alpha())         {             *this = other.template cast_to<P>();         }         else if constexpr (sse and (std::is_floating_point_v<typename P::T> or std::is_floating_point_v<typename U::T>))         {             *this = m128(m128_blend<U>(m128(), other.m128()));             if constexpr (std::is_integral_v<typename U::T>) _mm_empty();         }         else if constexpr (mmx and std::is_integral_v<typename P::T> and std::is_integral_v<typename U::T>)         {             *this = m64(m64_blend<U>(m64(), other.m64()));         }         else         {             using VT = std::conditional_t<std::is_floating_point_v<typename P::T> or std::is_floating_point_v<typename U::T>, float, std::uint32_t>;             V<4, VT> src = other.template vector<VT>();             V<4, VT> dst = vector<VT>();             *this = vector<VT>(vector_blend<U, VT>(dst, src));         }         return *this;     }      template<typename U>     constexpr pixel& blend_straight(const pixel<U>& other)     {         if constexpr (not pixel<U>::has_alpha())         {             *this = other.template cast_to<P>();         }         else if constexpr (sse and (std::is_floating_point_v<typename P::T> or std::is_floating_point_v<typename U::T>))         {             *this = m128(m128_blend<U>(m128_premul(m128()), m128_premul(other.m128())));             if constexpr (std::is_integral_v<typename U::T>) _mm_empty();         }         else if constexpr (mmx and std::is_integral_v<typename P::T> and std::is_integral_v<typename U::T>)         {             *this = m64(m64_blend<U>(m64_premul(m64()), m64_premul(other.m64())));         }         else         {             using VT = std::conditional_t<std::is_floating_point_v<typename P::T> or std::is_floating_point_v<typename U::T>, float, std::uint32_t>;             V<4, VT> src = vector_premul<VT>(other.template vector<VT>());             V<4, VT> dst = vector_premul<VT>(vector<VT>());             *this = vector<VT>(vector_blend<U, VT>(dst, src));         }         return *this;     }      constexpr pixel& premultiply_alpha()     {         if constexpr (not has_alpha()) return *this;         if constexpr (sse and std::is_floating_point_v<typename P::T>) *this = m128(m128_premul(m128()));         else if constexpr (mmx and not std::is_floating_point_v<typename P::T>) *this = m64(m64_premul(m64()));         else         {             using VT = std::conditional_t<std::is_floating_point_v<typename P::T>, float, std::uint8_t>;             *this = vector<VT>(vector_premul<VT>(vector<VT>()));         }         return *this;     }  private:     template <typename U>     constexpr pixel<U> cast_to() const     {         constexpr bool not_constexpr = true;// not is_constexpr(this->b);         if constexpr (not_constexpr and sse and (std::is_floating_point_v<typename P::T> or std::is_floating_point_v<typename U::T>))         {             auto result = pixel<U>::m128(m128_cast_to<U>(m128()));             if constexpr (std::is_integral_v<typename P::T>) _mm_empty();             return result;         }         else if constexpr (not_constexpr and mmx and (sse or (std::is_integral_v<typename P::T> and std::is_integral_v<typename U::T>)))         {             return pixel<U>::m64(m64_cast_to<U>(m64()));         }         else         {             using VT = std::conditional_t<std::is_floating_point_v<typename P::T> or std::is_floating_point_v<typename U::T>, float, std::uint32_t>;             return pixel<U>::template vector<VT>(vector_cast_to<U, VT>(vector<VT>()));         }     }      static constexpr pixel m64(auto value) noexcept // V4HI     {         static_assert(not std::is_floating_point_v<typename P::T>);         auto v = _mm_packs_pu16(value, _mm_setzero_si64());         if constexpr (byte_aligned())         {             auto v2 = _mm_cvtsi64_si32(v);             pixel result { *reinterpret_cast<pixel*>(&v2) };             _mm_empty();             return result;         }         else         {             auto v2 = reinterpret_cast<V<8, byte>&>(v);             pixel result { v2[2], v2[1], v2[0], v2[3] };             _mm_empty();             return result;         }     }      constexpr __m64 m64() const noexcept    // V4HI     {         static_assert(not std::is_floating_point_v<typename P::T>);         __m64 v;         if constexpr (byte_aligned()) v = _mm_cvtsi32_si64(*reinterpret_cast<const int*>(this));         else if constexpr (has_alpha()) v = _mm_setr_pi8(this->b, this->g, this->r, this->a, 0, 0, 0, 0);         else v = _mm_setr_pi8(this->b, this->g, this->r, 0, 0, 0, 0, 0);         auto r = _mm_unpacklo_pi8(v, _mm_setzero_si64());         return r;     }      static constexpr pixel m128(__m128 value) noexcept  // V4SF     {         if constexpr (std::is_floating_point_v<typename P::T>) return *reinterpret_cast<pixel*>(&value);         else return m64(_mm_cvtps_pi16(value));     }      constexpr __m128 m128() const noexcept  // V4SF     {         if constexpr (std::is_floating_point_v<typename P::T>) return *reinterpret_cast<const __m128*>(this);         else return _mm_cvtpu16_ps(m64());     }      template<typename VT = std::uint16_t>     static constexpr pixel vector(V<4, VT> src) noexcept     {         if constexpr ((std::is_same_v<VT, float> and std::is_same_v<T, float>) or (sizeof(VT) == 1 and byte_aligned()))         {             return *reinterpret_cast<pixel*>(&src);         }         return pixel { static_cast<T>(src[2]), static_cast<T>(src[1]), static_cast<T>(src[0]), static_cast<T>(src[3]) };     }      template<typename VT = std::uint16_t>     constexpr V<4, VT> vector() const noexcept     {         V<4, VT> src;         if constexpr ((std::is_same_v<VT, float> and std::is_same_v<T, float>) or (sizeof(VT) == 1 and byte_aligned()))         {             src = *reinterpret_cast<const V<4, VT>*>(this);             if constexpr (has_alpha()) src = V<4, VT> { src[0], src[1], src[2], 1 };         }         else if constexpr (has_alpha()) src = V<4, VT> { static_cast<VT>(this->b), static_cast<VT>(this->g), static_cast<VT>(this->r), static_cast<VT>(this->a), };         else src = V<4, VT> { static_cast<VT>(this->b), static_cast<VT>(this->g), static_cast<VT>(this->r), 1 };         return src;     }      template <typename U>     static constexpr __m128 m128_cast_to(__m128 src) noexcept     {         constexpr __m128 cast = reinterpret_cast<__m128>(pixel<U>::template vector_max<float>(P::ax) * (1.0f / vector_max<float>(U::ax or 1.0f)));         src = _mm_mul_ps(src, cast);         if constexpr (pixel<U>::has_alpha() and not has_alpha()) src = _mm_setr_ps(src[0], src[1], src[2], static_cast<float>(U::ax));         return src;     }      template <typename U>     static constexpr __m64 m64_cast_to(__m64 src) noexcept     {         constexpr auto mullo = reinterpret_cast<__m64>(pixel<U>::template vector_max<std::uint16_t>());         constexpr auto mulhi = reinterpret_cast<__m64>(vector_max_reciprocal<17, std::uint16_t, 15>());         auto vector_max_contains = [](std::uint16_t value)         {             auto v = vector_max<std::uint16_t>();             for (auto i = 0; i < 4; ++i) if (v[i] == value) return true;             return false;         };          src = _mm_mullo_pi16(src, mullo);         auto dst = _mm_mulhi_pi16(src, mulhi);         dst = _mm_srli_pi16(_mm_adds_pu8(dst, _mm_set1_pi16(1)), 1);          if constexpr (vector_max_contains(1))         {             constexpr auto is1 = reinterpret_cast<__m64>(vector_max<std::uint16_t>() == 1);             auto v1 = _mm_and_si64(src, is1);             dst = _mm_or_si64(_mm_andnot_si64(is1, dst), v1);         }         if constexpr (vector_max_contains(3))         {             constexpr auto mulhi3 = reinterpret_cast<__m64>(vector_max_reciprocal<16, std::uint16_t, 15>());             constexpr auto is3 = reinterpret_cast<__m64>(vector_max<std::uint16_t>() == 3);             auto v3 = _mm_mulhi_pi16(_mm_and_si64(src, is3), mulhi3);             dst = _mm_or_si64(_mm_andnot_si64(is3, dst), v3);         }         if constexpr (pixel<U>::has_alpha() and not has_alpha()) dst = _mm_insert_pi16(dst, U::ax, 3);         return dst;     }      template <typename U, typename VT>     static constexpr V<4, VT> vector_cast_to(V<4, VT> src) noexcept     {         if constexpr (std::is_floating_point_v<VT>)         {             src *= pixel<U>::template vector_max<VT>(P::ax) * (1.0f / vector_max<VT>(U::ax or 1.0f));         }         else         {             constexpr auto rbits = (sizeof(VT) - 1) * 8;             src *= pixel<U>::template vector_max<VT>(P::ax | 1);             src *= vector_max_reciprocal<rbits, VT>(U::ax | 1);             src += 1 << (rbits - 1);             src >>= rbits;         }         if constexpr (has_alpha()) return src;         else return V<4, VT> { src[0], src[1], src[2], static_cast<VT>(U::ax) };     }      static constexpr __m128 m128_premul(__m128 src) noexcept     {         if constexpr (not has_alpha()) return src;         constexpr auto ax = reinterpret_cast<__m128>(1.0f / V<4, float> { P::ax, P::ax, P::ax, 1 });         auto srca = _mm_setr_ps(src[3], src[3], src[3], 1);         src = _mm_mul_ps(src, srca);         src = _mm_mul_ps(src, ax);         return src;     }      static constexpr __m64 m64_premul(__m64 src) noexcept     {         if constexpr (not has_alpha()) return src;         auto a = _mm_shuffle_pi16(src, shuffle_mask(3, 3, 3, 3));         src = _mm_mullo_pi16(src, a);         if constexpr (P::ax == 3)         {             constexpr auto ax = vector_reciprocal<16, std::uint16_t, 15>(P::ax);             src = _mm_mulhi_pi16(src, reinterpret_cast<__m64>(ax));         }         else if constexpr (P::ax > 3)         {             constexpr auto ax = vector_reciprocal<17, std::uint16_t, 15>(P::ax);             src = _mm_mulhi_pi16(src, reinterpret_cast<__m64>(ax));             src = _mm_srli_pi16(_mm_adds_pu8(src, _mm_set1_pi16(1)), 1);         }         src = _mm_insert_pi16(src, a[0], 3);         return src;     }      template <typename VT>     static constexpr V<4, VT> vector_premul(V<4, VT> src) noexcept     {         if constexpr (not has_alpha()) return src;         auto a = V<4, VT> { src[3], src[3], src[3], 1 };         if constexpr (std::is_floating_point_v<VT>)         {             constexpr auto ax = 1.0f / V<4, float> { P::ax, P::ax, P::ax, 1 };             src *= a * ax;         }         else         {             constexpr auto rbits = (sizeof(VT) - 1) * 8;             constexpr auto ax = vector_reciprocal<rbits, VT>(P::ax, P::ax, P::ax, 1);             src *= a;             src *= ax;             src += 1 << (rbits - 1);             src >>= rbits;         }         return src;     }      template <typename U>     constexpr __m128 m128_blend(__m128 dst, __m128 src)     {         constexpr auto ax = reinterpret_cast<__m128>(1.0f / V<4, float> { U::ax, U::ax, U::ax, U::ax });         auto a = _mm_sub_ps(_mm_set1_ps(U::ax), _mm_set1_ps(src[3]));          if constexpr (not std::is_same_v<P, U>) src = pixel<U>::template m128_cast_to<P>(src);         dst = _mm_mul_ps(dst, a);         dst = _mm_mul_ps(dst, ax);         dst = _mm_add_ps(dst, src);         return dst;     }      template <typename U>     constexpr __m64 m64_blend(__m64 dst, __m64 src)     {         //auto a = _mm_sub_pi16(_mm_set1_pi16(U::ax), _mm_shuffle_pi16(src, shuffle_mask(3, 3, 3, 3)));         auto a = _mm_set1_pi16(U::ax - reinterpret_cast<V<4, std::uint16_t>>(src)[3]);          if constexpr (not std::is_same_v<P, U>) src = pixel<U>::template m64_cast_to<P>(src);         dst = _mm_mullo_pi16(dst, a);         if constexpr (U::ax == 3)         {             constexpr auto ax = vector_reciprocal<16, std::uint16_t, 15>(U::ax);             dst = _mm_mulhi_pi16(dst, reinterpret_cast<__m64>(ax));         }         else if constexpr (U::ax != 1)         {             constexpr auto ax = vector_reciprocal<17, std::uint16_t, 15>(U::ax);             dst = _mm_mulhi_pi16(dst, reinterpret_cast<__m64>(ax));             dst = _mm_srli_pi16(_mm_adds_pu8(dst, _mm_set1_pi16(1)), 1);         }         dst = _mm_adds_pu16(dst, src);         return dst;     }      template <typename U, typename VT>     static constexpr V<4, VT> vector_blend(V<4, VT> dst, V<4, VT> src) noexcept     {         if constexpr (not std::is_same_v<P, U>) src = pixel<U>::template vector_cast_to<P, VT>(src);         if constexpr (std::is_floating_point_v<VT>)         {             constexpr auto ax = 1.0f / U::ax;             dst *= static_cast<VT>(U::ax - src[3]) * ax;             dst += src;         }         else         {             constexpr auto rbits = (sizeof(VT) - 1) * 8;             constexpr auto ax = vector_reciprocal<rbits, VT>(U::ax);             dst *= static_cast<VT>(U::ax - src[3]);             dst *= ax;             dst += 1 << (rbits - 1);             dst >>= rbits;             dst += src;         }         return dst;     }      template<std::size_t bits, typename VT = std::uint16_t, std::size_t maxbits = bits>     static constexpr auto vector_reciprocal(VT v0, VT v1, VT v2, VT v3) noexcept     {         auto r = [](VT v) -> VT { return std::min(((1ul << bits) + v - 1) / v, (1ul << maxbits) - 1); };         return V<4, VT> { r(v0), r(v1), r(v2), r(v3)};     }      template<std::size_t bits, typename VT = std::uint16_t, std::size_t maxbits = bits>     static constexpr auto vector_reciprocal(VT v0) noexcept     {         return vector_reciprocal<bits, VT, maxbits>(v0, v0, v0, v0);     }      template<typename VT = float>     static constexpr auto vector_max(VT noalpha = 1) noexcept     {         return V<4, VT> { P::bx, P::gx, P::rx, static_cast<VT>(has_alpha() ? P::ax : noalpha) };     }      template<std::size_t bits, typename VT = std::uint16_t, std::size_t maxbits = bits>     static constexpr auto vector_max_reciprocal(VT noalpha = 1) noexcept     {         return vector_reciprocal<bits, VT, maxbits>(P::bx, P::gx, P::rx, static_cast<VT>(has_alpha() ? P::ax : noalpha));     }      template<typename T> constexpr bool is_constexpr(T value) { return __builtin_constant_p(value); }     static constexpr auto shuffle_mask(int v0, int v1, int v2, int v3) noexcept { return (v0 & 3) | ((v1 & 3) << 2) | ((v2 & 3) << 4) | ((v3 & 3) << 6); }     static constexpr bool byte_aligned() noexcept { return P::byte_aligned; } };  struct alignas(0x10) bgra_ffff {     using T = float;     T b, g, r, a;      static constexpr T rx = 1.0f;     static constexpr T gx = 1.0f;     static constexpr T bx = 1.0f;     static constexpr T ax = 1.0f;     static constexpr bool byte_aligned = false; };  struct alignas(0x10) bgra_fff0 {     using T = float;     T b, g, r;     unsigned : sizeof(float);      static constexpr T rx = 1.0f;     static constexpr T gx = 1.0f;     static constexpr T bx = 1.0f;     static constexpr T ax = 0.0f;     static constexpr bool byte_aligned = false; };  struct alignas(4) bgra_8888 {     using T = std::uint8_t;     T b, g, r, a;      static constexpr T rx = 255;     static constexpr T gx = 255;     static constexpr T bx = 255;     static constexpr T ax = 255;     static constexpr bool byte_aligned = true; };  struct [[gnu::packed]] alignas(4) bgra_8880 {     using T = std::uint8_t;     T b, g, r;     T : 8;      static constexpr T rx = 255;     static constexpr T gx = 255;     static constexpr T bx = 255;     static constexpr T ax = 0;     static constexpr bool byte_aligned = true; };  struct [[gnu::packed]] bgr_8880 {     using T = std::uint8_t;     T b, g, r;      static constexpr T rx = 255;     static constexpr T gx = 255;     static constexpr T bx = 255;     static constexpr T ax = 0;     static constexpr bool byte_aligned = true; };  struct [[gnu::packed]] bgra_6668 {     using T = unsigned;     T b : 6, : 2;     T g : 6, : 2;     T r : 6, : 2;     T a : 8;      constexpr bgra_6668(T vb, T vg, T vr, T va) noexcept : b(vb), g(vg), r(vr), a(va) { }      static constexpr T rx = 63;     static constexpr T gx = 63;     static constexpr T bx = 63;     static constexpr T ax = 255;     static constexpr bool byte_aligned = true; };  struct alignas(2) [[gnu::packed]] bgr_5650 {     using T = unsigned;     T b : 5;     T g : 6;     T r : 5;      static constexpr T rx = 31;     static constexpr T gx = 63;     static constexpr T bx = 31;     static constexpr T ax = 0;     static constexpr bool byte_aligned = false; };  struct alignas(2) [[gnu::packed]] bgra_5551 {     using T = unsigned;     T b : 5;     T g : 5;     T r : 5;     T a : 1;      static constexpr T rx = 31;     static constexpr T gx = 31;     static constexpr T bx = 31;     static constexpr T ax = 1;     static constexpr bool byte_aligned = false; };  struct alignas(2) [[gnu::packed]] bgra_5550 {     using T = unsigned;     T b : 5;     T g : 5;     T r : 5;     T : 1;      static constexpr T rx = 31;     static constexpr T gx = 31;     static constexpr T bx = 31;     static constexpr T ax = 0;     static constexpr bool byte_aligned = false; };  struct alignas(2)[[gnu::packed]] bgra_4444 {     using T = unsigned;     T b : 4;     T g : 4;     T r : 4;     T a : 4;      static constexpr T rx = 15;     static constexpr T gx = 15;     static constexpr T bx = 15;     static constexpr T ax = 15;     static constexpr bool byte_aligned = false; };  struct [[gnu::packed]] bgr_2330 {     using T = unsigned;     T b : 2;     T g : 3;     T r : 3;      static constexpr T rx = 7;     static constexpr T gx = 7;     static constexpr T bx = 3;     static constexpr T ax = 0;     static constexpr bool byte_aligned = false; };  struct [[gnu::packed]] bgra_2321 {     using T = unsigned;     T b : 2;     T g : 3;     T r : 2;     T a : 1;      static constexpr T rx = 3;     static constexpr T gx = 7;     static constexpr T bx = 3;     static constexpr T ax = 1;     static constexpr bool byte_aligned = false; };  struct[[gnu::packed]] bgra_2222 {     using T = unsigned;     T b : 2;     T g : 2;     T r : 2;     T a : 2;      static constexpr T rx = 3;     static constexpr T gx = 3;     static constexpr T bx = 3;     static constexpr T ax = 3;     static constexpr bool byte_aligned = false; };  using pxf    = pixel<bgra_ffff>;     // floating-point for use with SSE using pxfn   = pixel<bgra_fff0>;     // floating-point, no alpha using px32a  = pixel<bgra_8888>;     // 24-bit, 8-bit alpha channel using px32n  = pixel<bgra_8880>;     // 24-bit, no alpha, 4 bytes wide using px24   = pixel<bgr_8880>;      // 24-bit, 3 bytes wide using px16   = pixel<bgr_5650>;      // 16-bit, typical 5:6:5 format using px16a  = pixel<bgra_5551>;     // 15-bit with 1-bit alpha using px16n  = pixel<bgra_5550>;     // 15-bit, no alpha, equal 5:5:5 format using px16aa = pixel<bgra_4444>;     // 12-bit, 4-bit alpha, equal 4:4:4 format using px8aa  = pixel<bgra_2222>;     // 6-bit 2:2:2, 2-bit alpha using px8a   = pixel<bgra_2321>;     // 7-bit 2:3:2, 1-bit alpha using px8n   = pixel<bgr_2330>;      // 8-bit 3:3:2, no alpha using pxvga  = pixel<bgra_6668>;     // VGA DAC palette format  static_assert(sizeof(pxf   ) == 16); static_assert(sizeof(pxfn  ) == 16); static_assert(sizeof(px32a ) ==  4); static_assert(sizeof(px32n ) ==  4); static_assert(sizeof(px24  ) ==  3); static_assert(sizeof(px16  ) ==  2); static_assert(sizeof(px16aa) ==  2); static_assert(sizeof(px16a ) ==  2); static_assert(sizeof(px16n ) ==  2); static_assert(sizeof(px8aa ) ==  1); static_assert(sizeof(px8a  ) ==  1); static_assert(sizeof(px8n  ) ==  1); static_assert(sizeof(pxvga ) ==  4);  inline auto generate_px8n_palette() {     std::vector<px32n> result;     result.reserve(256);     for (auto i = 0; i < 256; ++i)         result.emplace_back(reinterpret_cast<px8n&>(i));     return result; } 
              

Lista de respuestas

5
 
vote

El código parece obtener cada vez más cuestionable a medida que leemos hacia abajo. Comenzando en la parte inferior:

  name_of_new_library6  
  • Escritura name_of_new_library7 en lugar de name_of_new_library8 no le ahorra mucho de nada.

  • Escribir name_of_new_library9 en lugar de ascii_lowercase0 en realidad pierde usted (en ambos caracteres y claridad).

    < / li>
  • usando ascii_lowercase1 parece completamente en desacuerdo con el resto de este código. ¿Por qué no dar ascii_lowercase2 un constructor adecuado de ascii_lowercase3 , eliminando así el comportamiento indefinido y haciendo que su código sea portátil para los sistemas de Big-Endian al mismo tiempo?


  ascii_lowercase4  
  • No soy un fanático de su estilo de espacio en blanco en ascii_lowercase5 .

  • En cualquier momento que establezca un montón de copias del mismo código una y otra vez con solo diferencias menores, debe intentar usar una plantilla . Apuesto a que podría reducir estas 150 líneas de código a aproximadamente 40 mediante la plantilla y un montón de typedefs como ascii_lowercase6 y así sucesivamente.


  ascii_lowercase7  

No entiendo por qué esta estructura que contiene solo los campos 99887766555443338 debe ser ascii_lowercase9 en absoluto.


  import tkinter from tkinter import simpledialog from string import ascii_lowercase, digits   def process_user_input(event):     name_of_new_library = simpledialog.askstring('Create New Note Library', 'Alphanumeric lowercase and "_" only',                                                  initialvalue="Name_Here").lower().replace(' ', '_')      valid_filename_chars = "{}{}_".format(ascii_lowercase, digits)     final_name = ''     for character in name_of_new_library:         if character in valid_filename_chars:             final_name += character      return final_name if final_name else 'custom_name'   if __name__ == '__main__':     root = tkinter.Tk()     print(process_user_input(root)) 0  

Aquí, sugiero que import tkinter from tkinter import simpledialog from string import ascii_lowercase, digits def process_user_input(event): name_of_new_library = simpledialog.askstring('Create New Note Library', 'Alphanumeric lowercase and "_" only', initialvalue="Name_Here").lower().replace(' ', '_') valid_filename_chars = "{}{}_".format(ascii_lowercase, digits) final_name = '' for character in name_of_new_library: if character in valid_filename_chars: final_name += character return final_name if final_name else 'custom_name' if __name__ == '__main__': root = tkinter.Tk() print(process_user_input(root)) 1 sería un nombre más apropiado más apropiado que import tkinter from tkinter import simpledialog from string import ascii_lowercase, digits def process_user_input(event): name_of_new_library = simpledialog.askstring('Create New Note Library', 'Alphanumeric lowercase and "_" only', initialvalue="Name_Here").lower().replace(' ', '_') valid_filename_chars = "{}{}_".format(ascii_lowercase, digits) final_name = '' for character in name_of_new_library: if character in valid_filename_chars: final_name += character return final_name if final_name else 'custom_name' if __name__ == '__main__': root = tkinter.Tk() print(process_user_input(root)) 2 . (O bien, puede usar un nombre más detallado, como import tkinter from tkinter import simpledialog from string import ascii_lowercase, digits def process_user_input(event): name_of_new_library = simpledialog.askstring('Create New Note Library', 'Alphanumeric lowercase and "_" only', initialvalue="Name_Here").lower().replace(' ', '_') valid_filename_chars = "{}{}_".format(ascii_lowercase, digits) final_name = '' for character in name_of_new_library: if character in valid_filename_chars: final_name += character return final_name if final_name else 'custom_name' if __name__ == '__main__': root = tkinter.Tk() print(process_user_input(root)) 3 en primer lugar. De cualquier manera, intente eliminar el paralelismo engañoso entre import tkinter from tkinter import simpledialog from string import ascii_lowercase, digits def process_user_input(event): name_of_new_library = simpledialog.askstring('Create New Note Library', 'Alphanumeric lowercase and "_" only', initialvalue="Name_Here").lower().replace(' ', '_') valid_filename_chars = "{}{}_".format(ascii_lowercase, digits) final_name = '' for character in name_of_new_library: if character in valid_filename_chars: final_name += character return final_name if final_name else 'custom_name' if __name__ == '__main__': root = tkinter.Tk() print(process_user_input(root)) 4 y import tkinter from tkinter import simpledialog from string import ascii_lowercase, digits def process_user_input(event): name_of_new_library = simpledialog.askstring('Create New Note Library', 'Alphanumeric lowercase and "_" only', initialvalue="Name_Here").lower().replace(' ', '_') valid_filename_chars = "{}{}_".format(ascii_lowercase, digits) final_name = '' for character in name_of_new_library: if character in valid_filename_chars: final_name += character return final_name if final_name else 'custom_name' if __name__ == '__main__': root = tkinter.Tk() print(process_user_input(root)) 5 .)


  import tkinter from tkinter import simpledialog from string import ascii_lowercase, digits   def process_user_input(event):     name_of_new_library = simpledialog.askstring('Create New Note Library', 'Alphanumeric lowercase and "_" only',                                                  initialvalue="Name_Here").lower().replace(' ', '_')      valid_filename_chars = "{}{}_".format(ascii_lowercase, digits)     final_name = ''     for character in name_of_new_library:         if character in valid_filename_chars:             final_name += character      return final_name if final_name else 'custom_name'   if __name__ == '__main__':     root = tkinter.Tk()     print(process_user_input(root)) 6  

Este uso de import tkinter from tkinter import simpledialog from string import ascii_lowercase, digits def process_user_input(event): name_of_new_library = simpledialog.askstring('Create New Note Library', 'Alphanumeric lowercase and "_" only', initialvalue="Name_Here").lower().replace(' ', '_') valid_filename_chars = "{}{}_".format(ascii_lowercase, digits) final_name = '' for character in name_of_new_library: if character in valid_filename_chars: final_name += character return final_name if final_name else 'custom_name' if __name__ == '__main__': root = tkinter.Tk() print(process_user_input(root)) 7 no es válido C ++ 17 (ni se espera que actualmente sea válido C ++ 20). ¿No debería GCC le ha dado una advertencia sobre esto? Recopila con al menos import tkinter from tkinter import simpledialog from string import ascii_lowercase, digits def process_user_input(event): name_of_new_library = simpledialog.askstring('Create New Note Library', 'Alphanumeric lowercase and "_" only', initialvalue="Name_Here").lower().replace(' ', '_') valid_filename_chars = "{}{}_".format(ascii_lowercase, digits) final_name = '' for character in name_of_new_library: if character in valid_filename_chars: final_name += character return final_name if final_name else 'custom_name' if __name__ == '__main__': root = tkinter.Tk() print(process_user_input(root)) 8 , a los cuales algunos agregan (pero otros no) import tkinter from tkinter import simpledialog from string import ascii_lowercase, digits def process_user_input(event): name_of_new_library = simpledialog.askstring('Create New Note Library', 'Alphanumeric lowercase and "_" only', initialvalue="Name_Here").lower().replace(' ', '_') valid_filename_chars = "{}{}_".format(ascii_lowercase, digits) final_name = '' for character in name_of_new_library: if character in valid_filename_chars: final_name += character return final_name if final_name else 'custom_name' if __name__ == '__main__': root = tkinter.Tk() print(process_user_input(root)) 9 .


  lower0  

DOS COSAS:

  • ¿Cuál es el propósito de lower1 ? Desde el nombre, podría pensar que se pretendía que era una forma inteligente de forzar el 99887766655443352 para que se evalúe en tiempo de ejecución, excepto por ese lower3 está explícitamente marcado lower4 (Entonces, el compilador definitivamente conoce su valor en el tiempo de compilación), y que la prueba completa se adjunta en lower5 lo que significa que debe evaluado en el tiempo de compilación.

  • como Linus una vez dicho , lower6 .


  lower7  

IIUC, lower8 < / a> es la forma de señalar al procesador que se ha hecho haciendo las cosas MMX por un rato. Realmente no entiendo por qué o cuando necesitarías escribirlo explícitamente en el código de C ++, pero supongamos que tiene razón que necesita hacer aquí.

¿Gardaría más sentido para expresarlo como un objeto RAII que se crea antes de comenzar a hacer las cosas MMX, quizás haya pasado a cada operación MMX como parámetro, y luego destruido automáticamente al final de ¿El cálculo de MMX? Entonces, en la práctica, su código anterior podría verse algo así después de RaiIfin:

  lower9  

  replace0  
  • Todos sus constructores podrían marcarse de manera productiva replace1 (Para evitar que las personas construyan accidentalmente a través de un 99887766555443362 , por ejemplo).

  • Si tuviera que elegir un nombre mnemónico corto para replace3 , el nombre 99887766555443364 no sería mi primera opción.

  • IIUC, los tres parámetros de la plantilla aquí tienen tres propósitos diferentes: uno ( 998877766555443365 ) es solo una mnemotécnica de conveniencia, se está utilizando uno para Sfinae, y el último (código> 99887766555443366 ) es solo un detalle de implementación de la SFINAE. ninguno de ellos está destinado a participar en realidad en la deducción de tipo de plantilla. Así que creo que este código es mucho más confuso de lo que debe ser.

  • estilo trivial nit: 99887766555443367 es más corta y, por lo tanto, más fácil en los ojos que replace8 .

P> Así que lo escribiría así:
  replace9  

Esta versión, por supuesto, elimina el valid_filename_chars0 S que estaba haciendo para suprimir las advertencias (o errores) que resultan de la reducción de las conversiones en la lista de inicializadores pulsados. Si realmente necesita realmente esas conversiones de estrechamiento que sucedan, entonces debe compensar una forma conveniente de deletrear valid_filename_chars1 â € "lo que ya tendría, excepto que ha tomado la decisión sumamente confusa de que 99887766555443372 debe ser un tipo diferente de valid_filename_chars3 .

La solución fácil pero no quirúrgica sería revertir esa decisión: reemplazar su

  valid_filename_chars4  

con

  valid_filename_chars5  

y luego haz las sustituncias obvias en todo:

  valid_filename_chars6  

La solución más quirúrgica, pero innecesariamente antagonista a su mantenedor sería

  valid_filename_chars7  

 

The code seems to get more and more questionable as we read downward. Starting at the bottom:

inline auto generate_px8n_palette() {     std::vector<px32n> result;     result.reserve(256);     for (auto i = 0; i < 256; ++i)         result.emplace_back(reinterpret_cast<px8n&>(i));     return result; } 
  • Writing auto instead of explicitly std::vector<px32n> doesn't save you much of anything.

  • Writing auto i = 0 instead of int i = 0 actually loses you something (in both character count and clarity).

  • Using reinterpret_cast<px8n&>(i) seems completely at odds with the rest of this code. Why not give px8n a proper constructor from int, thus eliminating the undefined behavior and making your code portable to big-endian systems at the same time?


struct[[gnu::packed]] bgra_2222 {     using T = unsigned;     T b : 2;     T g : 2;     T r : 2;     T a : 2;      static constexpr T rx = 3;     static constexpr T gx = 3;     static constexpr T bx = 3;     static constexpr T ax = 3;     static constexpr bool byte_aligned = false; }; 
  • I'm not a fan of your whitespace style in struct[[gnu::packed]].

  • Anytime you're stamping out a bunch of copies of the same code over and over with only minor differences, you should try to use a template. I bet you could reduce these 150 lines of code to about 40 by using a template and a bunch of typedefs like using bgra_2222 = bgra<2,2,2,2,false>; and so on.


struct [[gnu::packed]] bgr_8880 

I don't understand why this struct containing only uint8_t fields needs to be [[gnu::packed]] at all.


constexpr auto ax = vector_reciprocal<rbits, VT>(P::ax, P::ax, P::ax, 1); src *= a; src *= ax; 

Here, I suggest that one_over_ax would be a much more appropriate name than ax. (Or, you could use a more verbose name such as P::max_alpha in the first place. Either way, try to eliminate the misleading parallelism between P::ax and ax.)


static constexpr pixel m64(auto value) noexcept // V4HI 

This use of auto is not valid C++17 (nor is it currently expected to be valid C++20). Shouldn't GCC have given you a warning about this? Compile with at least -std=c++17 -W -Wall, to which some add (but others do not) -Wextra -pedantic.


constexpr bool not_constexpr = true;// not is_constexpr(this->b); if constexpr (not_constexpr and sse and (std::is_floating_point_v<typename P::T> or std::is_floating_point_v<typename U::T>))     // ... else if constexpr (not_constexpr and mmx and (sse or (std::is_integral_v<typename P::T> and std::is_integral_v<typename U::T>))) 

Two things:

  • What is the purpose of not_constexpr? From the name, I might think that it was intended as a clever way to force the if to be evaluated at runtime not compile-time, except for that not_constexpr is explicitly marked constexpr (so the compiler definitely knows its value at compile-time), and that the entire test is enclosed in if constexpr which means it must be evaluated at compile-time.

  • As Linus once said, -EEXPRESSIONTOOCOMPLICATEDTOLIVE.


*this = m128(m128_blend<U>(m128(), other.m128())); if constexpr (std::is_integral_v<typename U::T>) _mm_empty(); 

IIUC, _mm_empty() is the way to signal to the processor that you're done doing MMX things for a little while. I don't really understand why or when you'd need to write it explicitly in C++ code, but let's assume that you're right that it needs doing here.

Would it make more sense to express it as an RAII object that is created before you start doing MMX things, perhaps passed to each MMX operation as a parameter, and then destroyed automatically at the end of the MMX computation? So in practice your code above might look something like this after RAIIfication:

MMXComputationIf<std::is_integral_v<typename U::T>> guard; *this = m128(m128_blend<U>(m128(), other.m128())); 

template<typename U = P, typename PT = typename U::T, std::enable_if_t<pixel<U>::has_alpha(), bool> = { }> constexpr pixel(T cr, T cg, T cb, T ca) noexcept : P { static_cast<PT>(cb), static_cast<PT>(cg), static_cast<PT>(cr), static_cast<PT>(ca) } { } 
  • All your constructors could productively be marked explicit (to prevent people from accidentally constructing them via unadorned {1,2,3,4}, for example).

  • If I had to pick a short mnemonic name for typename U::T, the name PT would not be my first choice.

  • IIUC, the three template parameters here have three different purposes: one (PT) is just a convenience mnemonic, one is actually being used for SFINAE, and the last (U) is just an implementation detail of the SFINAE. None of them are meant to actually participate in template type deduction. So I think this code is much more confusing than it ought to be.

  • Trivial style nit: class is shorter and thus easier on the eyes than typename.

So I would write it like this:

template<class P_ = pixel, class = std::enable_if_t<P_::has_alpha()>> constexpr pixel(T cr, T cg, T cb, T ca) noexcept :     P { cb, cg, cr, ca } {} 

This version of course eliminates the static_casts which you were doing to suppress warnings (or errors) resulting from narrowing conversions in the braced initializer-list. If you really really need those narrowing conversions to happen, then you should make up a convenient way to spell static_cast<typename P::T> xe2x80x94 which you would already have, except that you have made the supremely confusing decision that pixel<P>::T should be a different type from P::T.

The easy but non-surgical solution would be to reverse that decision: replace your

using T = std::conditional_t<std::is_integral_v<typename P::T>, unsigned, typename P::T>; 

with

using T = typename P::T; using unsigned_or_T = std::conditional_t<std::is_integral_v<T>, unsigned, T>; 

and then make the obvious substitions throughout:

template<class P_ = pixel, class = std::enable_if_t<P_::has_alpha()>> constexpr pixel(unsigned_or_T cr, unsigned_or_T cg, unsigned_or_T cb, unsigned_or_T ca) noexcept :     P { T(cb), T(cg), T(cr), T(ca) } {} 

The more surgical but needlessly-antagonistic-to-your-maintainer solution would be

using T = std::conditional_t<std::is_integral_v<typename P::T>, unsigned, typename P::T>;  static constexpr inline PTcast(T t) noexcept {     return static_cast<typename P::T>(t); }  template<class P_ = pixel, class = std::enable_if_t<P_::has_alpha()>> constexpr pixel(T cr, T cg, T cb, T ca) noexcept :     P { PTcast(cb), PTcast(cg), PTcast(cr), PTcast(ca) } {} 
 
 
         
         

Relacionados problema

3  Tratando de mejorar y entender mejor Intel SSE intrínsecos  ( Trying to improve and better understand intel sse intrinsics ) 
He estado escribiendo una colección de función de procesamiento de señales optimizada con intrínsecos SSE (principalmente para el procesamiento de audio). Aqu...

6  Optimización de la multiplicación de matrices cuadradas para la utilización completa de la CPU  ( Optimizing multiplication of square matrices for full cpu utilization ) 
problema Estoy aprendiendo sobre HPC y optimización de código. Intento replicar los resultados en Papel de multiplicación de matriz seminal de GoTo . A p...

0  Encontrar el valor mínimo y máximo en una imagen  ( Finding the minimum and maximum value in an image ) 
Dada una imagen que se acolee para admitir alineación (SSE), necesito encontrar su valor mínimo y máximo lo más rápido posible. Se importa que los valores ac...

4  Optimización de SSE para remuestreo de audio [cerrado]  ( Sse optimisation for audio resampling ) 
cerrado. Esta pregunta es off-topic . Actualmente no está aceptando respuestas. ¿Quieres ...

3  Extracción de parches bilineares de grises - optimización SSE  ( Grayscale bilinear patch extraction sse optimization ) 
MI PROGRAMA Hace un uso intensivo de pequeñas sub-imágenes extraídas usando la interpolación bilineal de imágenes en escala de grises más grandes (algunos lla...

6  Convertir la matriz de flotadores a uint8 (`char`) o uint16 ('no firmado corto') usando SSE4  ( Converting array of floats to uint8 char or uint16 unsigned short using ) 
El problema se le da la imagen en formato de punto flotante de 32 bits ( float3 ) Cómo convertirlo a uint8 ( 99887776655443344 ) o unidad16 ( 9988777665544333...

7  AVX SIMD EN MULTIPLICACIÓN DE MATRIX  ( Avx simd in matrix multiplication ) 
He codificado la siguiente función C para multiplicar dos matrices NXN y usar vectores AVX para acelerar el cálculo. Funciona, pero la aceleración no es lo qu...

9  Convolución de imagen vectorizada y multi roscada  ( Vectorized and multi threaded image convolution ) 
He creado un código para imagen convolución . El código está en mi Imagen de la imagen del repositorio de GitHub . Incluye el caso de arbitrario Imagen d...

4  ¿Este programa C ++ se implementa correctamente en SSE?  ( Is this c program correctly implemented in sse ) 
Tengo que implementar un programa simple en SSE, y no sé si lo he hecho de la manera correcta (es mi primer programa en SSE). Este es el programa C ++: d...

4  4 × 4 Cofactor en SSE  ( 4%c3%974 cofactor in sse ) 
El cofactor de una matriz 4Ã-4 se puede usar para convertir una matriz "geometría regular" en la matriz que transforma las normales. Es una alternativa al pat...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos