-
-
Notifications
You must be signed in to change notification settings - Fork 55.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
int to proper enum type #12288
int to proper enum type #12288
Conversation
Use 'CamelCase' for types / enums. All capitals letters are reserved for macro / constants itself. BTW, This is not regular (simple) enum. This is "bit-set" enum, for example: |
adafff3
to
2e2892d
Compare
Some design work is required to resolve "enum" handling. Enum categoriesI see these classes of enums used in OpenCV:
Handling enums in Python.Currently all enums are "int" contants in Python. This approach is not safe and error prone. Unfortunately, only Python 3.6+ have "native" enum types:
We should emulate this for other Python versions somehow. Usage compatibility between C++ and PythonIn C++ enum type is not used for accessing of enum value (added to namespace/class): So probably we should duplicate enum values into current module to save compatibility with existed Python code and keep similarity between C++/Python code:
|
|
8fd21a8
to
1cf6d48
Compare
Thanks for revisiting enums for OpenCV 4 this was bothering me too.
some of those enums in classes are there for encapsulation. However they seem to cause problems for Python wrapper (#10681). Could this be supported for wrapping? Should those enums be moved to be consistent with rest of the OpenCV?
Python enums are basically
I can't see why that should cause any issues for Eigen. What was the exact error? If possible, I think introducing this operator for "flags" enums like this would be quite an easy and backward-compatible way. Of cause wrap this in macro, so we can easily add it for enums that need it. Like |
@@ -63,6 +63,16 @@ namespace cv | |||
//! @addtogroup core_basic | |||
//! @{ | |||
|
|||
//////////////////////////////// Enum operators ////////////////////////////// | |||
|
|||
template<typename T, typename std::enable_if< std::is_enum<T>::value >::type* = nullptr> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe consider adding this only for "flags" enums on per-enum basis. For "mode" enums this does not make sense. It could confuse users to use this to pass OR-ed values where it should not be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also operator | ()
is needed too.
If I define: template<typename T, typename std::enable_if< std::is_enum<T>::value >::type* = nullptr>
static T operator|(const T& a, const T& b)
{
typedef typename std::underlying_type<T>::type EnumType;
return static_cast<T>(static_cast<EnumType>(a) | static_cast<EnumType>(b));
} Then the following errors occurs, and while I can manage the first bullet, I do not know how to fix the second:
|
1cf6d48
to
a69f060
Compare
Just don't use templates. Separate operator definition for each "flags" enum, something like this:
I like this idea to declare multiple operators. |
that seems to be the same issue. constexpr should fix that. However, I think it is not a good idea to declare templated @alalek exactly! |
a69f060
to
80d8839
Compare
To resolve To be specific:
(you should add more operators for &, |=, &= etc.) Then declare
constexpr allows to use the operator in constant expressions. This approach allows us to declare the operator only for enums where it makes sense. BTW: I'm not sure if we need |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about this solution? I guess it is mature enough, is not it?
template<typename T, typename T2, typename std::enable_if< std::is_enum<T>::value | ||
&& T::CV_FLAGS_ENUM == T::CV_FLAGS_ENUM >::type* = nullptr> | ||
static T operator|(const T2& a, const T& b) | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about utilizing SFINAE and introducing CV_FLAGS_ENUM
in the flag-based enums? I guess this solution is elegant enough.
ACCESS_RW=3<<24, ACCESS_MASK=ACCESS_RW, ACCESS_FAST=1<<26 }; | ||
enum AccessFlag { ACCESS_READ=1<<24, ACCESS_WRITE=1<<25, | ||
ACCESS_RW=3<<24, ACCESS_MASK=ACCESS_RW, ACCESS_FAST=1<<26, | ||
CV_FLAGS_ENUM = ACCESS_READ }; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As you can see, CV_FLAGS_ENUM
is introduced to enable bitwise operators, and it can take any value, and in this case, it is assigned ACCESS_READ
for safety against ignorant users.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool. I think that would work.
The obvious disadvantage is that we have extra CV_FLAGS_ENUM
in every flags enum and in documentation etc. Also in my experience widely used SFINAE can affect compilation times pretty badly.
Therefore, I would prefer the solution above, but this is certainly workable too. If you want to go with this, I suggest to add constexpr to allow using it in constant expressions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
constexpr
is available from Visual Studio 2015.
Do we really want to drop support of Visual Studio 2013? It is still widely used...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think OpenCV 4 will be C++11 as per OE-4
modules/core/src/matrix_wrap.cpp
Outdated
@@ -15,7 +15,7 @@ namespace cv { | |||
Mat _InputArray::getMat_(int i) const | |||
{ | |||
int k = kind(); | |||
int accessFlags = flags & ACCESS_MASK; | |||
AccessFlag accessFlags = flags & ACCESS_MASK; | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hrnr The problem with the macro-based solution is that it cannot handle two types T1, T2
, thus the above expression would not compile since flags
is int
. Of couse we can introduce cast in such cases, but this might break user code as well. The only solution that seems to work with minimal changes is a template-based one. Accordingly, I would like to go with my proposal, at least for the time-being.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is about this?
AccessFlag operator & (const int a, const AccessFlag& b)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This also would work, but I am not sure if int
is the only type utilized with bitwise operations (how about long
?), and I do not think we want to provide all the variants. On the other hand, the template-based solution referenced above is just doing that with minimal effort, I guess.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
int
, long
and other helper operators can be placed under CV_FLAGS_ENUM(enumType)
macro:
enum AccessFlag { ... };
CV_FLAGS_ENUM(AccessFlag); // define helper operators here
It can be added for each bit-set/flags enum types.
80d8839
to
25c0bd6
Compare
CV_FLAGS_ENUM_XOR_EQ(EnumType, EnumType); \ | ||
CV_FLAGS_ENUM_OR_EQ (EnumType, int); \ | ||
CV_FLAGS_ENUM_AND_EQ(EnumType, int); \ | ||
CV_FLAGS_ENUM_XOR_EQ(EnumType, int); \ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although it is hard to maintain, I need to admit that it is looks beautiful and have optimal performance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work. Keep going!
I think that int is enough for the overloads as enums convert implicitly to ints (we have only int enums). Moreover, I think we should get rid of those overloads one day to disallow AccessFlags flags = cv::RANSAC | ACCESS_WRITE;
. Casts would need to be added to some places though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The good news is, if cv::RANSAC
is not an int
, AccessFlags flags = cv::RANSAC | ACCESS_WRITE
would not work.
That is another reason to avoid using int
, and use enum
types instead.
25c0bd6
to
cff9c46
Compare
modules/core/src/ocl.cpp
Outdated
if (!(arg.flags & KernelArg::READ_ONLY)) | ||
accessFlags &= ~ACCESS_READ; | ||
if (!(arg.flags & KernelArg::WRITE_ONLY)) | ||
accessFlags &= ~ACCESS_WRITE; | ||
bool ptronly = (arg.flags & KernelArg::PTR_ONLY) != 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alalek @hrnr We do not have ACCESS_NONE
to write something like ((arg.flags & KernelArg::READ_ONLY) ? ACCESS_READ : ACCESS_NONE) | ((arg.flags & KernelArg::WRITE_ONLY) ? ACCESS_WRITE : ACCESS_NONE)
and even the ACCESS_MASK
is not covering the FAST_ACCESS
bit...
In this case, all I can think of is the negative logic. Is there any better idea to do this more efficiently?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For any "flags" enum, "0" is default "none" value.
I would like to avoid introducing separate meaningless enum value like ACCESS_NONE
. Perhaps we can write here (AccessFlag)0
instead.
It is better to drop "negative logic" in code, like your suggestion.
Alternatively we can try to overload operator - ()
for "flag" enums (but we should make it safe).
e6f1bbc
to
20517ce
Compare
|
||
// Exposes the listed 5 members of the enum class AccessFlag to the current namespace | ||
CV_ENUM_CLASS_EXPOSE(AccessFlag, 5, ACCESS_READ, ACCESS_WRITE, ACCESS_RW, ACCESS_MASK, ACCESS_FAST); | ||
@endcode |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Making all enums enum class would be, however, a big disaster (without any backward compatibility stuff).
I managed to get C++11 enum class
es working with backwards compatibility and minimal changes.
Basically, instead of:
enum xyz { m1, m2, m3};
one would define:
enum class xyz { m1, m2, m3};
CV_ENUM_CLASS_EXPOSE(xyz, m1, m2, m3);
and in case it is a flag enum, then CV_ENUM_FLAGS_CLASS(AccessFlag);
instead of CV_ENUM_FLAGS(AccessFlag);
would do the trick.
Only Python module still have issues with that, but I believe I can work around that as well.
@alalek @hrnr Shall I consider changing the enum
s into enum class
es?
20517ce
to
a01d44a
Compare
5bc7784
to
794e88d
Compare
794e88d
to
65b4ad7
Compare
TESTING... DO NOT MERGE!
Merge with opencv/opencv_contrib#1730 and opencv/opencv_extra#515This pullrequest changes
There are hundreds of unnamed enums, and they are being passed as int in the C++ interface.
In order to avoid passing a wrong value, and to maintain good practices, the hope is to name most of these enums, and change the int arguments into the proper enum types wherever possible.
Newly introduced enums
ElemType
for handling the depth and channels of matrix elements (Produced byDataType<T>::type
andtraits::Type<T>::value
)ElemDepth
for handling the depth of matrix elements (Produced byDataDepth<T>::type
andtraits::Depth<T>::value
)MagicFlag
for handling the mixed magic values ofElemType
,AccessFlag
and_InputArray::KindFlag
Flag enums
AccessFlag
forunnamed
enum havingACCESS_READ
as first memberunnamed
enum havingDEFAULT
as first memberMemoryFlag
for UMatData::unnamed
enum havingCOPY_ON_MAP
as first memberKindFlag
for _InputArray::unnamed
enum havingKIND_SHIFT
as first memberMode enums
DescriptorType
for AKAZE::unnamed
enum havingDESCRIPTOR_KAZE_UPRIGHT
as first memberDetectorType
for AgastFeatureDetector::unnamed
enum havingAGAST_5_8
as first memberFeatureType
for CvFeatureParams::unnamed
enum havingHAAR
as first memberDetectorType
for FastFeatureDetector::unnamed
enum havingTYPE_5_8
as first memberMatcherType
for DescriptorMatcher::unnamed
enum havingFLANNBASED
as first memberFormatType
for Formatter::unnamed
enum havingFMT_DEFAULT
as first memberHistogramNormType
for HOGDescriptor::unnamed
enum havingL2Hys
as the only memberunnamed
enum havingnormType
as the only memberunnamed
enum havingnormType
as the only memberunnamed
enum havingnormType
as the only memberunnamed
enum havingnormType
as the only memberunnamed
enum havingMAGIC_MASK
as first memberunnamed
enum havingMAGIC_VAL
as first memberunnamed
enum havingMAGIC_VAL
as first memberunnamed
enum havingMAGIC_MASK
as first memberunnamed
enum havingMAGIC_VAL
as first memberDiffusivityType
for KAZE::unnamed
enum havingDIFF_PM_G1
as first memberScoreType
for ORB::unnamed
enum havingkBytes
as first member, andkBytes
become a static const intunnamed
enum havingINT
as first memberunnamed
enum havingLOCATION_ROW
as first memberunnamed
enum havingDESCR_FORMAT_ROW_BY_ROW
as first memberunnamed
enum havingX_ROW
as first memberNormalizationType
for xfeatures2d::DAISY::unnamed
enum havingNRM_NONE
as first memberunnamed
enum havingNB_SCALES
as first memberDepthMask
for _OutputArray::unnamed
enum havingDEPTH_MASK_8U
as first memberTasks list
unnamed
enum havingCALIB_CB_ADAPTIVE_THRESH
as first memberunnamed
enum havingCALIB_CB_SYMMETRIC_GRID
as first memberunnamed
enum havingCALIB_USE_INTRINSIC_GUESS
as first memberunnamed
enum havingCAP_INTELPERC_DEPTH_GENERATOR
as first memberunnamed
enum havingCAP_INTELPERC_DEPTH_MAP
as first memberunnamed
enum havingCAP_OPENNI_DEPTH_GENERATOR
as first memberunnamed
enum havingCAP_OPENNI_DEPTH_MAP
as first memberunnamed
enum havingCAP_OPENNI_IMAGE_GENERATOR_PRESENT
as first memberunnamed
enum havingCAP_OPENNI_VGA_30HZ
as first memberunnamed
enum havingCAP_PROP_DC1394_OFF
as first memberunnamed
enum havingCAP_PROP_GIGA_FRAME_OFFSET_X
as first memberunnamed
enum havingCAP_PROP_GPHOTO2_PREVIEW
as first memberunnamed
enum havingCAP_PROP_GSTREAMER_QUEUE_LENGTH
as first memberunnamed
enum havingCAP_PROP_IMAGES_BASE
as first memberunnamed
enum havingCAP_PROP_INTELPERC_PROFILE_COUNT
as first memberunnamed
enum havingCAP_PROP_IOS_DEVICE_FOCUS
as first memberunnamed
enum havingCAP_PROP_OPENNI_OUTPUT_MODE
as first memberunnamed
enum havingCAP_PROP_PVAPI_MULTICASTIP
as first memberunnamed
enum havingCAP_PROP_XI_DOWNSAMPLING
as first memberunnamed
enum havingCAP_PVAPI_DECIMATION_OFF
as first memberunnamed
enum havingCAP_PVAPI_FSTRIGMODE_FREERUN
as first memberunnamed
enum havingCAP_PVAPI_PIXELFORMAT_MONO8
as first memberunnamed
enum havingCASCADE_DO_CANNY_PRUNING
as first memberunnamed
enum havingFM_7POINT
as first memberunnamed
enum havingINPAINT_NS
as first memberunnamed
enum havingLDR_SIZE
as first memberunnamed
enum havingLMEDS
as first memberunnamed
enum havingMOTION_TRANSLATION
as first memberunnamed
enum havingNORMAL_CLONE
as first memberunnamed
enum havingOPTFLOW_USE_INITIAL_FLOW
as first memberunnamed
enum havingRECURS_FILTER
as first memberunnamed
enum havingSOLVEPNP_ITERATIVE
as first memberunnamed
enum havingUNIFORM
as first memberunnamed
enum havingPREFILTER_NORMALIZED_RESPONSE
as first memberunnamed
enum havingDISP_SHIFT
as first memberunnamed
enum havingMODE_SGBM
as first memberunnamed
enum havingORIG_RESOL
as first memberunnamed
enum havingNEXT_AROUND_ORG
as first memberunnamed
enum havingPTLOC_ERROR
as first memberunnamed
enum havingMODE_POSITIVE
as first memberunnamed
enum havingMODE_INIT_POS
as first memberunnamed
enum havingRETINA_COLOR_RANDOM
as first memberunnamed
enum havingNO
as first memberunnamed
enum havingNO
as first memberunnamed
enum havingAS_IS
as first memberunnamed
enum havingCALIB_USE_INTRINSIC_GUESS
as first memberunnamed
enum havingLINEAR
as first memberunnamed
enum havingONE_STEP
as first memberunnamed
enum havingDEFAULT
as first memberunnamed
enum havingDEFAULT_NCLUSTERS
as first memberunnamed
enum havingSTART_E_STEP
as first memberunnamed
enum havingPINHOLE
as first memberunnamed
enum havingEXEC_KERNEL
as first memberunnamed
enum havingFP_DENORM
as first memberunnamed
enum havingNO_CACHE
as first memberunnamed
enum havingNO_LOCAL_MEM
as first memberunnamed
enum havingTYPE_DEFAULT
as first memberunnamed
enum havingUNKNOWN_VENDOR
as first memberunnamed
enum havingLOCAL
as first memberunnamed
enum havingCALIB_USE_GUESS
as first memberunnamed
enum havingRECTIFY_PERSPECTIVE
as first memberunnamed
enum havingXYZRGB
as first memberunnamed
enum havingPRESET_ULTRAFAST
as first memberunnamed
enum havingROTATION
as first memberunnamed
enum havingCACHE_SRC
as first memberunnamed
enum havingDECODE_3D_UNDERWORLD
as first memberunnamed
enum havingFTP
as first memberunnamed
enum havingERFILTER_NM_RGBLGrad
as first memberunnamed
enum havingOCR_LEVEL_WORD
as first memberunnamed
enum havingNONE
as first memberunnamed
enum havingLOAD_AUTO
as first memberunnamed
enum havingFRAMES
as first memberCurrent issues
unnamed
enum havingUNDEFINED
as first memberstatic_cast<MagicFlag>()
are utilized now. Proper operators needs to get enabledunnamed
enum havingDEFAULT_NLEVELS
as the only member to to static const int causes some Java test to fail[javac] /build/precommit_android/build/android_test/src/org/opencv/test/objdetect/HOGDescriptorTest.java:204: error: cannot find symbol [javac] assertEquals(HOGDescriptor.DEFAULT_NLEVELS, hog.get_nlevels()); [javac] ^ [javac] symbol: variable DEFAULT_NLEVELS [javac] location: class HOGDescriptor [javac] Note: Some input files use unchecked or unsafe operations. [javac] Note: Recompile with -Xlint:unchecked for details. [javac] 1 error