Can't OR 2 enum values of the same type outside its enum class declaration - enums

I am a newbie to both C++ and game programming. I am dealing with something I don't know how to make it work. I am coding along a game from a book, the authors didn't use enum class for his type but as recommended by most people, I am using enum class to remake it. It produces no error when I OR 2 enum value inside its enum class scope like this:
// This is inside the "Category.h" header file
namespace Category
{
enum class Type
{
None = 0,
SceneAirLayer = 1 << 0,
PlayerAircraft = 1 << 1,
AlliedAircraft = 1 << 2,
EnemyAircraft = 1 << 3,
Pickup = 1 << 4,
AlliedProjectile = 1 << 5,
EnemyProjectile = 1 << 6,
Aircraft = PlayerAircraft | AlliedAircraft | EnemyAircraft,
Projectile = AlliedProjectile | EnemyProjectile
};
}
But when I try to OR them inside a function of another source file, the compiler produces an error,
that is: "no operator "|" matches these operands operand type are Category::Type | Category::Type"
and here is the code inside that function (the game works for the authors version enum without class)
void World::destroyEntitiesOutsideView()
{
// This "command.category" just returns an "unsigned int" value
Command command;
// The error appears here
command.category = static_cast<unsigned int>(Category::Type::Projectile | Category::Type::EnemyAircraft);
// This is I just try to OR them alone but still the same error
Category::Type::Aircraft | Category::Type::AlliedProjectile;
}
Please someone tell me why and how can I fix this error??? Thank you a lot!!!

It is because you are using enum class instead of just enum. "Class enum doesn’t allow implicit conversion to int, and also doesn’t compare enumerators from different enumerations"

Related

Adding a new Object to V8 using Torque

TL;DR: I tried adding a new Object defined exclusively in Torque and use it as a new member for the Name class. This resulted in compilation failures due to function used but never defined errors, pertaining to a function that IS defined in torque-generated files, however for some reason not properly included.
I am unsure how to proceed and trying to just include different combinations of the torque-generated files in the appropriate locations simply led to redefinition errors.
The question: Is it possible to define a new object and use it in the way I intend to, without adding C++ class definitions (that inherit from the torque-generated classes and so forth) and if yes, where do I seem to be going wrong. In the following I will describe the steps I took so far:
Add a myClass.tq/ file to src/objects that includes a definition of my class along the lines of:
#export
#generateBodyDescriptors
class MyClass extends HeapObject {
macro SomeMacro(): Boolean {...}
macro Set(): void { this.i = 1 }
i: uint32;
}
Add this file to BUILD.gn
I then tried to use this new type to add a member to an existing type (the abstract Name type):
Added a new member in src/objects/name.tq
Included torque-generated/src/objects/myClass.tq in src/objects/name.h
String inherits from Name so i had to modify two "constructors" methods in src/objects/string.tq to include the new member
Changed the expected size of String objects in include/v8-interal.h to account for the new member
Added some macros to Name that actually use the new member (check if its internal uint is non-zero and set the value to one)
And lastly I added two methods to the String prototype that I defined as javascript builtins, so that I can verify my changes work.
Concretely, the resulting errors complained about the TorqueGeneratedMyClass::cast(Object) method being used but never defined. This error results from the myClass-tq.inc file. However, the method is defined, in the corresponding myClass-tq-inl.inc file.
I'm not sure if I described the issue concretely enough, but I'm happy to clarify uncertainties and appreciate every help.
Edit:
Complete Changes:
// src/objects/myClass.tq
#export
#generateBodyDescriptors
class MyClass extends HeapObject {
macro IsSet(): Boolean {
return this.i == 0 ? False : True;
}
macro Set(): void { this.i = 1 }
i: uint32;
}
// src/objects/name.h
## -16,6 +17,7 ##
namespace v8 {
namespace internal {
+#include "torque-generated/src/objects/taint-tq.inc"
#include "torque-generated/src/objects/name-tq.inc"
// src/objects/name.tq
## -4,7 +4,18 ##
#abstract
extern class Name extends PrimitiveHeapObject {
+ macro IsSet(): Boolean {
+ return this.test.IsSet();
+ }
+
+ macro Set(): void {
+ this.test.Set();
+ }
+
+ test: MyClass;
raw_hash_field: NameHash;
}
// src/objects/string.tq
## -135,7 +135,10 ## macro AllocateNonEmptySeqOneByteString<Iterator: type>(
dcheck(length != 0 && length <= kStringMaxLength);
return new SeqOneByteString{
map: kOneByteStringMap,
+ test: new StringTaint{tainted: 0},
raw_hash_field: kNameEmptyHashField,
length: Signed(length),
chars: ...content
};
## -146,7 +149,10 ## macro AllocateNonEmptySeqTwoByteString<Iterator: type>(
dcheck(length > 0 && length <= kStringMaxLength);
return new SeqTwoByteString{
map: kStringMap,
+ test: new StringTaint{tainted: 0},
raw_hash_field: kNameEmptyHashField,
length: Signed(length),
chars: ...content
};
// src/builtins/string-test.tq
namespace string {
transitioning javascript builtin StringPrototypeIsSet(js-implicit context: NativeContext, receiver: JSAny)(): Boolean {
const string: String = ToThisString(receiver, 'String.prototype.testIsSet');
return string.IsSet();
}
transitioning javascript builtin StringPrototypeSet(js-implicit context: NativeContext, receiver: JSAny)(): JSAny {
const string: String = ToThisString(receiver, 'String.prototype.testSet');
string.Set();
return Undefined;
}
}
// src/init/bootstrapper.cc
## -2078,6 +2078,10 ## void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
Builtin::kStringPrototypeSup, 0, false);
SimpleInstallFunction(isolate_, prototype, "startsWith",
Builtin::kStringPrototypeStartsWith, 1, false);
+ SimpleInstallFunction(isolate_, prototype, "testSet",
+ Builtin::kStringPrototypeTaint, 0, true);
+ SimpleInstallFunction(isolate_, prototype, "testIsSet",
+ Builtin::kStringPrototypeIsTainted, 0, true);
SimpleInstallFunction(isolate_, prototype, "toString",
Builtin::kStringPrototypeToString, 0, true);
SimpleInstallFunction(isolate_, prototype, "trim",
// BUILD.gn
## -1698,6 +1698,7 ## torque_files = [
"src/builtins/string-startswith.tq",
"src/builtins/string-substr.tq",
"src/builtins/string-substring.tq",
+ "src/builtins/string-test.tq",
"src/builtins/string-trim.tq",
"src/builtins/symbol.tq",
"src/builtins/torque-internal.tq",
## -1781,6 +1782,7 ## torque_files = [
"src/objects/swiss-hash-table-helpers.tq",
"src/objects/swiss-name-dictionary.tq",
"src/objects/synthetic-module.tq",
+ "src/objects/myClass.tq",
"src/objects/template-objects.tq",
"src/objects/templates.tq",
"src/objects/torque-defined-classes.tq",
Error:
In file included from ../deps/v8/src/objects/name.h:20,
from ../deps/v8/src/objects/string.h:15,
from ../deps/v8/src/heap/factory.h:25,
from ../deps/v8/src/execution/isolate.h:33,
from ../deps/v8/src/logging/log.h:16,
from ../deps/v8/src/heap/base-space.h:12,
from ../deps/v8/src/heap/spaces.h:16,
from ../deps/v8/src/heap/marking-visitor.h:13,
from ../deps/v8/src/heap/concurrent-marking.h:14,
from ../deps/v8/src/heap/concurrent-marking.cc:5:
/home/ccloud/sap_node/out/Release/obj/gen/torque-generated/src/objects/myClass-tq.inc:26:22: warning: inline function ‘static D v8::internal::TorqueGeneratedMyClass<D, P>::cast(v8::internal::Object) [with D = v8::internal::MyClass; P = v8::internal::HeapObject]’ used but never defined
26 | V8_INLINE static D cast(Object object);
| ^~~~
/home/ccloud/sap_node/out/Release/obj/gen/torque-generated/src/objects/myClass-tq.inc: In static member function ‘static T v8::internal::ConcurrentMarkingVisitor::Cast(v8::internal::HeapObject) [with T = v8::internal::MyClass]’:
/home/ccloud/sap_node/out/Release/obj/gen/torque-generated/src/objects/myClass-tq.inc:26:22: error: inlining failed in call to always_inline ‘static D v8::internal::TorqueGeneratedMyClass<D, P>::cast(v8::internal::Object) [with D = v8::internal::MyClass; P = v8::internal::HeapObject]’: function body not available
../deps/v8/src/heap/concurrent-marking.cc:103:19: note: called from here
103 | return T::cast(object);
| ~~~~~~~^~~~~~~~
make[1]: *** [tools/v8_gypfiles/v8_base_without_compiler.target.mk:1000: /home/ccloud/sap_node/out/Release/obj.target/v8_base_without_compiler/deps/v8/src/heap/concurrent-marking.o] Error 1
make[1]: *** Waiting for unfinished jobs....
In file included from ../deps/v8/src/objects/name.h:20,
from ../deps/v8/src/objects/string.h:15,
from ../deps/v8/src/heap/factory.h:25,
from ../deps/v8/src/execution/isolate.h:33,
from ../deps/v8/src/common/ptr-compr-inl.h:10,
from ../deps/v8/src/execution/isolate-utils-inl.h:8,
from ../deps/v8/src/diagnostics/objects-printer.cc:11:
/home/ccloud/sap_node/out/Release/obj/gen/torque-generated/src/objects/myClass-tq.inc:26:22: warning: inline function ‘static D v8::internal::TorqueGeneratedMyClass<D, P>::cast(v8::internal::Object) [with D = v8::internal::MyClass; P = v8::internal::HeapObject]’ used but never defined
26 | V8_INLINE static D cast(Object object);
| ^~~~
/home/ccloud/sap_node/out/Release/obj/gen/torque-generated/src/objects/myClass-tq.inc: In member function ‘void v8::internal::HeapObject::HeapObjectPrint(std::ostream&)’:
/home/ccloud/sap_node/out/Release/obj/gen/torque-generated/src/objects/myClass-tq.inc:26:22: error: inlining failed in call to always_inline ‘static D v8::internal::TorqueGeneratedMyClass<D, P>::cast(v8::internal::Object) [with D = v8::internal::MyClass; P = v8::internal::HeapObject]’: function body not available
../deps/v8/src/diagnostics/objects-printer.cc:216:21: note: called from here
216 | Name::cast(*this).Name##Print(os); \
| ^
/home/ccloud/sap_node/out/Release/obj/gen/torque-generated/instance-types.h:637:3: note: in expansion of macro ‘MAKE_TORQUE_CASE’
637 | V(MyClass, MY_CLASS_TYPE) /* src/objects/myClass.tq?l=1&c=1 */ \
| ^
../deps/v8/src/diagnostics/objects-printer.cc:220:7: note: in expansion of macro ‘TORQUE_INSTANCE_CHECKERS_SINGLE_FULLY_DEFINED’
220 | TORQUE_INSTANCE_CHECKERS_SINGLE_FULLY_DEFINED(MAKE_TORQUE_CASE)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from ../deps/v8/src/objects/name.h:20,
from ../deps/v8/src/objects/string.h:15,
from ../deps/v8/src/heap/factory.h:25,
from ../deps/v8/src/execution/isolate.h:33,
from ../deps/v8/src/common/ptr-compr-inl.h:10,
from ../deps/v8/src/execution/isolate-utils-inl.h:8,
from ../deps/v8/src/diagnostics/objects-printer.cc:11:
/home/ccloud/sap_node/out/Release/obj/gen/torque-generated/src/objects/myClass-tq.inc:26:22: error: inlining failed in call to always_inline ‘static D v8::internal::TorqueGeneratedMyClass<D, P>::cast(v8::internal::Object) [with D = v8::internal::MyClass; P = v8::internal::HeapObject]’: function body not available
26 | V8_INLINE static D cast(Object object);
| ^~~~
../deps/v8/src/diagnostics/objects-printer.cc:216:21: note: called from here
216 | Name::cast(*this).Name##Print(os); \
| ^
/home/ccloud/sap_node/out/Release/obj/gen/torque-generated/instance-types.h:637:3: note: in expansion of macro ‘MAKE_TORQUE_CASE’
637 | V(MyClass, MY_CLASS_TYPE) /* src/objects/myClass.tq?l=1&c=1 */ \
| ^
../deps/v8/src/diagnostics/objects-printer.cc:220:7: note: in expansion of macro ‘TORQUE_INSTANCE_CHECKERS_SINGLE_FULLY_DEFINED’
220 | TORQUE_INSTANCE_CHECKERS_SINGLE_FULLY_DEFINED(MAKE_TORQUE_CASE)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Is it possible to define a new object and use it in the way I intend to, without adding C++ class definitions
Yes.
where do I seem to be going wrong
This part seems suspicious:
the method is defined, in the corresponding myClass-tq-inl.inc file
All generated *.inc files have to be #included somewhere. There's likely some *.cc file that needs it (you didn't provide enough details, so I can't tell for sure).
A couple of more general points:
when asking for programming help (anywhere!), provide reproducible code (in this case: your complete patch, not just a prose description of it).
when asking about compiler errors, provide the complete error message, not just a vague summary like "the errors complained about ...".
while you are of course free to fork V8 and muck with its internals, a word of caution: such modifications are likely to be very labor-intensive to maintain as you update to newer V8 versions (and you will want to update to newer V8 versions, if this isn't just some throwaway experiment). To make your work more future-proof, either attempt to upstream it (which might be difficult in this case, as increasing the size of Name objects will be an unpopular proposition, I expect), or use only the public API (which isn't perfectly stable, but much more stable than random internals). Of course, the latter won't allow you to modify internally used objects; since you didn't describe your higher-level goal I can't tell whether that's a dealbreaker or whether there could be alternative approaches.

f# Cast enum element type

I have a question rather simple I think but I can not find any info about it.
So for example in c# I can define value enum types using inheritance like:
public enum RequestedService : ushort
{
[Description("Unknown")]
Unknown = 0,
[Description("Status")]
SERVICE1 = 0x0001
}
But how would I do it in F#, so far I translate it like:
type RequestedService =
| [<Description("Unknown")>] Unknown = 0u
| [<Description("Status")>] SERVICE1 = 0x0001u
I tried using inheritance, and tried to define type before value like
Unknown = uint16 0u
But I am getting compile error, so is it possible?
Casting of non-int32 values to an enum is documented in Enumerations:
The default enum function works with type int32. Therefore, it cannot be used with enumeration types that have other underlying types. Instead, use the following.
type uColor =
| Red = 0u
| Green = 1u
| Blue = 2u
let col3 = Microsoft.FSharp.Core.LanguagePrimitives.EnumOfValue<uint32, uColor>(2u)
Thus you would do:
open Microsoft.FSharp.Core.LanguagePrimitives
type RequestedService =
| [<Description("Unknown")>] Unknown = 0u
| [<Description("Status")>] SERVICE1 = 0x0001u
let service = EnumOfValue<uint32, RequestedService>(0u) // Or 1u or whatever
Or if you prefer:
let service : RequestedService = EnumOfValue 0u // Or 1u or whatever
For more see: LanguagePrimitives.EnumOfValue<'T,'Enum> Function.

Setting owner in boost::python::ndarray so that data is owned and managed by Python

I am trying to use boost::python::numpy::ndarray to create a multi-dimensional array in C++ and pass it to python. The problem is how to do this without having to manage the memory associated with the ndarray in C++ myself.
I am trying to use the boost::python::numpy::from_data function to create numpy array in C++. My basic understanding is that without the appropriate owner argument to the function, the responsibility of managing the memory associated with the array falls on me.
My original assumption was that the owner argument needn't be passed based on the boost page which says this about owner: "the owner of the data, in case it is not the ndarray itself."
However, I have read posts which seem to say otherwise. E.g., link says, "If you pass object() as owner argument the array should definitely own its data (and thus report OWNDATA=True) ... " and link says that the object has to be associated with an explicit destructor.
I was wondering what the correct approach is. Or is this not the intended use case for boost::python::numpy?
Yep, the documentation says that if you pass object(), the array will free the data when but this doens't work as advertised.
Here are some excerpts from my post on github https://github.com/boostorg/python/issues/97#issuecomment-519679003 which is the same issue that OP links but the answer wasn't there before. The answer doesn't come from me, just the demonstration of the answer and why the demo of the object() way not working.
The solution would be to create an object (a capsule) that owns the raw pointer and pass that to the the boost::python::numpy::ndarray::from_data() function. A capsule is a Python object that manages a pointer:
PyObject* PyCapsule_New(void *pointer, const char *name, PyCapsule_Destructor destructor)
Here is an example where I create a pretty large array. I'm going to call this function repeatedly in a Python while True: loop. With this function, you can let the loop go on all day. That's because in the loop, I assign the return value to the same variable, so at each iteration, the previously returned ndarray's refcount goes to zero and the memory gets freed.
typedef long int my_data_type;
inline void destroyManagerCObject(PyObject* self) {
auto * b = reinterpret_cast<my_data_type*>( PyCapsule_GetPointer(self, NULL) );
std::cout << "C++ : " << __PRETTY_FUNCTION__ << " delete [] " << b << std::endl;
delete [] b;
}
boost::python::numpy::ndarray get_array_that_owns_through_capsule()
{
// Change this to see how the adresses change.
unsigned int last_dim = 6000;
boost::python::object shape = boost::python::make_tuple(4, 5, last_dim);
boost::python::numpy::dtype dt = boost::python::numpy::dtype::get_builtin<my_data_type>();
auto * const data_ptr = new my_data_type[4*5*last_dim];
const size_t s = sizeof(my_data_type);
boost::python::object strides = boost::python::make_tuple(5*last_dim*s, last_dim*s, s);
for(int i = 1; i <= 4*5*last_dim; ++i){ data_ptr[i-1] = i; }
// This sets up a python object whose destruction will free data_ptr
PyObject *capsule = ::PyCapsule_New((void *)data_ptr, NULL, (PyCapsule_Destructor)&destroyManagerCObject);
boost::python::handle<> h_capsule{capsule};
boost::python::object owner_capsule{h_capsule};
std::cout << "C++ : " << __PRETTY_FUNCTION__ << "data_ptr = " << data_ptr << std::endl;
return boost::python::numpy::from_data( data_ptr, dt, shape, strides, owner_capsule);
}
BOOST_PYTHON_MODULE(interface){
.def("get_array_that_owns_through_capsule", get_array_that_owns_through_capsule)
Then in a while loop, I can call this function all day long and
import interface
import psutil
def get_process_memory_usage():
process = psutil.Process(os.getpid())
return process.memory_info().rss
hundred_mb = 100000000
MEMORY_MAX = 100 * one_mb
i = 0
while True:
print("PYTHON : ---------------- While iteration ------------------- ({})".format(i))
print("PYTHON : BEFORE calling test_capsule_way()")
arr = interface.get_array_that_owns_through_default_object()
print("PYTHON : AFTER calling test_capsule_way()")
i += 1
if i % 1000 == 0:
print("PYTHON : Nb arrays created (and pretty sure not destroyed) : {}".format(i))
mem = get_process_memory_usage()
if mem > MEMORY_MAX:
print("PYTHON : Bro chill with the memory, you're using {}MB over here!".format(mem/one_mb))
quit()
print("PYTHON : ----------- End while iteration\n")
print("PYTHON : SCRIPT END")
The output of the first couple iterations of this is
PYTHON : ---------------- While iteration ------------------- (0)
PYTHON : BEFORE calling test_capsule_way()
C++ : boost::python::numpy::ndarray get_array_that_owns_through_capsule()data_ptr = 0x7fb7c9831010
PYTHON : AFTER calling test_capsule_way()
PYTHON : ----------- End while iteration
PYTHON : ---------------- While iteration ------------------- (1)
PYTHON : BEFORE calling test_capsule_way()
C++ : boost::python::numpy::ndarray get_array_that_owns_through_capsule()data_ptr = 0x7fb7c9746010
C++ : void destroyManagerCObject(PyObject*) delete [] 0x7fb7c9831010
PYTHON : AFTER calling test_capsule_way()
PYTHON : ----------- End while iteration
PYTHON : ---------------- While iteration ------------------- (2)
PYTHON : BEFORE calling test_capsule_way()
C++ : boost::python::numpy::ndarray get_array_that_owns_through_capsule()data_ptr = 0x14c9f20
C++ : void destroyManagerCObject(PyObject*) delete [] 0x7fb7c9746010
PYTHON : AFTER calling test_capsule_way()
PYTHON : ----------- End while iteration
PYTHON : ---------------- While iteration ------------------- (3)
In the issue, I also have a demonstration of how if you do this and instead of the capsule, you pass boost::python::object() as the owner parameter, the memory is not freed and the python loop will stop because of the check on the process memory : https://github.com/boostorg/python/issues/97#issuecomment-520555403

C++11: string(50, 'x') versus string{50, 'x'}

As seen on ideone:
cout << string(50, 'x'); // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
cout << string{50, 'x'}; // 2x
WAT??
I have figured out that 50 is ASCII '2', so:
cout << static_cast<int>('2'); // 50
cout << static_cast<char>(50); // 2
But that's as far as I've got.
Does this lead to a solid argument against C++11 initializers?
When you do string { 50, 'x' } you're essentially initializing the string with a list of characters.
On the other hand, string(50, 'x') calls a 2 argument constructor, which is defined to repeat the character x 50 times. The reason why string { 50, 'x' } doesn't pick the constructor is that it could be ambiguous. What if you had a three parameter constructor as well? If the type has an initializer_list constructor, it will be picked when you use { ... } for initialization.
Basically you need to be aware of the constructors your type has. The initializer_list constructor will always have a precedence to avoid ambiguity.

F# compiler requires project reference, but method is private

The F# compiler gives an error saying I must add a project reference because the type I'm using has a method argument that lives in that project. But this method is private!
I have the following project structure:
Program -> Library -> SubLibrary
SubLibrary contains this:
namespace SubLibrary
type Widget = { Value: int }
Library contains this:
namespace Library
open SubLibrary
type Banana =
{ Value: int }
member private x.TakeWidget (w: Widget) = ()
Program contains this:
open Library
[<EntryPoint>]
let main argv =
printfn "%A" argv
let banana = { Value = 42 }
0
I get this error:
error FS0074:
The type referenced through 'SubLibrary.Widget' is defined in an assembly that is not referenced.
You must add a reference to assembly 'SubLibrary'
But the TakeWidget method is private!
I tried changing Banana into a class, rather than a record, but that made no difference.
As an experiment, I created a C# version of Library, called CLibrary:
using SubLibrary;
namespace CLibrary {
public class CBanana {
int m_value;
public CBanana(int value) {
m_value = value;
}
private void TakeWidget(Widget w) {
}
}
}
Then I changed Program to use CBanana instead of Banana:
open Library
[<EntryPoint>]
let main argv =
printfn "%A" argv
let banana = CBanana 42
0
Now I don't get an error. In fact, with C# I can make that method public, and so long as I don't try to compile a call to it, there is no error.
Why is the compiler insisting I add a reference to SubLibrary? Sure, I could just go ahead and do what it tells me to do, for a quiet life, but SubLibrary is a private implementation detail of Library, which should not be exposed to Program.
Actually, when I tried with a class instead of record, it did the trick (F# 3.1):
type BananaClass (value:int) =
member private x.TakeWidget (w: Widget) = ()
member x.Value = value
You can work around it with a record as well - you need to move the private member into a separate module and have it as a type augmentation:
type Banana = { Value: int }
module Ext =
type Banana with
member x.TakeWidget (w: Widget) = ()
Compiler won't complain about the missing dependency until you open the Ext module.
I don't have a good idea why the compiler was complaining in the first place. Probably one of its quirks. I couldn't find anything seriously suspicious in the generated IL (other than a surprising fact that F# compiler marks both private and internal members as internal in the IL - this turned out to be of no consequence here).
Indeed this to me looks like an error I have raised an issue here, https://github.com/Microsoft/visualfsharp/issues/86. So you'll be able to track feedback from there.

Resources