/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ /*========================================================================= * * Portions of this file are subject to the VTK Toolkit Version 3 copyright. * * Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen * * For complete copyright, license and disclaimer of warranty information * please refer to the NOTICE file at the top of the ITK source tree. * *=========================================================================*/ #ifndef itkConceptChecking_h #define itkConceptChecking_h #include "itkPixelTraits.h" #include "itkNumericTraits.h" #include /** Choose a concept checking implementation based on compiler abilities. */ #ifndef ITK_CONCEPT_NO_CHECKING # if defined(_MSC_VER) && !defined(__ICL) # define ITK_CONCEPT_IMPLEMENTATION_VTABLE // TST_RMV_20100730 #elif defined(__SUNPRO_CC) // TST_RMV_20100730 #define ITK_CONCEPT_IMPLEMENTATION_VTABLE # else # define ITK_CONCEPT_IMPLEMENTATION_STANDARD # endif #endif /** Define the concept checking implementation chosen above. */ #if defined(ITK_CONCEPT_IMPLEMENTATION_STANDARD) /** * Standard instantiation-time concept check. No run-time overhead * introduced. This implementation is based on "Concept Checking: * Binding Parametric Polymorphism in C++" by Jeremy Siek and Andrew * Lumsdaine, University of Notre Dame. */ // Leave ()'s off the sizeof to force the caller to pass them in the // concept argument of the itkConceptMacro. This is necessary because // the argument may contain commas. # define itkConceptConstraintsMacro() \ template \ struct Enforcer \ {}; \ using EnforcerInstantiation = Enforcer<&Constraints::constraints>; \ ITK_MACROEND_NOOP_STATEMENT # define itkConceptMacro(name, concept) \ enum \ { \ name = sizeof concept \ }; \ ITK_MACROEND_NOOP_STATEMENT #elif defined(ITK_CONCEPT_IMPLEMENTATION_VTABLE) /** * Alternate implementation for some compilers. This introduces no * run-time overhead. The "vtable" approach was invented for this * project by Brad King at Kitware. */ # define itkConceptConstraintsMacro() \ virtual void Enforcer() { &Constraints::constraints; } # define itkConceptMacro(name, concept) \ enum \ { \ name = sizeof concept \ } #elif defined(ITK_CONCEPT_IMPLEMENTATION_CALL) /** Not implemented. */ # define itkConceptConstraintsMacro() # define itkConceptMacro(name, concept) \ enum \ { \ name = 0 \ } #else /** Disable concept checking. */ # define itkConceptConstraintsMacro() # define itkConceptMacro(name, concept) \ enum \ { \ name = 0 \ } #endif namespace itk { /** All concept class definitions are contained in the "itk::Concept" namespace. */ namespace Concept { /** * Some concept implementation details are adapted from the BOOST C++ * libraries (www.boost.org). These are marked with "(BOOST)" in the * corresponding comment. */ /** Namespace containing concept check implementation details. */ namespace Detail { template struct UniqueType {}; template struct UniqueType_int {}; template struct UniqueType_unsigned_int {}; template struct UniqueType_bool {}; /** * Concept checks may require a variable to be declared but not used. * This function can be called with the variable to prevent the compiler * warning. (BOOST) */ template inline void IgnoreUnusedVariable(T) {} /** * Concept checks may require that an expression be convertible to bool. * Passing the expression to this function will enforce this requirement. * (BOOST) */ template void RequireBooleanExpression(const T & t) { bool x = t; IgnoreUnusedVariable(x); } } // namespace Detail /** Concept requiring T to have a default constructor. (BOOST) */ template struct DefaultConstructible { struct Constraints { void constraints() { T a; Detail::IgnoreUnusedVariable(a); } }; itkConceptConstraintsMacro(); }; /** Concept requiring T to have a copy constructor. (BOOST) */ template struct CopyConstructible { struct Constraints { void constraints() { T a(b); T * p = &a; const_constraints(a); Detail::IgnoreUnusedVariable(p); } void const_constraints(const T & a) { T c(a); const T * p = &a; Detail::IgnoreUnusedVariable(c); Detail::IgnoreUnusedVariable(p); } T b; }; itkConceptConstraintsMacro(); }; /** Concept requiring T1 to be convertible to T2. (BOOST) */ template struct Convertible { struct Constraints { void constraints() { auto b = static_cast(a); Detail::IgnoreUnusedVariable(b); } T1 a; }; itkConceptConstraintsMacro(); }; /** Concept requiring T to have operator =. (BOOST) */ template struct Assignable { struct Constraints { void constraints() { T x = a; const_constraints(x); } void const_constraints(const T & b) { a = b; } T a; }; itkConceptConstraintsMacro(); }; /** Concept requiring T1 to have operators < and <= with a right-hand operator of type T2. (BOOST) */ template struct LessThanComparable { struct Constraints { void constraints() { Detail::RequireBooleanExpression(a < b); Detail::RequireBooleanExpression(a <= b); } T1 a; T2 b; }; itkConceptConstraintsMacro(); }; /** Concept requiring T1 to have operators > and >= with a right-hand operator of type T2. (BOOST) */ template struct GreaterThanComparable { struct Constraints { void constraints() { Detail::RequireBooleanExpression(a > b); Detail::RequireBooleanExpression(a >= b); } T1 a; T2 b; }; itkConceptConstraintsMacro(); }; /** Concept requiring T1 to have operators == and != with a right-hand operator of type T2. (BOOST) */ template struct EqualityComparable { struct Constraints { void constraints() { CLANG_PRAGMA_PUSH CLANG_SUPPRESS_Wfloat_equal Detail::RequireBooleanExpression(a == b); Detail::RequireBooleanExpression(a != b); CLANG_PRAGMA_POP } T1 a; T2 b; }; itkConceptConstraintsMacro(); }; /** Concept requiring T1 to have operators <, >, <=, >=, ==, != with a right-hand operator of type T2. (BOOST) */ template struct Comparable { struct Constraints { void constraints() { Detail::RequireBooleanExpression(a < b); Detail::RequireBooleanExpression(a > b); Detail::RequireBooleanExpression(a <= b); Detail::RequireBooleanExpression(a >= b); CLANG_PRAGMA_PUSH CLANG_SUPPRESS_Wfloat_equal Detail::RequireBooleanExpression(a == b); Detail::RequireBooleanExpression(a != b); CLANG_PRAGMA_POP } T1 a; T2 b; }; itkConceptConstraintsMacro(); }; /** Concept requiring T1 to have operators +, -, in the form T1 op T2 = T3. */ template struct AdditiveOperators { struct Constraints { void constraints() { a = static_cast(b + c); a = static_cast(b - c); const_constraints(b, c); } void const_constraints(const T1 & d, const T2 & e) { a = static_cast(d + e); a = static_cast(d - e); } T3 a; T1 b; T2 c; }; itkConceptConstraintsMacro(); }; /** Concept requiring T1 to have operators +=, -= in the form T2 op= T1. */ template struct AdditiveAndAssignOperators { struct Constraints { void constraints() { a += c; a -= c; const_constraints(c); } void const_constraints(const T1 & d) { a += d; a -= d; } T2 a; T1 c; }; itkConceptConstraintsMacro(); }; /** Concept requiring T to have operator * in the form T1 op T2 = T3. */ template struct MultiplyOperator { struct Constraints { void constraints() { a = static_cast(b * c); const_constraints(b, c); } void const_constraints(const T1 & d, const T2 & e) { a = static_cast(d * e); } T3 a; T1 b; T2 c; }; itkConceptConstraintsMacro(); }; /** Concept requiring T to have operator *= in the form T2 op= T1. */ template struct MultiplyAndAssignOperator { struct Constraints { void constraints() { a *= b; const_constraints(b); } void const_constraints(const T1 & d) { a *= d; } T2 a; T1 b; }; itkConceptConstraintsMacro(); }; /** Concept requiring T to have operators / the form T1 op T2 = T3. */ template struct DivisionOperators { struct Constraints { void constraints() { a = static_cast(b / c); const_constraints(b, c); } void const_constraints(const T1 & d, const T2 & e) { a = static_cast(d / e); } T3 a; T1 b; T2 c; }; itkConceptConstraintsMacro(); }; /** Concept requiring T to have operators /= in the form T2 op= T1. */ template struct DivisionAndAssignOperators { struct Constraints { void constraints() { a /= c; const_constraints(c); } void const_constraints(const T1 & d) { a /= d; } T1 c; T2 a; }; itkConceptConstraintsMacro(); }; /** Concept requiring T1 to have operators &, |, and ^ in the form T1 op T2 = T3. */ template struct BitwiseOperators { struct Constraints { void constraints() { a = static_cast(b & c); a = static_cast(b | c); a = static_cast(b ^ c); a &= static_cast(c); a |= static_cast(c); a ^= static_cast(c); const_constraints(b, c); } void const_constraints(const T1 & d, const T2 & e) { a = static_cast(d & e); a = static_cast(d | e); a = static_cast(d ^ e); a &= static_cast(e); a |= static_cast(e); a ^= static_cast(e); } T3 a; T1 b; T2 c; }; itkConceptConstraintsMacro(); }; /** Concept requiring T1 to have operators [] in the form T1 [] T2 = T3. */ template struct BracketOperator { struct Constraints { void constraints() { a = static_cast(b[c]); const_constraints(b, c); } void const_constraints(const T1 & d, const T2 & e) { a = static_cast(d[e]); } T3 a; T1 b; T2 c; }; itkConceptConstraintsMacro(); }; /** Concept requiring T to have operator !. */ template struct NotOperator { struct Constraints { void constraints() { a = !a; } T a; }; itkConceptConstraintsMacro(); }; /** Concept requiring T to have operators ++ and --. */ template struct IncrementDecrementOperators { struct Constraints { void constraints() { a++; a--; ++a; --a; } T a; }; itkConceptConstraintsMacro(); }; /** Concept requiring T to be writable to an ostream. */ template struct OStreamWritable { struct Constraints { void constraints() { std::cout << a; } T a; }; itkConceptConstraintsMacro(); }; /** Concept requiring T to be signed. */ template struct Signed { using Self = Signed; static constexpr bool IsSigned = NumericTraits::is_signed; struct Constraints { using TrueT = Detail::UniqueType_bool; using SignedT = Detail::UniqueType_bool; void constraints() { SignedT a = TrueT(); Detail::IgnoreUnusedVariable(a); } }; itkConceptConstraintsMacro(); }; /** Concept requiring T1 and T2 to be the same type. */ template struct SameType { struct Constraints { void constraints() { Detail::UniqueType a = Detail::UniqueType(); Detail::IgnoreUnusedVariable(a); } }; itkConceptConstraintsMacro(); }; /** Concept requiring D1 and D2 to be the same dimension. */ template struct SameDimension { struct Constraints { using DT1 = Detail::UniqueType_unsigned_int; using DT2 = Detail::UniqueType_unsigned_int; void constraints() { DT1 a = DT2(); Detail::IgnoreUnusedVariable(a); } }; itkConceptConstraintsMacro(); }; /** Concept requiring T to have NumericTraits */ template struct HasNumericTraits { struct Constraints { void constraints() { Detail::UniqueType::ValueType>(); Detail::UniqueType::PrintType>(); Detail::UniqueType::AbsType>(); Detail::UniqueType::AccumulateType>(); Detail::UniqueType::RealType>(); Detail::UniqueType::ScalarRealType>(); Detail::UniqueType::FloatType>(); T a{}; // Test these methods that take an instance of T to // allow for types with variable length. a = NumericTraits::NonpositiveMin(a); a = NumericTraits::ZeroValue(a); a = NumericTraits::OneValue(a); bool b = NumericTraits::IsPositive(a); b &= NumericTraits::IsNonpositive(a); b &= NumericTraits::IsNegative(a); b &= NumericTraits::IsNonnegative(a); Detail::IgnoreUnusedVariable(a); Detail::IgnoreUnusedVariable(b); } }; itkConceptConstraintsMacro(); }; /** Concept requiring T to have PixelTraits */ template struct HasPixelTraits { struct Constraints { void constraints() { Detail::UniqueType::ValueType>(); unsigned int a = PixelTraits::Dimension; Detail::IgnoreUnusedVariable(a); } }; itkConceptConstraintsMacro(); }; /** Concept requiring T to have a trait called ValueType */ template struct HasValueType { struct Constraints { void constraints() { Detail::UniqueType(); } }; itkConceptConstraintsMacro(); }; /** Concept requiring T to have Zero */ template struct HasZero { struct Constraints { void constraints() { T a; a = T{}; Detail::IgnoreUnusedVariable(a); } }; itkConceptConstraintsMacro(); }; /** Concept requiring T to have JoinTraits */ template struct HasJoinTraits { struct Constraints { void constraints() { Detail::UniqueType::ValueType>(); } }; itkConceptConstraintsMacro(); }; /** Concept requiring D1 and D2 to be the same dimension or D1-1 = D2. */ template struct SameDimensionOrMinusOne { struct Constraints { using Type1 = Detail::UniqueType_unsigned_int; using Type2 = Detail::UniqueType_unsigned_int; void f(Type1) {} void f(Type2, int = 0) {} void constraints() { Detail::UniqueType_unsigned_int tt; this->f(tt); } }; itkConceptConstraintsMacro(); }; /** Concept requiring D1 and D2 to be the same dimension, D1-1 = D2 or D1-2 = D2. */ template struct SameDimensionOrMinusOneOrTwo { struct Constraints { using Type1 = Detail::UniqueType_unsigned_int; using Type2 = Detail::UniqueType_unsigned_int; using Type3 = Detail::UniqueType_unsigned_int; void f(Type1) {} void f(Type2, int = 0) {} void f(Type3, int = 0, int = 0) {} void constraints() { Detail::UniqueType_unsigned_int tt; this->f(tt); } }; itkConceptConstraintsMacro(); }; /** Concept requiring T to be integer. */ template struct IsInteger { using Self = IsInteger; static constexpr bool Integral = std::is_integral_v; struct Constraints { using TrueT = Detail::UniqueType_bool; using IntegralT = Detail::UniqueType_bool; void constraints() { IntegralT a = TrueT(); Detail::IgnoreUnusedVariable(a); } }; itkConceptConstraintsMacro(); }; /** Concept requiring T to be an unsigned integer. */ template struct IsUnsignedInteger { using Self = IsUnsignedInteger; static constexpr bool Unsigned = !NumericTraits::is_signed; struct Constraints { using TrueT = Detail::UniqueType_bool; using UnsignedT = Detail::UniqueType_bool; void constraints() { UnsignedT a = TrueT(); Detail::IgnoreUnusedVariable(a); } }; itkConceptConstraintsMacro(); }; /** Concept requiring T to be non-integer. */ template struct IsNonInteger { using Self = IsNonInteger; static constexpr bool NonIntegral = std::is_integral_v; struct Constraints { using FalseT = Detail::UniqueType_bool; using NonIntegralT = Detail::UniqueType_bool; void constraints() { NonIntegralT a = FalseT(); Detail::IgnoreUnusedVariable(a); } }; itkConceptConstraintsMacro(); }; /** Concept requiring T to be floating point. */ template struct IsFloatingPoint { using Self = IsFloatingPoint; static constexpr bool Integral = std::is_integral_v; static constexpr bool IsExact = std::numeric_limits::ValueType>::is_exact; struct Constraints { using FalseT = Detail::UniqueType_bool; using IntegralT = Detail::UniqueType_bool; using ExactT = Detail::UniqueType_bool; void constraints() { IntegralT a = FalseT(); ExactT b = FalseT(); Detail::IgnoreUnusedVariable(a); Detail::IgnoreUnusedVariable(b); } }; itkConceptConstraintsMacro(); }; /** Concept requiring T to be fixed point. */ template struct IsFixedPoint { using Self = IsFixedPoint; static constexpr bool Integral = std::is_integral_v; static constexpr bool IsExact = std::numeric_limits::ValueType>::is_exact; struct Constraints { using TrueT = Detail::UniqueType_bool; using FalseT = Detail::UniqueType_bool; using IntegralT = Detail::UniqueType_bool; using ExactT = Detail::UniqueType_bool; void constraints() { IntegralT a = FalseT(); ExactT b = TrueT(); Detail::IgnoreUnusedVariable(a); Detail::IgnoreUnusedVariable(b); } }; itkConceptConstraintsMacro(); }; } // end namespace Concept } // end namespace itk #endif