After seeing a glimpse of memory from assembly to Swift enumeration on the nuggets, the author analyzes the memory layout of several different enumerations, but I feel that the coverage is not comprehensive enough to complement the author’s article. It is suggested to read the author’s article first. The author’s conclusion is as follows:

Enumeration of associated values: Sum of maximum bytes extra + 1 Storage of the last byte Case Type Non-associated values Enumeration: Memory occupied 1 byte Values with subscripts are accumulated in the memory

doubt

Do not know after you read, have I same question?

  1. Ordinary enumeration takes up one byte of memory, and a byte can only be from 0 to 255 at most. What happens when case has more than 256 options
  2. What if the association value type is protocol, struct, class, or other enumeration? What is the memory footprint at this point
  3. What about recursive enumeration?

The answer

  • The show function in the test code will print the address, memory, and size of the enumeration from the copied Mems
func test(){
     enum TestEnum {
       case testCase1
       case testCase2
    }
   var testEnum = TestEnum.testCase1
   show(val: &testEnum)
   testEnum = .testCase2
   show(val: &testEnum)
}
Copy the code

  • When there are too many case options beyond 256, such as 300, it will take up 2 bytes. Since there are too many cases for more than 2 bytes, I did not test it, but it should be an analogy
/ / testcaseWhen too much functest1(){
    var testEnum = MoreCaseEnum.case257
    show(val: &testEnum)
}
Copy the code

  • When the correlation value is a structure, it is the same as the author’s conclusion
struct TestStruct: TestProtocol {
    var testPropetry1 = 10
    var testPropetry2 = 11
    var testPropetry3 = 12
    var testPropetry4 = 13
    var testPropetry5 = 14
}
func test2() {
    enum TestStructEnum {
        case testCase1
        case testCase2(TestStruct)
        case testCase3
    }
    var testEnum = TestStructEnum.testCase1
    show(val: &testEnum)
    testEnum = .testCase2(TestStruct())
    show(val: &testEnum)
    testEnum = .testCase3
    show(val: &testEnum)
}
Copy the code

  • If the value of the enumeration is class, then the address of the object is stored. If the value of the enumeration is class, then the address of the object is stored. If the value of the enumeration is class, then the address of the object is stored
// The test association value is of type class functest3() {
    enum TestClassEnum {
        case testCase1
        case testCase2(TestClass)
        case testCase3
    }
    var testEnum = TestClassEnum.testCase1
    show(val: &testEnum)
    testEnum = .testCase2(TestClass())
    show(val: &testEnum)
    testEnum = .testCase3
    show(val: &testEnum)
}
Copy the code

  • When the associated value is of type class+bool(Int16, Int8, Int16, Int16, Int8), the associated value is of type class+bool. Enumeration takes up 8 bytes. If the associated value is an object, it stores the address of the object. Otherwise, the first half of the 8 bytes stores the discriminating type, and the second half stores the associated value or the location of the enumerated case (I haven’t detected the specific rule).
func test4() {
    enum TestClassOtherEnum {
        case testCase1
        case testCase2(TestClass)
        case testCase3(Bool)
    }
    var testEnum = TestClassOtherEnum.testCase1
    show(val: &testEnum)
    testEnum = .testCase2(TestClass())
    show(val: &testEnum)
    testEnum = .testCase3(true)
    show(val: &testEnum)
}
Copy the code

  • Conclusion: Enumerations take up one byte, with the first four bits identifying the type and the last four bits representing the specific value
func test5() {
    enum TestEnum {
        case testCase1
        case testCase2
    }
    enum TestSamllEnum {
        case testCase1
        case testCase2(TestEnum)
        case testCase3(Bool)
    }
    var testEnum = TestSamllEnum.testCase1
    show(val: &testEnum)
    testEnum = .testCase2(.testCase2)
    show(val: &testEnum)
    testEnum = .testCase3(true)
    show(val: &testEnum)
}
Copy the code

  • Conclusion when the type of the associated value is protocol: Enumeration occupies 40 bytes, and the last item is to distinguish the type. For case of associated value protocol, if the protocol satisfies class, the first item is the address of class. If the protocol satisfies struct, and the space occupied by struct is not more than 24, then the first three items store structure values. Otherwise, the value of the structure is stored externally
func test6() {
    enum TestProtocolEnum {
        case testCase1
        case testCase2(TestProtocol)
        case testCase3
    }
    var testEnum = TestProtocolEnum.testCase1
    show(val: &testEnum)
    testEnum = .testCase2(TestClass())
    show(val: &testEnum)
    testEnum = .testCase2(TestStruct())
    show(val: &testEnum)
    testEnum = .testCase3
    show(val: &testEnum)
}
Copy the code

  • When the enumeration type is recursive, the space occupied is always 8
func test7() {
    indirect enum TestIndirectEnum {
        case testCase1
        case testCase2(TestIndirectEnum)
        case testCase3
    }
    var testEnum = TestIndirectEnum.testCase1
    show(val: &testEnum)
    testEnum = .testCase2(.testCase3)
    show(val: &testEnum)
    testEnum = .testCase3
    show(val: &testEnum)
}
Copy the code

Other

All the above conclusions are tested and summarized, cannot guarantee absolute correctness, only for reference, test demo

Refer to the link

  • A glimpse of memory from assembly to Swift enumeration

  • Mems