1/*
2 *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11
12/* This code is in the public domain.
13** Version: 1.1  Author: Walt Karas
14*/
15
16#include "hmm_intrnl.h"
17
18int U(resize)(U(descriptor) *desc, void *mem, U(size_aau) n)
19{
20    U(size_aau) i;
21    head_record *next_head_ptr;
22    head_record *head_ptr = PTR_REC_TO_HEAD(mem);
23
24    /* Flag. */
25    int next_block_free;
26
27    /* Convert n from desired block size in AAUs to BAUs. */
28    n += HEAD_AAUS;
29    n = DIV_ROUND_UP(n, HMM_BLOCK_ALIGN_UNIT);
30
31    if (n < MIN_BLOCK_BAUS)
32        n = MIN_BLOCK_BAUS;
33
34#ifdef HMM_AUDIT_FAIL
35
36    AUDIT_BLOCK(head_ptr)
37
38    if (!IS_BLOCK_ALLOCATED(head_ptr))
39        HMM_AUDIT_FAIL
40
41        if (desc->avl_tree_root)
42            AUDIT_BLOCK(PTR_REC_TO_HEAD(desc->avl_tree_root))
43
44#endif
45
46            i = head_ptr->block_size;
47
48    next_head_ptr =
49        (head_record *) BAUS_FORWARD(head_ptr, head_ptr->block_size);
50
51    next_block_free =
52        (next_head_ptr == desc->last_freed) ||
53        !IS_BLOCK_ALLOCATED(next_head_ptr);
54
55    if (next_block_free)
56        /* Block can expand into next free block. */
57        i += BLOCK_BAUS(next_head_ptr);
58
59    if (n > i)
60        /* Not enough room for block to expand. */
61        return(-1);
62
63    if (next_block_free)
64    {
65#ifdef HMM_AUDIT_FAIL
66        AUDIT_BLOCK(next_head_ptr)
67#endif
68
69        if (next_head_ptr == desc->last_freed)
70            desc->last_freed = 0;
71        else
72            U(out_of_free_collection)(desc, next_head_ptr);
73
74        next_head_ptr =
75            (head_record *) BAUS_FORWARD(head_ptr, (U(size_bau)) i);
76    }
77
78    /* Set i to number of "extra" BAUs. */
79    i -= n;
80
81    if (i < MIN_BLOCK_BAUS)
82        /* Not enough extra BAUs to be a block on their own, so just keep them
83        ** in the block being resized.
84        */
85    {
86        n += i;
87        i = n;
88    }
89    else
90    {
91        /* There are enough "leftover" BAUs in the next block to
92        ** form a remainder block. */
93
94        head_record *rem_head_ptr;
95
96        rem_head_ptr = (head_record *) BAUS_FORWARD(head_ptr, n);
97
98        rem_head_ptr->previous_block_size = (U(size_bau)) n;
99        rem_head_ptr->block_size = (U(size_bau)) i;
100
101        if (desc->last_freed)
102        {
103#ifdef HMM_AUDIT_FAIL
104            AUDIT_BLOCK(desc->last_freed)
105#endif
106
107            U(into_free_collection)(desc, (head_record *)(desc->last_freed));
108
109            desc->last_freed = 0;
110        }
111
112        desc->last_freed = rem_head_ptr;
113    }
114
115    head_ptr->block_size = (U(size_bau)) n;
116    next_head_ptr->previous_block_size = (U(size_bau)) i;
117
118    return(0);
119}
120