It is currently Tue May 26, 2020 12:43 am

All times are UTC + 1 hour




Post new topic Reply to topic  [ 2 posts ] 
Author Message
 Post subject: Scoped enumerations with added features
PostPosted: Thu Jul 19, 2018 8:52 pm 
Offline
Addict
Addict

Joined: Sat Jun 30, 2007 8:04 pm
Posts: 3362
This is similar to features provided by the Enum class in Java. It allows enumerations to hold additional information and for their type to be queried for validity.

Code:
DeclareModule ENUM_CARDINAL_DIRECTION
  Structure Class
    *vTable
    name.s
    ordinal.i
  EndStructure
 
  ; --
 
  Macro POINTER
    i
  EndMacro
 
  Interface Public
    name.s()
    ordinal.i()
  EndInterface
 
  ;/ Static
  Declare new(ordinal.i, name.s)
  Declare.POINTER fromOrdinal(ordinal.i)
  Declare.POINTER valueOf(name.s)
 
  NewMap values.Public()
 
  NONE.Public=new(1,"NONE")
  NORTH.Public=new(2,"NORTH")
  EAST.Public=new(3,"EAST")
  SOUTH.Public=new(4,"SOUTH")
  WEST.Public=new(5,"WEST")
EndDeclareModule

Module ENUM_CARDINAL_DIRECTION
  Structure VTable
    *name
    *ordinal
  EndStructure
 
  Declare setVTable(*vTable.Class)
 
  ;/ Static
  Global vTable.VTable
  setVTable(@vTable)
 
  Procedure new(ordinal.i, name.s)
    Protected *instance.Class
   
    *instance=AllocateStructure(Class)
    *instance\vTable=@vTable
   
    *instance\name.s=name.s
    *instance\ordinal=ordinal
   
    ENUM_CARDINAL_DIRECTION::values(Str(ordinal))=*instance
   
    ProcedureReturn *instance
  EndProcedure
 
  Procedure.POINTER fromOrdinal(ordinal.i)
    ProcedureReturn ENUM_CARDINAL_DIRECTION::values(Str(ordinal))
  EndProcedure
 
  Procedure.POINTER valueOf(name.s)
    ForEach ENUM_CARDINAL_DIRECTION::values()
      If ENUM_CARDINAL_DIRECTION::values()\name()=name.s
        ProcedureReturn ENUM_CARDINAL_DIRECTION::values()
      EndIf
    Next
   
    ProcedureReturn #Null
  EndProcedure
 
  ;/ Public
  Procedure.s name(*this.Class)
    ProcedureReturn *this\name.s
  EndProcedure
 
  Procedure.i ordinal(*this.Class)
    ProcedureReturn *this\ordinal
  EndProcedure
 
  ;/ Private
  Procedure setVTable(*vTable.VTable)
    *vTable\name=@name()
    *vTable\ordinal=@ordinal()
  EndProcedure
EndModule

Interface ENUM_CARDINAL_DIRECTION Extends ENUM_CARDINAL_DIRECTION::Public
EndInterface


Demonstration:

Code:
;/ Enums can have names (for debug and serialization)
Debug ENUM_CARDINAL_DIRECTION::NONE\name()

Debug "--"

;/ Query the enum for all values
ForEach ENUM_CARDINAL_DIRECTION::values()
  With ENUM_CARDINAL_DIRECTION::values()
    Debug Str(\ordinal())+" "+\name()
  EndWith
Next

Debug "--"

;/ Deserialize and validation
If Not ENUM_CARDINAL_DIRECTION::valueOf("UNKNOWN")
  Debug "No enum by that name"
EndIf

Debug "--"

;/ From ordinal
Define result.ENUM_CARDINAL_DIRECTION

reuslt=ENUM_CARDINAL_DIRECTION::fromOrdinal(3)

Debug result\name()


Output:

Code:
NONE
--
1 NONE
2 NORTH
3 EAST
4 SOUTH
5 WEST
--
No enum by that name
--
EAST


Top
 Profile  
Reply with quote  
 Post subject: Re: Scoped enumerations with added features
PostPosted: Sun Oct 20, 2019 9:58 pm 
Offline
Addict
Addict

Joined: Sat Jun 30, 2007 8:04 pm
Posts: 3362
Improved base class module "Enum" which removes a lot of code duplication:

https://github.com/codespunk/libcodespu ... st/enum.pb

Code:
XIncludeFile #CODESPUNK_HOME+"/purebasic/mod_Assertion.pb"
XIncludeFile #CODESPUNK_HOME+"/purebasic/mod_SAL.pb"
XIncludeFile #CODESPUNK_HOME+"/purebasic/mod_Type.pb"

EnableExplicit

DeclareModule Enum
  UseModule SAL
 
  Macro ORDINAL_TYPE
    Type::INT_32
  EndMacro
 
  Interface IObject
    name.s()
    ordinal.ORDINAL_TYPE()
  EndInterface
 
  Macro OBJECT_POINTER
    Type::POINTER
  EndMacro
EndDeclareModule

Module Enum
  UseModule SAL
EndModule

DeclareModule _Enum
  UseModule SAL
  UseModule Enum
 
  Structure VTable
    *name
    *ordinal
  EndStructure
 
  Structure Class
    *vTable
    name.s
    ordinal.ORDINAL_TYPE
  EndStructure
 
  ;/ Static
  Global vTable.VTable
 
  Declare.OBJECT_POINTER new(_IN_OUT Map values.IObject(), _IN ordinal.ORDINAL_TYPE, _IN name.s)
  Declare.OBJECT_POINTER fromOrdinal(_IN_OUT Map values.IObject(), _IN ordinal.ORDINAL_TYPE)
  Declare.OBJECT_POINTER valueOf(_IN_OUT Map values.IObject(), _IN name.s)
EndDeclareModule

Module _Enum
  UseModule Assertion
  UseModule SAL
 
  Procedure.OBJECT_POINTER new(_IN_OUT Map values.IObject(), _IN ordinal.ORDINAL_TYPE, _IN name.s)
    Protected *instance.Class
   
    *instance=AllocateStructure(Class)
    *instance\vTable=@vTable
   
    *instance\name.s=name.s
    *instance\ordinal=ordinal
   
    values(Str(ordinal))=*instance
   
    ProcedureReturn *instance
  EndProcedure
 
  Procedure.OBJECT_POINTER fromOrdinal(_IN_OUT Map values.IObject(), _IN ordinal.ORDINAL_TYPE)
    ASSERT_MAP_KEY(values(),Str(ordinal))
   
    ProcedureReturn values(Str(ordinal))
  EndProcedure
 
  Procedure.OBJECT_POINTER valueOf(_IN_OUT Map values.IObject(), _IN name.s)
    ForEach values()
      If values()\name()=name.s
        ProcedureReturn values()
      EndIf
    Next
   
    ASSERT(#False,"Invalid name")
   
    ProcedureReturn #Null
  EndProcedure
 
  ;/ IObject methods
  Procedure.s name(_IN *this.Class)
    ProcedureReturn *this\name.s
  EndProcedure
 
  Procedure.ORDINAL_TYPE ordinal(_IN *this.Class)
    ProcedureReturn *this\ordinal
  EndProcedure
 
  vTable\name=@name()
  vTable\ordinal=@ordinal()
EndModule

DisableExplicit


Example:

Code:
XIncludeFile #CODESPUNK_HOME+"/purebasic/mod_Enum.pb"
XIncludeFile #CODESPUNK_HOME+"/purebasic/mod_SAL.pb"
XIncludeFile #CODESPUNK_HOME+"/purebasic/mod_Type.pb"


DeclareModule _ENUM_CARDINAL_DIRECTION
  UseModule SAL
 
  #ENUM_CARDINAL_DIRECTION_NONE=1
  #ENUM_CARDINAL_DIRECTION_NORTH=2<<0
  #ENUM_CARDINAL_DIRECTION_EAST=2<<1
  #ENUM_CARDINAL_DIRECTION_SOUTH=2<<2
  #ENUM_CARDINAL_DIRECTION_WEST=2<<3
  #ENUM_CARDINAL_DIRECTION_NORTHEAST=#ENUM_CARDINAL_DIRECTION_NORTH|#ENUM_CARDINAL_DIRECTION_EAST
  #ENUM_CARDINAL_DIRECTION_SOUTHEAST=#ENUM_CARDINAL_DIRECTION_SOUTH|#ENUM_CARDINAL_DIRECTION_WEST
  #ENUM_CARDINAL_DIRECTION_SOUTHWEST=#ENUM_CARDINAL_DIRECTION_NORTH|#ENUM_CARDINAL_DIRECTION_EAST
  #ENUM_CARDINAL_DIRECTION_NORTHWEST=#ENUM_CARDINAL_DIRECTION_SOUTH|#ENUM_CARDINAL_DIRECTION_WEST
  #ENUM_CARDINAL_DIRECTION_UP=2<<4
  #ENUM_CARDINAL_DIRECTION_DOWN=2<<5
EndDeclareModule

Module _ENUM_CARDINAL_DIRECTION
EndModule

DeclareModule ENUM_CARDINAL_DIRECTION
  UseModule _ENUM_CARDINAL_DIRECTION
  UseModule SAL
 
  Macro OBJECT_POINTER
    Type::POINTER
  EndMacro
 
  Interface IObject Extends ENUM::IObject
  EndInterface
 
  ;/ Static
  Global NewMap values.ENUM::IObject()
 
  ;/ Static methods
  Declare.OBJECT_POINTER fromOrdinal(_IN ordinal.Type::INT_32)
  Declare.OBJECT_POINTER valueOf(_IN name.s)
 
  ;/ Static variables
  NONE.IObject=_Enum::new(values(),#ENUM_CARDINAL_DIRECTION_NONE,"CARDINAL_DIRECTION_NONE")
  NORTH.IObject=_Enum::new(values(),#ENUM_CARDINAL_DIRECTION_NORTH,"CARDINAL_DIRECTION_NORTH")
  EAST.IObject=_Enum::new(values(),#ENUM_CARDINAL_DIRECTION_EAST,"CARDINAL_DIRECTION_EAST")
  SOUTH.IObject=_Enum::new(values(),#ENUM_CARDINAL_DIRECTION_SOUTH,"CARDINAL_DIRECTION_SOUTH")
  WEST.IObject=_Enum::new(values(),#ENUM_CARDINAL_DIRECTION_WEST,"CARDINAL_DIRECTION_WEST")
  NORTHEAST.IObject=_Enum::new(values(),#ENUM_CARDINAL_DIRECTION_NORTHEAST,"CARDINAL_DIRECTION_NORTHEAST")
  SOUTHEAST.IObject=_Enum::new(values(),#ENUM_CARDINAL_DIRECTION_SOUTHEAST,"CARDINAL_DIRECTION_SOUTHEAST")
  SOUTHWEST.IObject=_Enum::new(values(),#ENUM_CARDINAL_DIRECTION_SOUTHWEST,"CARDINAL_DIRECTION_SOUTHWEST")
  NORTHWEST.IObject=_Enum::new(values(),#ENUM_CARDINAL_DIRECTION_NORTHWEST,"CARDINAL_DIRECTION_NORTHWEST")
  UP.IObject=_Enum::new(values(),#ENUM_CARDINAL_DIRECTION_UP,"CARDINAL_DIRECTION_UP")
  DOWN.IObject=_Enum::new(values(),#ENUM_CARDINAL_DIRECTION_DOWN,"CARDINAL_DIRECTION_DOWN")
 
  Declare.OBJECT_POINTER fromOrdinal(_IN ordinal.Type::INT_32)
  Declare.OBJECT_POINTER valueOf(_IN name.s)
EndDeclareModule

Module ENUM_CARDINAL_DIRECTION
  Procedure.OBJECT_POINTER fromOrdinal(_IN ordinal.Type::INT_32)
    ProcedureReturn _Enum::fromOrdinal(values(), ordinal)
  EndProcedure
 
  Procedure.OBJECT_POINTER valueOf(_IN name.s)
    ProcedureReturn _Enum::valueOf(values(), name.s)
  EndProcedure
EndModule

;/ Enums can have names (for debug and serialization)
Debug ENUM_CARDINAL_DIRECTION::NONE\name()

Debug "--"

;/ Query the enum for all values
ForEach ENUM_CARDINAL_DIRECTION::values()
  With ENUM_CARDINAL_DIRECTION::values()
    Debug Str(\ordinal())+" "+\name()
  EndWith
Next

Debug "--"

;/ From ordinal
Define result.ENUM_CARDINAL_DIRECTION::IObject

result=ENUM_CARDINAL_DIRECTION::fromOrdinal(4)

Debug result\name()

Debug "--"

;/ Deserialize and validation
If Not ENUM_CARDINAL_DIRECTION::valueOf("UNKNOWN")
  Debug "No enum by that name"
EndIf


Output:

Code:
CARDINAL_DIRECTION_NONE
--
0 CARDINAL_DIRECTION_NONE
2 CARDINAL_DIRECTION_NORTH
4 CARDINAL_DIRECTION_EAST
6 CARDINAL_DIRECTION_SOUTHWEST
8 CARDINAL_DIRECTION_SOUTH
16 CARDINAL_DIRECTION_WEST
24 CARDINAL_DIRECTION_NORTHWEST
32 CARDINAL_DIRECTION_UP
64 CARDINAL_DIRECTION_DOWN
--
CARDINAL_DIRECTION_EAST
--
<Assertion>


Dependencies:
https://github.com/codespunk/libcodespu ... sertion.pb
https://github.com/codespunk/libcodespu ... od_Enum.pb
https://github.com/codespunk/libcodespu ... mod_SAL.pb
https://github.com/codespunk/libcodespu ... od_Type.pb


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 2 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 20 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

 


Powered by phpBB © 2008 phpBB Group
subSilver+ theme by Canver Software, sponsor Sanal Modifiye