|
HMDT - Special Issue / CoreFoundation の秘密 / Collection Services - CFArray の実装 |
- Collection Services -
|
|
CoreFoundation/Collections.subproj/CFArray.c
|
struct __CFArrayImmutable {
CFRuntimeBase _base;
CFIndex _count; /* number of objects */
};
|
最初に CFRuntimeBase があって、次に配列の中にあるオブジェクトの数がある。
CFMutableArray の方はこんな感じ。
|
CoreFoundation/Collections.subproj/CFArray.c
|
struct __CFArrayFixedMutable {
CFRuntimeBase _base;
CFIndex _count; /* number of objects */
CFIndex _capacity; /* maximum number of objects */
};
|
CFRuntimeBase と、オブジェクトの数があって、格納できるオブジェクトの最大数がある。
あれ?じゃ、実際に入るオブジェクトはどこに?実は、この構造体は配列のヘッダみたいなもので、こいつらの後ろにメモリが確保されてその中に入る。オブジェクトは次の __CFArrayBucket っていう構造体に入れられるんだ。
|
CoreFoundation/Collections.subproj/CFArray.c
|
struct __CFArrayBucket {
const void *_item;
};
|
まぁ、ただのポインタだわな。というわけで、CFArray と CFMutableArray の構造を図に描くと、こうなる。


メモリの固まりにオブジェクトが入っているんだ。リンクリストじゃないんだよ。
![]()
次は配列を作るところを見てみよう。配列を作る API は次の 4 つ。固定長か可変長か、オブジェクトをコピーするしないか、で分かれる。
|
CoreFoundation/Collections.subproj/CFArray.h
|
CF_EXPORT
CFArrayRef CFArrayCreate(
CFAllocatorRef allocator,
const void **values,
CFIndex numValues,
const CFArrayCallBacks *callBacks);
CF_EXPORT
CFArrayRef CFArrayCreateCopy(
CFAllocatorRef allocator,
CFArrayRef theArray);
CF_EXPORT
CFMutableArrayRef CFArrayCreateMutable(
CFAllocatorRef allocator,
CFIndex capacity,
const CFArrayCallBacks *callBacks);
CF_EXPORT
CFMutableArrayRef CFArrayCreateMutableCopy(
CFAllocatorRef allocator,
CFIndex capacity,
CFArrayRef theArray);
|
これらの実装がどうなっているかというと、4 つとも __CFArrayInit() っていう関数を呼び出している。この中で CFArray を作ったり、メモリを確保したりしているんだ。こいつを見てみよう。
|
CoreFoundation/Collections.subproj/CFArray.c
|
static CFArrayRef __CFArrayInit(
CFAllocatorRef allocator,
UInt32 flags,
CFIndex capacity,
const CFArrayCallBacks *callBacks)
{
struct __CFArrayImmutable *memory;
UInt32 size;
...
size = __CFArrayGetSizeOfType(flags) - sizeof(CFRuntimeBase);
switch (__CFBitfieldGetValue(flags, 1, 0)) {
case __kCFArrayImmutable:
case __kCFArrayFixedMutable:
/* サイズを決定 */
/* 容量の大きさ×__CFArrayBucket の大きさ */
size += capacity * sizeof(struct __CFArrayBucket);
break;
case __kCFArrayMutableDeque:
case __kCFArrayMutableStore:
break;
}
/* サイズの大きさだけインスタンスを確保 */
memory = (struct __CFArrayImmutable *)_CFRuntimeCreateInstance(
allocator, __kCFArrayTypeID, size, NULL);
if (NULL == memory) {
return NULL;
}
...
return (CFArrayRef)memory;
}
|
ということで、指定した大きさの分だけバケツを確保してできあがり、というわけだ。
![]()
配列の実装をメモリの固まりで行っている(リンクリストじゃない)ことから、オブジェクトをインデックスを指定して取得するのは速いけど、追加したり削除したりという操作は遅いことが予想できるよね。次の項で、そこを見てみよう。
(Jan. 24, 2003)
|
Home | Link | Download | Back Number | Speciall Issue
|