template<typenameCharT,size_t=sizeof(CharT)>structSSOPadding{charpadding[sizeof(CharT)-sizeof(char)];};template<typenameCharT>structSSOPadding<CharT,1>{// template specialization to remove the padding structure to avoid warnings on zero length arrays
// also, this allows us to take advantage of the empty-base-class optimization.
};// The view of memory when the string data is able to store the string data locally (without a heap allocation).
structSSOLayout{enum: size_type{SSO_CAPACITY=(sizeof(HeapLayout)-sizeof(char))/sizeof(value_type)};// mnSize must correspond to the last byte of HeapLayout.mnCapacity, so we don't want the compiler to insert
// padding after mnSize if sizeof(value_type) != 1; Also ensures both layouts are the same size.
structSSOSize:SSOPadding<value_type>{charmnRemainingSize;};value_typemData[SSO_CAPACITY];// Local buffer for string data.
SSOSizemRemainingSizeField;};
SSO에서는 이 24byte를 활용해서 문자열을 집어넣는다. 남은 문자를 저장하기 위해 최소 1byte를 남겨두고 나머지를 문자열을 담을 공간으로 활용한다.
여기서는 남은 문자열 크기(mnRemainingSize)를 padding까지 해서 무조건 HeapLayout의 마지막 byte에 두는데, 이는 지금 Heap인지 SSO인지 확인하는데 이 byte를 쓰기 때문이다.
#ifdef EA_SYSTEM_BIG_ENDIAN
// Big Endian use LSB, unless we want to reorder struct layouts on endianness, Bit is set when we are in Heap
staticconstexprsize_typekHeapMask=0x1;staticconstexprsize_typekSSOMask=0x1;#else
// Little Endian use MSB
staticconstexprsize_typekHeapMask=~(size_type(~size_type(0))>>1);staticconstexprsize_typekSSOMask=0x80;#endif
...inlineboolIsHeap()constEA_NOEXCEPT{return!!(sso.mRemainingSizeField.mnRemainingSize&kSSOMask);}...// Largest value for SSO.mnSize == 23, which has two LSB bits set, but on big-endian (BE)
// use least significant bit (LSB) to denote heap so shift.
inlinesize_typeGetSSOSize()constEA_NOEXCEPT{#ifdef EA_SYSTEM_BIG_ENDIAN
returnSSOLayout::SSO_CAPACITY-(sso.mRemainingSizeField.mnRemainingSize>>2);#else
return(SSOLayout::SSO_CAPACITY-sso.mRemainingSizeField.mnRemainingSize);#endif
}inlinevoidSetSSOSize(size_typesize)EA_NOEXCEPT{#ifdef EA_SYSTEM_BIG_ENDIAN
sso.mRemainingSizeField.mnRemainingSize=(char)((SSOLayout::SSO_CAPACITY-size)<<2);#else
sso.mRemainingSizeField.mnRemainingSize=(char)(SSOLayout::SSO_CAPACITY-size);#endif
}...inlinevoidSetHeapCapacity(size_typecap)EA_NOEXCEPT{#ifdef EA_SYSTEM_BIG_ENDIAN
heap.mnCapacity=(cap<<1)|kHeapMask;#else
heap.mnCapacity=(cap|kHeapMask);#endif
}inlinesize_typeGetHeapCapacity()constEA_NOEXCEPT{#ifdef EA_SYSTEM_BIG_ENDIAN
return(heap.mnCapacity>>1);#else
return(heap.mnCapacity&~kHeapMask);#endif
}
지금 상태가 Heap인지 SSO인지는 특이하게 판단한다. Layout의 마지막 byte에 masking bit를 넣어서 판단하는데, little endian이랑 big endian이랑 넣는 위치가 다르다.
little endian인 경우 해당 byte의 MSB
에다가 넣는다. 이경우 MSB가 1이면, SSO 입장에서는 mnRemainingSize가 음수이기 때문에 이런 상황이 나올 수가 없고, Heap 입장에서는 저 bit가 mnCapacity에선 매우 큰 값을 나타내기 때문에 masking에 써도 괜찮다.
big endian인 경우 해당 byte의 LSB
에다가 넣고, 실제 값은 왼쪽으로 shifting해서 넣는다. 여기서 SSO의 mnRemainingSize는 왼쪽으로 2번 shifting하는데 왜 그러는지는 모르겠다. 1번만 해도 될 것 같은데?
굳이 bool변수를 안 넣고 이렇게 masking bit를 넣는 것은 공간 낭비를 최소화하려고 그런게 아닐까 생각한다.