Skip to content
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

Replace enum_long by 'enum class' #868

Closed
dirkwhoffmann opened this issue Jan 24, 2025 · 2 comments
Closed

Replace enum_long by 'enum class' #868

dirkwhoffmann opened this issue Jan 24, 2025 · 2 comments

Comments

@dirkwhoffmann
Copy link
Owner

Background: For most enum-like types, vAmiga defines a C-style enum together with a xxxEnum class that allows some kind of reflection support. The xxxEnum classes are utilizes at various places both on the C++ side and the Swift side to translate textual descriptions (e.g. those coming from RetroShell command) into enums and vice versa. A type declaration typically looks like this:

enum_long(RTC_REVISION)
{
    RTC_NONE,
    RTC_OKI,
    RTC_RICOH
};
typedef RTC_REVISION RTCRevision;

struct RTCRevisionEnum : util::Reflection<RTCRevisionEnum, RTCRevision>
{
    static constexpr long minVal = 0;
    static constexpr long maxVal = RTC_RICOH;
    
    static const char *prefix() { return "RTC"; }
    static const char *_key(long value)
    {
        switch (value) {
                
            case RTC_NONE:   return "NONE";
            case RTC_OKI:    return "OKI";
            case RTC_RICOH:  return "RICOH";
        }
        return "???";
    }
    static const char *help(long value)
    {
        return "";
    }
};

Starting with vAmiga 3.3, Swift/C++ interoperability will be enabled, that is, Swift understands C++ syntax. Thus, we can replace the enum part by this:

enum class RtcRevision
{
    NONE,
    OKI,
    RICOH
};

Pros:

  • The ugly enum_long macro goes away
  • Enum items are automatically embedded in a namespace
@dirkwhoffmann
Copy link
Owner Author

Switching to strongly-typed enum classes already pays off.

Background: vAmiga utilizes multiple so-called register change recorders to maintain pending register changes. A RegChangeRecorder is a ring buffer that stores objects of type RegChange (in a sorted order).

struct RegChangeRecorder : public util::SortedRingBuffer<RegChange, capacity>

RegChange is defined as follows: 

struct RegChange : Serializable
{
    u32 addr;
    u16 value;
    u16 accessor;
}  

With the benefit of strongly typed enum classes, the compiler now complains that I use the RegChange recorders inconsistently. 

I.e., Agnus stores enums of type RegChangeID in the address field, whereas the DIW sequencer, which maintains its own recorder, stores a plain chipset register address. 

I introduced RegChangeID a long time ago to distinguish between different accessors. I.e., there is a SET_BPLCON0_AGNUS and a SET_BPLCON0_DENISE.

enum RegChangeID : i32
{
    SET_NONE,
    …
    SET_INTREQ,
    SET_INTENA,
    SET_BPLCON0_AGNUS,
    SET_BPLCON0_DENISE,
    …
}

TODO: Trash the RegChangeID enum. As seen above, RegChange has a field called accessor, which can be used to distinguish the accessor. This field is currently unused. I guess I introduced it a while ago in order to get rid of RegChangeID as described and then forgot about it.

@dirkwhoffmann
Copy link
Owner Author

Accomplished. My old work-around to access enums on the Swift side is no longer needed:

/* The following macros 'enum_<type>' provide a way to make enumerations
 * easily accessible in Swift. All macros have two definitions, one for the
 * Swift side and one for the C side. Please note that the type mapping for
 * enum_long differs on both sides. On the Swift side, enums of this type are
 * mapped to 'long enums' to make them accessible via the Swift standard type
 * 'Int'. On the C side all enums are mapped to 'enum-less longs' to make them
 * easily serializable.
 */

#if defined(__SWIFT__)

// Definition for Swift
#define enum_generic(_name, _type) \
typedef enum __attribute__((enum_extensibility(open))) _name : _type _name; \
enum _name : _type

// #define enum_long(_name) enum_generic(_name, long)
#define enum_i8(_name) enum_generic(_name, i8)

#else

// Definition for C
#define enum_generic(_name, _type) \
typedef _type _name; \
enum : _type

// #define enum_long(_name) enum_generic(_name, long)
#define enum_i8(_name) enum_generic(_name, i8)

#endif

enum classes are mapped perfectly out of the box.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant