This article begins with a small example

Enum A {case a1(A :Int8,b:Int,c:Int16)} print(MemoryLayout<A>.size) print(MemoryLayout<A>.stride)Copy the code

Enum A {case a0(A :Int); Case a1(a:Int8,b:Int,c:Int16)} print(MemoryLayout< a >.size) print(MemoryLayout< a >.size)Copy the code

One is 18 and the other is 19. The 1 difference is because the enumeration case also needs a byte to store, so when is +1 and when is not +1 ???? Let’s explore that

How do you first determine how much memory is used by associative enumerations?

Take the maximum memory size used by each case. The rules for calculating the memory size used by each case are as follows:

The sum of the bytes used by the first n-1 argument must be the smallest positive integer multiple of the bytes used by the NTH argument or 8 bytes

enum Test{
     case enum1(t1:Int)
     case enum2(t1:Int8,t2:Int16,t3:Int)
     case enum3(t1:Int8,t2:Int,t3:Int16,t4:Int32)
     case enum4(t1:Int8,t2:Int,t3:Int16,t4:Int,t5:Int8,t6:String)
}
Copy the code

Enum1 is 8 bytes. No alignment is required

Enum2,2,8 (1) a total of 11 bytes, because 1 divided by 2 cannot be divided exactly by the need to take 1 to 2 take into,2,8 (2), and 2 + 2 8 cannot fill divisible requires 4 divided by 2 to 6 to take up as,6,8 (2)

Enum3 contains 15 bytes (1,8,2,4). Since 1 is not divisible by 8, add 7 to enum4. In this case,8 +8 is divisible by 2.

Enum4 (1,8,2,8,1,16) (8,8,2,8,1,16) (8,8,2,8,1,16) (8,8,2,8,1,16) (8,8,2,8,1,16) (8,8,2,8,1,16) Because 8+8+8+8+ 8 =33, who should we compare 33 with? We know that the system is aligned with 8 bytes, so expanding 16 bytes will waste space, so we need to add 7 (8,8,8,8,8,16).

See the article Swift enumeration associated value occupancy

We will become a real store actual content storage area and align with memory allocation of storage space for more called expand a (this is a temporary concept, help to understand the content), will take intersection all take out the expansion of a case, if the result is empty, the system can determine the current inside the memory allocated to you you must have to use the area of less than, This area can be used to store cases. Let’s verify this

For example,

Enum A {//1 case a0(A :Int8) //1+ 1=2 case a1(A :Int8,b:Int8) //1+2+ 2 Case a2(a:Int8,b:Int16,c:Int) // Case A2 (a:Int8,b:Int16,c:Int) // Case A2 (a:Int8,b:Int16,c:Int) // Case A2 (A :Int8,b:Int16,c:Int) // Case A2 (A :Int8,b:Int16,c:Int) // Case A2 (A :Int8, B :Int16,c:Int) // Case A2 (A :Int8, B :Int16,c:Int A3 (a:Int8,b:Int32,c:Int)} 1) //1-8 bytes store two values of type Int8, is 1 byte aligned //1-8 bytes memory layout 01 02 00 00 00 00 00 00 00 Var a2 = a.a2 (a: 1, b: 2,c: 1, b: 2,c: 1) 3) //1-8 byte memory layout 01 00 00 00 02 00 00 00 00 var a3 = a3(a: 1, b: 2,c: 1) 3) print(MemoryLayout<A>.size) print(MemoryLayout<A>.stride) print("end")Copy the code

verify

So from here we know that the enumeration takes 16 bytes, and the real storage bits and expansion bits for A0, A1, A2, and A3 are

A0 Real storage bits: [1]

A0 expansion:,3,4,5,6,7,8,9,10,11,12,13,14,15,16 [2]

A1 real storage bits: [1,2]

A1 expansion:,4,5,6,7,8,9,10,11,12,13,14,15,16 [3]

A2 real storage:,3,4,9,10,11,12,13,14,15,16 [1]

A2 expansion bit: [2,5,6,7,8]

A3 real storage:,5,6,7,8,9,10,11,12,13,14,15,16 [1]

A3 expansion bits: [2,3,4]

If we set the intersection of all extended bits to null, then we need to create another byte to store the enumerated cases, so we need to +1

Enum A {case A0 (A :Int8) //1 byte Case A1 (A :Int8,b:Int8) //1+1=2 bytes Case A2 (A :Int8, B :Int16,c:Int) //8+8=16 bytes CASE Print (MemoryLayout< a >.size) print(MemoryLayout< a >.size) print(MemoryLayout< a >.size) print(MemoryLayout< a >.size)Copy the code

Let’s change the second parameter of A3 to Int16

Enum A {//1 case a0(A :Int8) //1+ 1=2 case a1(A :Int8,b:Int8) //1+2+ 2 1/2 for positive integer - > 2 + 2 + 8 4/8 not positive integer - > 2 + 6 + 8 = 16 case a2 (a: Int8, b: Int16, c: Int) / / 1 + 2 + 8, Case A3 (a:Int8,b:Int16,c: Int16)} // If (a:Int8,b:Int16,c: Int8) Yes 1 byte alignment //1-8 byte memory layout 01 00 00 00 00 00 00 00 00 var a0 = A.a0(a: 1) //1-8 bytes store two values of type Int8, is 1 byte aligned //1-8 bytes memory layout 01 02 00 00 00 00 00 00 00 Var a2 = a.a2 (a: 1, b: 2,c: 1, b: 2,c: 1) 3) //1-8 byte memory layout 01 00 00 00 02 00 00 00 00 var a3 = a3(a: 1, b: 2,c: 1) 3) print(MemoryLayout<A>.size) print(MemoryLayout<A>.stride) print("end")Copy the code

Real storage bits and expansion bits of A0, A1, A2, and A3

A0 Real storage bits: [1]

A0 expansion:,3,4,5,6,7,8,9,10,11,12,13,14,15,16 [2]

A1 real storage bits: [1,2]

A1 expansion:,4,5,6,7,8,9,10,11,12,13,14,15,16 [3]

A2 real storage:,3,4,9,10,11,12,13,14,15,16 [1]

A2 expansion bit: [2,5,6,7,8]

A3 real storage:,3,4,9,10,11,12,13,14,15,16 [1]

A3 expansion bits: [2,5,6,7,8]

The result is [5,6,7,8], so there is no need to create another byte to store the enumerated cases, so there is no need to add +1

Enum A {case A0 (A :Int8) //1 byte Case A1 (A :Int8,b:Int8) //1+1=2 bytes Case A2 (A :Int8, B :Int16,c:Int) //8+8=16 bytes CASE } var a3 = a.3 (a: 1, b: 2, c: 2);} var a3 = a.3 (a: 1, b: 2, c: 2); 3) print(MemoryLayout<A>.size) print(MemoryLayout<A>.stride) print("end")Copy the code

After observation, the case will be stored on the last bit of the expanded bit intersection, verification is over!!

Memory layout for associated enumerations (part 2)