C language enumeration

  • C language enumeration writing method
Enum Enum name {Enumeration value 1, enumeration value 2,...... };Copy the code
  • We represent the seven days of the week by enumeration
enum Week {
	MON,TUS,WED,THU,FRI,SAT,SUN
};
Copy the code
  • In C, the default value of the first member of an enumeration is 0, and the subsequent enumeration value can be analogized, or the corresponding value can be specified directly, and the enumeration value after it is still incremented
enum Week { MON=3,TUS,WED,THU=9,FRI,SAT,SUN }; The values of this enumeration are 3,4,5,9,10,11,12Copy the code

Swift enumerated

Use of the Swift enumeration

  • Implement this enumeration as well, written as follows
Enum Week {case MON case TUS case WED case THU case FRI case SAT case SUN} Use commas enum Week {TUS case MON, WED, THU, FRI, SAT, SUN}Copy the code
  • This is an enumeration of integers, the same as in C,SwiftCan also be expressed by enumerationString
enum Week : String {
    case MON = "MON"
    case TUS = "TUS"
    case WED = "WED"
    case THU = "THU"
    case FRI = "FRI"
    case SAT = "SAT"
    case SUN = "SUN"
}
Copy the code
  • =On the right isSwiftIn theRawValueIf we don’t write the following string, it will defaultImplicit RawValue allocation, or you can specify members of the enumeration individuallyRawValue
  • Looking at the SIL file, you can see that one is automatically generatedinit? (rawValue:)Method, and onegetmethods
enum Week : String { case MON case TUS case WED case THU case FRI case SAT case SUN typealias RawValue = String init? (rawValue: String) var rawValue: String { get } }Copy the code
  • Let’s seeinit? (rawValue:)When is the function called, observed by the symbolic breakpoint

  • Run discovery:Week.MON.rawValueIt doesn’t triggerinitFunction, only callsWeek(rawValue: "MON")Will enter the symbol breakpoint, and then print the following code
Print (Week(rawValue: "MON")) print(Week(rawValue: "hello")) // Print result Optional(SwiftEnumerate.week.mon) nilCopy the code
  • View the SIL fileinitMethod, we will first put the enumeration values into an array, and then pass_findStringSwitchCaseMethod matches the string passed in and returns one if a match is foundindexIf no match is found, return one- 1If there is a match, the enumeration value is retrieved and returned as an optional value. If there is no match, the returned value is nil, so the return value is optional.
// Week.init(rawValue:) sil hidden @$s4main4WeekO8rawValueACSgSS_tcfC : $@convention(method) (@owned String, @thin Week.Type) -> Optional<Week> { // %0 "rawValue" // users: %164, %158, %79, %3 // %1 "$metatype" bb0(%0 : $String, %1 : $@thin Week.Type): %2 = alloc_stack $Week, var, name "self" // users: %162, %154, %143, %132, %121, %110, %99, %88, %165, %159 debug_value %0 : $String, let, name "rawValue", argno 1 // id: %3 %4 = integer_literal $Builtin.Word, 7 // user: % 6 / / function_ref _allocateUninitializedArray < A > (_) creates A tuple, there are enumerated values array, % 5 = function_ref @ $ss27_allocateUninitializedArrayySayxG_BptBwlF and Pointers: $@convention(thin) <τ_0_0> (builtin.word) -> (@owned Array<τ_0_0>, builtin.rawpointer) // user: %6 %6 = apply %5<StaticString>(%4) : $@convention(thin) <τ_0_0> (builtin.word) -> (@owned Array<τ_0_0>, builtin.rawpointer) // users: %8, %7 %7 = tuple_extract %6 : $(Array<StaticString>, Builtin.RawPointer), 0 // users: %80, %79 %8 = tuple_extract %6 : $(Array<StaticString>, Builtin.RawPointer), 1 // user: %9 %9 = pointer_to_address %8 : $Builtin.RawPointer to [strict] $*StaticString // users: %17, %69, %59, %49, %39, %29, %19 %10 = string_literal utf8 "MON" // user: %12 creates a string %11 = integer_literal $builtin. Word, 3 // user: %16 Its length is 3, the size we allocated in memory %12 = Builtin "ptrtoint_Word"(%10: $Builtin.RawPointer) : $Builtin.Word // user: %16 br bb1 // id: %13 bb1: // Preds: bb0 %14 = integer_literal $Builtin.Int8, 2 // user: %16 br bb2 // id: %15 bb2: // Preds: bb1 %16 = struct $StaticString (%12 : $Builtin.Word, %11 : $Builtin.Word, %14 : $Builtin.Int8) // user: %17 store %16 to %9 : $*StaticString // id: %17 %18 = integer_literal $Builtin.Word, 1 // user: %19 %19 = index_addr %9 : $*StaticString, %18 : $Builtin.Word // user: %20 = string_literal UTf8 "TUS" // user: %22 %21 = integer_literal $Builtin.Word, 3 // user: %26 %22 = builtin "ptrtoint_Word"(%20 : $Builtin.RawPointer) : $Builtin.Word // user: %26 br bb3 // id: %23 ...... bb14: // Preds: bb13 %76 = struct $StaticString (%72 : $Builtin.Word, %71 : $Builtin.Word, %74 : $Builtin.Int8) // user: %77 store %76 to %69 : $*StaticString // id: %77 // function_ref _findStringSwitchCase(cases:string:) %78 = function_ref @$ss21_findStringSwitchCase5cases6stringSiSays06StaticB0VG_SStF : $@convention(thin) (@guaranteed Array<StaticString>, @guaranteed String) -> Int // user: Index %79 = apply %78(%7, %0) : $@convention(thin) (@guaranteed Array<StaticString>, @guaranteed String) -> Int // users: %149, %138, %127, %116, %105, %94, %83, %147, %136, %125, %114, %103, %92, %81 release_value %7 : $Array<StaticString> // id: %80 debug_value %79 : $Int, let, name "$match" // id: %81 %82 = integer_literal $Builtin.Int64, 0 // user: %84 %83 = struct_extract %79 : $Int, #Int._value // user: %84 %84 = builtin "cmp_eq_Int64"(%82 : $Builtin.Int64, %83 : $Builtin.Int64) : $Builtin.Int1 // user: Cond_br %84, bb15, bb16 // id: % 85bb15: // Preds: bb14 %86 = metatype $@thin Week.Type %87 = enum $Week, #Week.MON! enumelt // user: %89 %88 = begin_access [modify] [static] %2 : $*Week // users: %89, %90 store %87 to %88 : $*Week // id: %89 end_access %88 : $*Week // id: %90 br bb29 // id: %91 ...... Preds: bb26 release_value %0: $String // id: %158 dealloc_stack %2: $*Week // id: %159 %160 = enum $Optional<Week>, #Optional.none! Enumelt // user: %161 br bb30(%160: $Optional<Week>) // id: %161 bb27 bb25 bb23 bb21 bb19 bb17 bb15 %162 = load %2 : $*Week // user: %163 %163 = enum $Optional<Week>, #Optional.some! enumelt, %162 : $Week // user: %166 release_value %0 : $String // id: %164 dealloc_stack %2 : $*Week // id: %165 br bb30(%163 : $Optional<Week>) // id: %166 // %167 // user: %168 bb30(%167 : $Optional<Week>): // Preds: bb29 bb28 return %167 : $Optional<Week> // id: %168 } // end sil function '$s4main4WeekO8rawValueACSgSS_tcfC'Copy the code
  • SwiftIn the source_findStringSwitchCaseThe implementation of the
/// The compiler intrinsic which is called to lookup a string in a table
/// of static string case values.
@_semantics("findStringSwitchCase")
public // COMPILER_INTRINSIC
func _findStringSwitchCase(
  cases: [StaticString],
  string: String) -> Int {

  for (idx, s) in cases.enumerated() {
    if String(_builtinStringLiteral: s.utf8Start._rawValue,
              utf8CodeUnitCount: s._utf8CodeUnitCount,
              isASCII: s.isASCII._value) == string {
      return idx
    }
  }
  return -1
}
Copy the code
  • Now, how do you get itrawValuethe
// main calls week.rawValue. getter to return the string sil@main: $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 { bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>): alloc_global @$s4main1aSSvp // id: %2 %3 = global_addr @$s4main1aSSvp : $*String // user: %8 %4 = metatype $@thin Week.Type %5 = enum $Week, #Week.MON! Enumelt / / user: % 7 MON / / create an enumerated values function_ref Week. RawValue. 6 = function_ref getter % @ $s4main4WeekO8rawValueSSvg: $@convention(method) (Week) -> @owned String // user: %7 %7 = apply %6(%5) : $@convention(method) (Week) -> @owned String // user: %8 store %7 to %3 : $*String // id: %8 %9 = integer_literal $Builtin.Int32, 0 // user: %10 %10 = struct $Int32 (%9 : $Builtin.Int32) // user: %11 return %10 : $Int32 // id: %11 } // end sil function 'main' // Week.rawValue.getter sil hidden @$s4main4WeekO8rawValueSSvg : $@convention(method) (Week) -> @owned String { // %0 "self" // users: %2, %1 bb0(%0 : $Week): debug_value %0 : $Week, let, name "self", argno 1 // id: %1 switch_enum %0 : $Week, case #Week.MON! enumelt: bb1, case #Week.TUS! enumelt: bb2, case #Week.WED! enumelt: bb3, case #Week.THU! enumelt: bb4, case #Week.FRI! enumelt: bb5, case #Week.SAT! enumelt: bb6, case #Week.SUN! Enumelt: bb7 // id: %2 // Match enumerations, build string returns bb1: // Preds: bb0 %3 = string_literal UTf8 "MON" // user: %8 %4 = integer_literal $Builtin.Word, 3 // user: %8 %5 = integer_literal $Builtin.Int1, -1 // user: %8 %6 = metatype $@thin String.Type // user: %8 // function_ref String.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:) %7 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String // user: %8 %8 = apply %7(%3, %4, %5, %6) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String // user: %9 br bb8(%8 : $String) // id: %9 ...... // user: %53 bb8(%52: $String): // Preds: bb7 bb6 bb5 bb4 bb3 bb2 bb1 return %52: $String // id: %53 } // end sil function '$s4main4WeekO8rawValueSSvg'Copy the code
  • In this case the enumerated values are string constants and should be stored in a Mach-O file__TEXT,__cstringAs you can see, currently we specifyenumtheRawValueforStringAfter that, the system automatically creates a contiguous memory space to hold the current by defaultcaseThe corresponding string.

One thing to note here is that enumerations and rawValues are two different things. There is no way to assign a String variable to an enumeration, even if the enum is of type String

The associated values

  • inSwiftIn, we can express complex information through enumeration values, that is, correlation values, through enumeration to express a shape, circle, rectangle, radius, rectangle width, height, this is very useful
enum Shape {
    case circle(radious:Double)
    case rectangle(width:Double,height:Double)
}
Copy the code
  • After we use the correlation value, noRawValueBecause each of uscaseAll have a set of values, so you don’t need to use themRawValueHere we useradious,width,heightIt’s a label we picked up ourselves. We can omit it
  • Creates an enumeration of associated values
enum Shape { case circle(radious:Double) case rectangle(width:Double,height:Double) } var circle = Shape.circle(radious: Rectangle = Shape. Rectangle (width: 50, height: 50)Copy the code

Other uses of enumeration

Pattern matching

  • useswitchWhen matching enumerated values, you need to traverse all possible cases, otherwise the compiler will report an error if you don’t want to match all of themcase, you can usedefalutThe keyword represents the default.

  • Matching of associated values
enum Shape { case circle(radious:Double) case rectangle(width:Double,height:Double) } var circle = Shape.circle(radious: Rectangle (width: 15.0, height: 18.0) switch circle {case let.circle (radious): print("circle radious\(radious)") case let .rectangle(width, height) : print("rectangle width:\(width),height:\(height)") } switch rectangle { case .circle(let radious): print("circle radious\(radious)") case .rectangle(let width,let height) : print("rectangle width:\(width),height:\(height)") }Copy the code
  • Matches a single association value
if case let Shape.circle(radious) = circle {
    print(radious)
}
Copy the code
  • differentcaseThe same associated value of
enum Shape{ case circle(radious: Double, diameter: Double) case rectangle(width: Double, height: Double) case square(width: Double, width: Double)} let shape = shape. circle(radious: 10.0, diameter: 20.0) switch Shape {case let. circle(x, 20.0), let. square(x, 20.0): print(x) default: break}Copy the code
  • Use wildcards
switch shape {
	case let .circle(_, x), let .square(x, _):
		print(x) 
    default:
		break
}

switch shape {
	case let .circle(x, y), let .rectangle(y, x):
		print("x=\(x),y=\(y)") 
    default:
		break
}
Copy the code

Nesting of enumerations

  • Enumerations nested within enumerations
enum CombineDirect{
    enum BaseDirect{
        case up
        case down
        case left
        case right
    }

    case leftUp(combineElement1: BaseDirect, combineElement2: BaseDirect)
    case rightUp(combineElement1: BaseDirect, combineElement2: BaseDirect)
    case leftDown(combineElement1: BaseDirect, combineElement2: BaseDirect)
    case rightDown(combineElement1: BaseDirect, combineElement2: BaseDirect)
}
Copy the code

Nesting in a structure

  • Nested enumerations in a structure
struct Skill {
    enum KeyType {
        case up
        case down
        case left
        case right
    }
    
    let key : KeyType
}
Copy the code

Enumerations contain properties and methods

  • Enumerations can contain computed properties, type properties, but not storage properties

  • Enumeration defines instance methods,staticmethods
enum Week : Int {
    case MON
    case TUS
    case WED
    case THU
    case FRI
    case SAT
    case SUN
    
    mutating func nextDay() {
        if self == .SUN {
            self = Week(rawValue: 1)!
        }else{
            self = Week(rawValue: 1+self.rawValue)!
        }
    }
    static func doSomething() {
        print("111\(self.init(rawValue: 1))")
    }
    
}
Copy the code

Size of enumeration

  • acaseSize of time
Enum noMean {case a} print(MemoryLayout<noMean>. Size) print(MemoryLayout<noMean>. Stride) // The result is 0 1Copy the code
  • ordinarycaseWhen there is no associated value, the size of the enumeration is one byte, and the maximum that a byte can represent is 255 if ourcaseAbove 255, the size changes fromInt8->Int16If not, it will continue to double
Enum noMean {case A case B} print(MemoryLayout<noMean>. Size) print(MemoryLayout<noMean>. Stride) 1 1 // Changes the rawValue type. The print result remains unchanged. Enum noMean: String {case A case B} // The print result is 1 1Copy the code
  • The size of an enumeration with associated values depends on the largestcaseMemory size, but if you look at it it should be 16, 24, 32, even numbers, but I’m adding 1 every time, so this is where we are right nowcaseIt takes 1 byte. There is only onecaseBy defaultsizeTo zero.
enum Shape{ case circle(radious: Print (MemoryLayout<Shape>.size) print(MemoryLayout<Shape>.stride) 8 enum Shape{ case circle(radious: Double) case rectangle(width: Double, height: Print (MemoryLayout<Shape>. Size) print(MemoryLayout<Shape>. StrideCopy the code
  • Print memory structure

Note that, due to byte alignment, sometimes the 1 byte of 'case' will be optimized by the compiler to be added to the previous position, and its size will not be +1Copy the code
  • Let’s verify this with a little bit of code

  • Modify thecircletheradiousThe type ofInt

  • conclusion
    • 1,RawValueThe default size of the enumeration is 1 byte (UInt8), which means the current maximum size can be stored is 255. If this size is exceeded, the size of the current enumeration is changed fromUInt8->UInt16So on
    • 2, the enumeration size of the associated value and the maximumcaseThe memory size of.

An indirect keyword

  • We want to implement a linked list through enumeration, we need to useindirectThe keyword

  • The modified version of the compiler looks like this
Indirect enum List<T> {case end case node(T, next: List<T>)} or enum List<T> {case end case node(T, next: List<T>) }Copy the code
  • Enumeration is a value type, which means that its size is determined at compile time, so this process is very important for our current oneListFrom a system perspective, I don’t know how much memory I’m currently allocating to this enumeration. So what? The official documentation explains it as follows

You indicate that an enumeration case is recursive by writing indi rect before it, which tells the compiler to insert the necessary l ayer of indirection.

  • Let me print the size

  • Print the memory structure of the instance object

  • View the SIL file,alloc_boxThe essence of callswift_allocObjet, soindirectThe keyword tells the compiler that my enumeration is recursive, so I’m not sure of its size, so I need to allocate a heap of memory for it.

Swift enumeration and OC mixed

Oc uses Swift enumeration

  • The enumeration in OC is just an integer value, if you want to use theSwiftIs exposed to oc and needs to be added@objcKeyword, and the current enumeration should beIntThe type of
@objc enum Week : Int{
    case MON
    case TUE
}
Copy the code
  • inxxx-Swift.hDefinition in header file, import header file can be used in OC
typedef SWIFT_ENUM(NSInteger, Week, closed) {
  WeekMON = 0,
  WeekTUE = 1,
};
Copy the code

Swift uses OC enumeration

  • Define the following three enums through OC
NS_ENUM(NSInteger, OCENUM){
    Value1,
    Value2
};

typedef enum{
    Num1,
    Num2
} OCNum;

typedef NS_ENUM(NSInteger, CEnum) {
    CEnumInvalid = 0,
    CEnumA = 1,
    CEnumB,
    CEnumC
};
Copy the code
  • View the correspondingSwiftThe header file
public var OCENUM: OCENUM
public enum OCENUM : Int {
    case Value1 = 0
    case Value2 = 1
}

public struct OCNum : Equatable, RawRepresentable {
    public init(_ rawValue: UInt32)
    public init(rawValue: UInt32)
    public var rawValue: UInt32
}

public enum CEnum : Int {
    case invalid = 0
    case A = 1
    case B = 2
    case C = 3
}
Copy the code