Android Utils 之 Vector 學習筆記(一)—— VectorImpl 程式碼分析

StoneDemo發表於2018-07-11

前言

在維護 Android Framework 層時,常常能看到對 KeyedVectorDefaultKeyedVector 的使用。並且我們內部的服務框架也有用到 KeyedVector 這個結構。但在維護專案的過程中,我們發現它可能會導致資料處理順序出現混亂的情況,我認為這一定是因為我們對這個結構不夠了解導致的。關於這個結構內部的具體實現,我覺得我有必要去了解清楚,以便在後續的使用中能夠發揮出它的最大功效,並且避免一些出問題的情況。

根據引用的標頭檔案名,我們可以到 Android 原始碼目錄下的 system/core/libutils/include 中找到相應的標頭檔案。

瀏覽相關標頭檔案,可以看到在 Android 內建的 Utils 中,有四種可用的 Vector 結構:

  1. Vector
  2. SortedVector
  3. KeyedVector
  4. DefaultKeyedVector

這些類之間的關係如下圖:
@圖1. 簡單類圖

由圖可知:

  • VectorSortedVector 分別繼承自抽象類 VectorImplSortedVectorImpl(而後者又是前者的子類),這兩個抽象類實現了一些重要的底層操作。
  • VectorSortedVector 之間具有依賴關係(後者成員函式中有前者型別的引數)。
  • KeyedVector 相對獨立,它與 SortedVector 是關聯關係(前者有一個後者型別的成員變數)。
  • DefaultKeyedVector 繼承自 KeyedVector,而根據程式碼來看,它們之間沒有多少差異。

首先要讀懂 VectorImplSortedVectorImpl,然後再看 VectorSortedVector。最後就要看我的重點 KeyedVector,這時候應該就有一個比較清晰的理解了。DefaultKeyedVector 差別不大,和 KeyedVector 一起看就行。


相關文章


標頭檔案

檔案路徑:system\core\libutils\include\utils\VectorImpl.h

概覽:

  • 開頭的註釋內容:這個類是實現 Vector 類的核心部分。它能保證逆向二進位制相容,並且減少程式碼量。考慮效能原因,將 mStoragemCount 兩個內部欄位暴露出來,它們是固定不變的。
  • 第 13~17 行:傳入建構函式的標誌位,表示是否為 trivial 型別。其中,ctor 表示建構函式,dtor 即是析構,copy 則表示拷貝。
  • 第 24 行:子類析構時必須呼叫的函式,涉及到記憶體空間的釋放與內部成員重置。
  • 第 29 行:用於以 C 語言陣列風格返回 Vector 的訪問指標,但不能對其進行編輯操作
  • 第 30 行:用於以 C 語言陣列風格返回 Vector,並且可以對內容進行編輯
  • 第 40~43 行:用於往當前 Vector 中插入(或末尾追加)另一個 Vector(或陣列)
  • 第 46~57 行:用於增加、插入、替換以及刪除 Vector 中的單個元素
  • 第 58 行:用於清空(重置) Vector。
  • 第 60、61 行:用於查詢 index 位置對應的元素,注意名帶 edit 的返回的是可編輯的結果
  • 第 63~66 行:定義兩個函式指標,用於指向自定義的比較函式。sort 函式則是基於比較函式進行排序。
  • 第 70 行:用於釋放 mStorage 的儲存空間。
  • 第 72~77 行:一組純虛擬函式,在子類中必須進行具體實現。
  • 第 80、81 行:用於從 Vector 的 where 位置開始擴充(或收縮)
  • 第 83~88 行:這些行內函數與前面的那組純虛擬函式是一一對應的,各自的功能已經由其函式名錶述清楚了。
  • 第 92~96 行:內部成員變數,分別儲存了 Vector 資料首地址、元素總數、關於 trivial 型別的標誌,以及單個元素的資料大小
/*!
 * Implementation of the guts of the vector<> class
 * this ensures backward binary compatibility and
 * reduces code size.
 * For performance reasons, we expose mStorage and mCount
 * so these fields are set in stone.
 *
 */

class VectorImpl
{
public:
    enum { // flags passed to the ctor
        HAS_TRIVIAL_CTOR    = 0x00000001,
        HAS_TRIVIAL_DTOR    = 0x00000002,
        HAS_TRIVIAL_COPY    = 0x00000004,
    };

                            VectorImpl(size_t itemSize, uint32_t flags);
                            VectorImpl(const VectorImpl& rhs);
    virtual                 ~VectorImpl();

    /*! must be called from subclasses destructor */
            void            finish_vector();

            VectorImpl&     operator = (const VectorImpl& rhs);    

    /*! C-style array access */
    inline  const void*     arrayImpl() const       { return mStorage; }
            void*           editArrayImpl();

    /*! vector stats */
    inline  size_t          size() const        { return mCount; }
    inline  bool            isEmpty() const     { return mCount == 0; }
            size_t          capacity() const;
            ssize_t         setCapacity(size_t size);
            ssize_t         resize(size_t size);

            /*! append/insert another vector or array */
            ssize_t         insertVectorAt(const VectorImpl& vector, size_t index);
            ssize_t         appendVector(const VectorImpl& vector);
            ssize_t         insertArrayAt(const void* array, size_t index, size_t length);
            ssize_t         appendArray(const void* array, size_t length);

            /*! add/insert/replace items */
            ssize_t         insertAt(size_t where, size_t numItems = 1);
            ssize_t         insertAt(const void* item, size_t where, size_t numItems = 1);
            void            pop();
            void            push();
            void            push(const void* item);
            ssize_t         add();
            ssize_t         add(const void* item);
            ssize_t         replaceAt(size_t index);
            ssize_t         replaceAt(const void* item, size_t index);

            /*! remove items */
            ssize_t         removeItemsAt(size_t index, size_t count = 1);
            void            clear();

            const void*     itemLocation(size_t index) const;
            void*           editItemLocation(size_t index);

            typedef int (*compar_t)(const void* lhs, const void* rhs);
            typedef int (*compar_r_t)(const void* lhs, const void* rhs, void* state);
            status_t        sort(compar_t cmp);
            status_t        sort(compar_r_t cmp, void* state);

protected:
            size_t          itemSize() const;
            void            release_storage();

    virtual void            do_construct(void* storage, size_t num) const = 0;
    virtual void            do_destroy(void* storage, size_t num) const = 0;
    virtual void            do_copy(void* dest, const void* from, size_t num) const = 0;
    virtual void            do_splat(void* dest, const void* item, size_t num) const = 0;
    virtual void            do_move_forward(void* dest, const void* from, size_t num) const = 0;
    virtual void            do_move_backward(void* dest, const void* from, size_t num) const = 0;

private:
        void* _grow(size_t where, size_t amount);
        void  _shrink(size_t where, size_t amount);

        inline void _do_construct(void* storage, size_t num) const;
        inline void _do_destroy(void* storage, size_t num) const;
        inline void _do_copy(void* dest, const void* from, size_t num) const;
        inline void _do_splat(void* dest, const void* item, size_t num) const;
        inline void _do_move_forward(void* dest, const void* from, size_t num) const;
        inline void _do_move_backward(void* dest, const void* from, size_t num) const;

            // These 2 fields are exposed in the inlines below,
            // so they're set in stone.
            void *      mStorage;   // base address of the vector
            size_t      mCount;     // number of items

    const   uint32_t    mFlags;
    const   size_t      mItemSize;
};

具體實現

檔案路徑:system\core\libutils\VectorImpl.cpp

如果對所有函式的實現都一一解釋,那樣太浪費時間了,所以我只選擇一些我認為比較重要的函式實現進行分析。
基本的元素操作(增刪查詢)就不說了,接下來我們分析這幾個函式:

  1. 排序函式:sort
  2. 擴充函式:_grow
  3. 收縮函式:_shrink

首先來看看一個常量 kMinVectorCapacity,顧名思義,這定義的是 Vector 的最小容量,也是其初始容量。可以看到 Android 中將其設定為 4

const size_t kMinVectorCapacity = 4;

雖然在前面有提到一些函式的用途,但在這裡我還是要再描述一遍,因為如果不瞭解這些函式的功能,後面的分析可能就難以看下去了。

函式功能簡述

我們可以分成幾個大類來看:

  1. (Public)提供 Vector 的陣列式訪問:
    • arrayImpl:返回不可編輯的陣列。
    • editArrayImpl:返回可編輯的資料。
  2. (Public)關於 Vector 資料量的操作:
    • size:返回當前資料量大小,值得一提的是,它是通過 mStorage 的空間大小與設定的元素大小 mItemSize 計算出來的。
    • isEmpty:判斷當前是否無資料。
    • capacity:返回當前 Vector 的容量
    • setCapacity:設定 Vector 的容量(成功則返回新容量數值,失敗則返回相應錯誤碼)。
    • resize:調整當前資料量大小。若調整值 size 大於當前資料量,則從資料末端增加元素直到資料量大小等於 size;若 size 小於當前資料量,則從資料末端向前刪除元素直到資料量大小等於 size(成功則返回新資料量大小,失敗返回相應錯誤碼)。
  3. (Public)Vector 或陣列之間的合併操作:
    • insertVectorAt / insertArrayAt:在當前 Vector 的某一位置插入另一個 Vector 或陣列。
    • appendVector / appendArray:向當前 Vector 末端追加另一個 Vector 或陣列。
  4. (Public)Vector 中單個元素的相關操作:
    • insertAt:在指定位置插入元素。
    • pop:彈出(刪除)Vector 末尾的一個元素。
    • push:在 Vector 末尾放入(插入)一個元素。
    • add:與 push 一樣,末端插入一個元素,但該函式有返回值,若動作失敗則返回錯誤碼。
    • replaceAt:將指定位置的元素替換為自定義的元素。
    • removeItemsAt:刪除指定位置的元素。
    • itemLocation:返回指定位置的元素,不可編輯
    • editItemLocation:返回指定位置的元素,可編輯
  5. 記憶體釋放回收操作:
    • finish_vector:釋放 mStorage 儲存空間,並將其與 mCount 重置為 0。(在子類的解構函式中必須呼叫該函式以防記憶體洩露)
    • clear:清除 Vector 資料並重置,減容至最小狀態
    • release_storage:釋放 mStorage 的儲存空間。
  6. (Private)內部使用的底層操作:
    • _do_construct:若 mFlags 中沒有 HAS_TRIVIAL_CTOR 標記,則呼叫 do_constructmStorage 進行構造操作。反之則不進行任何動作。
    • _do_destroy:與構造類似(判斷 HAS_TRIVIAL_DTOR 標記),但這一函式是用於析構 mStorage 的。
    • _do_copy:將 from 指向的地址開始的 num 個元素拷貝到 dest 指向的地址。判斷 HAS_TRIVIAL_COPY 標記,若有則直接使用 memcpy 進行拷貝,若無則呼叫 do_copy 進行拷貝。
    • _do_splat:呼叫 do_splat 實現 Vector 分裂操作(在指定位置插入元素時會用到,首先在指定位置進行擴容,然後將用 do_splat 將元素覆蓋到該位置對應的記憶體空間上)。
    • _do_move_forward:呼叫 do_move_forward 將從 from 處開始的 num 個元素正向移動到記憶體位置 dest(當兩塊記憶體位置有重疊時,移動後 from 的內容可能會發生改變)。
    • _do_move_backward:與向前移動類似,呼叫 do_move_backward 將從 from 處開始的 num 個元素反向移動到記憶體位置 dest

排序函式分析

排序函式(插入排序)主要思想:i 個元素之前的陣列已經是按規則排序好的了,現在要將其插入到已排序陣列中的合適位置。我們從後往前依次尋找這個位置,在尋找過程中同時也將需要移動的元素向後進行移動,這樣只要一找到恰當的位置,就完成了一輪排序。只要依次遍歷所有元素,則整個 Vector 的排序也就完成了。

圖解排序:
@圖. cmp 函式指標呼叫示意圖

@圖. VectorImpl 排序流程

程式碼分析:

  • 第 1~4 行:定義一個靜態函式 sortProxy,用於通過函式指標 func 呼叫對應的比較函式。
  • 第 6~9 行:這個 sort 應是由外部呼叫的,它會進一步呼叫具體實現的 sort 函式。
  • 第 11 行:注意到傳入的引數 cmp,它對應的是上面的 sortProxy 函式;而引數 state 則對應的是自定義的具體的比較函式的函式指標。在該函式中呼叫 cmp 時,傳入的引數是需要比較的兩個元素以及 state 對應的函式指標,最終效果就是呼叫自定義比較函式比較兩個傳入的元素
  • 第 13~15 行(註釋翻譯):該排序必須是穩定的。我們目前使用的是插入排序,這種方法對於小規模(以及已排序的陣列)來說非常合適。而對於大規模陣列來說,使用歸併排序可能會更好。
  • 第 16、17 行:當 Vector 中資料量大於 1 時,排序才有意義。
  • 第 18 行:初始化指標 array。由於呼叫的是 arrayImpl 函式來獲取陣列訪問地址,而隨後需要對 array 進行強制型別轉換操作,所以需要把 arrayImpl 返回值的 const 限制移除(為什麼不直接呼叫 editArrayImpl 呢…)。
  • 第 21 行:開始從頭至尾遍歷每個元素進行排序。
  • 第 22、23 行:獲取陣列中第 i 個元素 item,以及第 i-1 個元素 curr。此處 array 強制型別轉換為 char* 型別(對其加一就是向後移動一個位元組),這樣就能保證 + 操作獲取到的是相應元素的首地址。
  • 第 24 行:通過呼叫 cmp 比較 curritem 兩個元素,我們可以認為這表示的是當 curr 大於 item進行接下來的排序操作(實際使用時需要根據 cmp 的具體實現來判斷)。
  • 第 28~33 行:這是最開始的一次比較時會進行的操作,呼叫 editArrayImpl 給指標 array 賦予陣列首地址,然後申請一份用於臨時存放需要轉移的元素的空間temp 指標指向其首地址。然後獲取第 i 個與第 i-1 個元素首地址。
  • 第 35 行:第二次比較以後,都會先清除 temp 指向的記憶體中的資料,但不會釋放這些記憶體。
  • 第 38 行:將 item 指向的元素拷貝至 temp 指向的臨時空間中。
  • 第 40~51 行:插入排序的核心部分。
    • (a) 首先令 next 指標指向第 i 個元素(即前面的 item,而此時 item 對應的資料已經拷貝到 temp 指向的位置了)。
    • (b) 進入迴圈,首先將 next 位置的元素資料銷燬,然後把前一個元素 curr 的資料拷貝到 next 的位置。
    • (c) 令 next 指向 curr 的位置,即 next 向前移動一個元素。
    • (d) 變數 j1,然後將 curr 指向陣列的第 j 個元素位置,即 curr 也向前移動一個元素。
    • (e) 繼續比較 currnext,若 curr 大於 next,則回到步驟 (b)。
  • 第 53、54 行:清除當前 next 指向的元素,並將 temp 中資料拷貝過去。(此時的 next 即是元素 i 在這一輪排序中最終的位置)
  • 第 56 行:對陣列中下一個元素進行插入排序。
  • 第 59~62 行:此時排序已經完全結束,則需要銷燬 temp 中的臨時資料,並釋放其對應的臨時記憶體空間。
static int sortProxy(const void* lhs, const void* rhs, void* func)
{
    return (*(VectorImpl::compar_t)func)(lhs, rhs);
}

status_t VectorImpl::sort(VectorImpl::compar_t cmp)
{
    return sort(sortProxy, (void*)cmp);
}

status_t VectorImpl::sort(VectorImpl::compar_r_t cmp, void* state)
{
    // the sort must be stable. we're using insertion sort which
    // is well suited for small and already sorted arrays
    // for big arrays, it could be better to use mergesort
    const ssize_t count = size();
    if (count > 1) {
        void* array = const_cast<void*>(arrayImpl());
        void* temp = 0;
        ssize_t i = 1;
        while (i < count) {
            void* item = reinterpret_cast<char*>(array) + mItemSize*(i);
            void* curr = reinterpret_cast<char*>(array) + mItemSize*(i-1);
            if (cmp(curr, item, state) > 0) {

                if (!temp) {
                    // we're going to have to modify the array...
                    array = editArrayImpl();
                    if (!array) return NO_MEMORY;
                    temp = malloc(mItemSize);
                    if (!temp) return NO_MEMORY;
                    item = reinterpret_cast<char*>(array) + mItemSize*(i);
                    curr = reinterpret_cast<char*>(array) + mItemSize*(i-1);
                } else {
                    _do_destroy(temp, 1);
                }

                _do_copy(temp, item, 1);

                ssize_t j = i-1;
                void* next = reinterpret_cast<char*>(array) + mItemSize*(i);                    
                do {
                    _do_destroy(next, 1);
                    _do_copy(next, curr, 1);
                    next = curr;
                    --j;
                    curr = NULL;
                    if (j >= 0) {
                        curr = reinterpret_cast<char*>(array) + mItemSize*(j);
                    }
                } while (j>=0 && (cmp(curr, temp, state) > 0));

                _do_destroy(next, 1);
                _do_copy(next, temp, 1);
            }
            i++;
        }

        if (temp) {
            _do_destroy(temp, 1);
            free(temp);
        }
    }
    return NO_ERROR;
}

擴充函式分析

擴充函式的主要邏輯:在 Vector 的指定位置 where 處(這個位置不能大於 mCount)開始,騰出 amount 個元素的空間(將原先從 where 處開始到末端的元素向後移動 amount 個位置),若判定容量不足以支援本次擴充,則會進行相應的擴容

NOTE:擴充表示的是將 Vector 當前大小(size)擴大,而擴容則是將 Vector 的容量(capacity)增大。

圖解擴充:
@圖. VectorImpl_grow 擴充圖解

程式碼分析:

  • 第 1 行:注意傳入的引數意義,where 是指定的擴充位置,amount 則是需要擴充的總個數。
  • 第 6~8 行:引數有效性檢測where 決不能大於 mCount,否則觸發中斷。
  • 第 11 行:計算新的 Vector 大小,此處用 safe_add 防止溢位,溢位時會觸發錯誤 LOG。
  • 第 13 行:如果新的大小大於 Vector 容量,則接下來需要有一些擴容操作
  • 第 21~26 行:新容量的計算,可以看出來 new_capacity = max(4, x + (x/2) + 1),其中每次加操作都需要呼叫 safe_add 完成以防止溢位(公式中有一個 1u,這表示 unsigned 型的 1)。
  • 第 28、29 行:計算需要申請的記憶體大小,呼叫 safe_mul 計算 new_alloc_size = new_capacity * mItemSize 以防止溢位。
  • 第 33~44 行:一個比較特殊的情況下的擴容處理
    • 條件:mStorage 不為空,where 指向 Vector 末端,同時 copydtor 都是 trivial 型別的。
    • 通過 SharedBuffermStorage 調整給其分配的記憶體空間。
    • 注意到此時不用進行資料拷貝之類的操作,所以調整記憶體完畢後就結束了。
  • 第 45~62 行:通常情況下的擴容操作
    • 首先從 SharedBuffer 中申請相應的空間,並讓指標 array 指向空間首地址。
    • 將當前 mStorage 中第 0 ~ where 個資料拷貝到 array 指向的空間中。
    • where 小於 count,則將 mStorage 中的從 where 處開始直到末端的元素拷貝到 array 中的 where + amount 位置(其實相當於向後移動了 amount 個位置)。
    • 清空當前 mStorage 的資料,釋放對應空間,並讓其指向 array 的地址。
  • 第 63~70 行:無需擴容的情況,只需要where 處直到末端的元素向後(正向)移動 amount 個位置即可。
void* VectorImpl::_grow(size_t where, size_t amount)
{
//    ALOGV("_grow(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
//        this, (int)where, (int)amount, (int)mCount, (int)capacity());

    ALOG_ASSERT(where <= mCount,
            "[%p] _grow: where=%d, amount=%d, count=%d",
            this, (int)where, (int)amount, (int)mCount); // caller already checked

    size_t new_size;
    LOG_ALWAYS_FATAL_IF(!safe_add(&new_size, mCount, amount), "new_size overflow");

    if (capacity() < new_size) {
        // NOTE: This implementation used to resize vectors as per ((3*x + 1) / 2)
        // (sigh..). Also note, the " + 1" was necessary to handle the special case
        // where x == 1, where the resized_capacity will be equal to the old
        // capacity without the +1. The old calculation wouldn't work properly
        // if x was zero.
        //
        // This approximates the old calculation, using (x + (x/2) + 1) instead.
        size_t new_capacity = 0;
        LOG_ALWAYS_FATAL_IF(!safe_add(&new_capacity, new_size, (new_size / 2)),
                            "new_capacity overflow");
        LOG_ALWAYS_FATAL_IF(!safe_add(&new_capacity, new_capacity, static_cast<size_t>(1u)),
                            "new_capacity overflow");
        new_capacity = max(kMinVectorCapacity, new_capacity);

        size_t new_alloc_size = 0;
        LOG_ALWAYS_FATAL_IF(!safe_mul(&new_alloc_size, new_capacity, mItemSize),
                            "new_alloc_size overflow");

//        ALOGV("grow vector %p, new_capacity=%d", this, (int)new_capacity);
        if ((mStorage) &&
            (mCount==where) &&
            (mFlags & HAS_TRIVIAL_COPY) &&
            (mFlags & HAS_TRIVIAL_DTOR))
        {
            const SharedBuffer* cur_sb = SharedBuffer::bufferFromData(mStorage);
            SharedBuffer* sb = cur_sb->editResize(new_alloc_size);
            if (sb) {
                mStorage = sb->data();
            } else {
                return NULL;
            }
        } else {
            SharedBuffer* sb = SharedBuffer::alloc(new_alloc_size);
            if (sb) {
                void* array = sb->data();
                if (where != 0) {
                    _do_copy(array, mStorage, where);
                }
                if (where != mCount) {
                    const void* from = reinterpret_cast<const uint8_t *>(mStorage) + where*mItemSize;
                    void* dest = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
                    _do_copy(dest, from, mCount-where);
                }
                release_storage();
                mStorage = const_cast<void*>(array);
            } else {
                return NULL;
            }
        }
    } else {
        void* array = editArrayImpl();
        if (where != mCount) {
            const void* from = reinterpret_cast<const uint8_t *>(array) + where*mItemSize;
            void* to = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
            _do_move_forward(to, from, mCount - where);
        }
    }
    mCount = new_size;
    void* free_space = const_cast<void*>(itemLocation(where));
    return free_space;
}

收縮函式分析

收縮函式主要邏輯:where 處開始,將連續的 amount 個元素銷燬(需要保證有這麼多可銷燬的元素),由於 Vector 收縮了,其容量可能也需要根據一定規律進行減容,以減少不必要的記憶體佔用。

圖解收縮:
@圖. VectorImpl_shrink 收縮函式圖解

程式碼分析:

  • 第 9~11 行:引數有效性判定,要保證存在足夠的可銷燬元素。
  • 第 14 行:計算收縮後的 Vector 大小,公式為 new_size = mCount - amount
  • 第 16 行:當 new_size 小於當前容量的一半時,需要進行減容操作。
  • 第 19 行:減容後的容量計算公式 new_capacity = max(4, new_size * 2),其中 new_size * 2 可以證明是不會溢位的。
  • 第 26~36 行:從末端元素進行收縮,且 copydtor 函式都是 trivial 型別的時候,只需要獲取 mStorage 對應的 SharedBuffer 進行 Resize 操作即可完成本次減容(以及收縮)。
  • 第 37~54 行:一般情況下的減容步驟
    • 首先通過 SharedBuffer 申請一塊空間,大小為 new_capacity * mItemSize,讓指標 array 指向其首地址。
    • mStorage0 ~ (where - 1) 的元素拷貝到 array 中。
    • where 小於 new_size,說明 Vector 後方還有一些元素需要拷貝過來。將 mStoragewhere + amount 處開始直至末尾的元素拷貝到當前 array 最後一個元素的後面。
    • 最後將當前 mStorage 指向的內容銷燬,然後在指向 array 即完成了減容(以及收縮)操作。
  • 第 55~63 行:若判定不需要進行減容操作,則直接將 where 處開始的連續 amount 個元素銷燬,再將 where + amount 處開始直至 Vector 末尾的元素反向移動到 where,就完成了一次收縮操作。
void VectorImpl::_shrink(size_t where, size_t amount)
{
    if (!mStorage)
        return;

//    ALOGV("_shrink(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
//        this, (int)where, (int)amount, (int)mCount, (int)capacity());

    ALOG_ASSERT(where + amount <= mCount,
            "[%p] _shrink: where=%d, amount=%d, count=%d",
            this, (int)where, (int)amount, (int)mCount); // caller already checked

    size_t new_size;
    LOG_ALWAYS_FATAL_IF(!safe_sub(&new_size, mCount, amount));

    if (new_size < (capacity() / 2)) {
        // NOTE: (new_size * 2) is safe because capacity didn't overflow and
        // new_size < (capacity / 2)).
        const size_t new_capacity = max(kMinVectorCapacity, new_size * 2);

        // NOTE: (new_capacity * mItemSize), (where * mItemSize) and
        // ((where + amount) * mItemSize) beyond this point are safe because
        // we are always reducing the capacity of the underlying SharedBuffer.
        // In other words, (old_capacity * mItemSize) did not overflow, and
        // where < (where + amount) < new_capacity < old_capacity.
        if ((where == new_size) &&
            (mFlags & HAS_TRIVIAL_COPY) &&
            (mFlags & HAS_TRIVIAL_DTOR))
        {
            const SharedBuffer* cur_sb = SharedBuffer::bufferFromData(mStorage);
            SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize);
            if (sb) {
                mStorage = sb->data();
            } else {
                return;
            }
        } else {
            SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
            if (sb) {
                void* array = sb->data();
                if (where != 0) {
                    _do_copy(array, mStorage, where);
                }
                if (where != new_size) {
                    const void* from = reinterpret_cast<const uint8_t *>(mStorage) + (where+amount)*mItemSize;
                    void* dest = reinterpret_cast<uint8_t *>(array) + where*mItemSize;
                    _do_copy(dest, from, new_size - where);
                }
                release_storage();
                mStorage = const_cast<void*>(array);
            } else{
                return;
            }
        }
    } else {
        void* array = editArrayImpl();
        void* to = reinterpret_cast<uint8_t *>(array) + where*mItemSize;
        _do_destroy(to, amount);
        if (where != new_size) {
            const void* from = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
            _do_move_backward(to, from, new_size - where);
        }
    }
    mCount = new_size;
}

小結

本文是 Vector 系列學習筆記的第一章,講述的是 Android Utils 中四種 Vector 的最基礎的部分,即抽象類 VectorImpl
稍作回顧,本文先從相關的標頭檔案入手,觀察 VectorImpl 的類定義,大概瞭解了這個類的一些基本功能,以及有哪些底層操作。隨後根據各個函式的實現,簡單介紹了類中成員函式的功能。最後,便是對三個我個人認為比較重要的函式 —— 排序、擴充,以及收縮函式,對它們進行了比較詳細的解析。
通過這一連串的分析,我對 VectorImpl 就有了一個比較全面的理解了。我認為在程式設計規範方面,我們內部需要向 google 學習的還是太多了。以及通過分析擴充與收縮函式(以及與之相關的一些函式),我發現 Vector 的一些基本操作都能通過複用它們來實現(實際上 google 就是這麼做的),比如插入元素、插入另一個 Vector、刪除元素……這使得整個類的實現的程式碼結構非常簡潔易懂,這種把基本操作高度抽象出來的做法值得我學習。

在分析過程中,我也發現還有一些更底層的內容我還沒有了解:

  • 一個是 trivial 型別相關的內容 —— 這個型別的定義是什麼,它有什麼作用?
  • 另一個是關於 SharedBuffer 類 —— 它的設計思想是什麼,它通過怎樣的方式來實現基本操作的?

這些內容只能以後再慢慢學習了,而接下來需要分析的則是另一個重要的抽象類 SortedVectorImpl

相關文章