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
18void U(shrink_chunk)(U(descriptor) *desc, U(size_bau) n_baus_to_shrink) {
19  head_record *dummy_end_block = (head_record *)
20                                 BAUS_BACKWARD(desc->end_of_shrinkable_chunk, DUMMY_END_BLOCK_BAUS);
21
22#ifdef HMM_AUDIT_FAIL
23
24  if (dummy_end_block->block_size != 0)
25    /* Chunk does not have valid dummy end block. */
26    HMM_AUDIT_FAIL
27
28#endif
29
30    if (n_baus_to_shrink) {
31      head_record *last_block = (head_record *)
32                                BAUS_BACKWARD(
33                                  dummy_end_block, dummy_end_block->previous_block_size);
34
35#ifdef HMM_AUDIT_FAIL
36      AUDIT_BLOCK(last_block)
37#endif
38
39      if (last_block == desc->last_freed) {
40        U(size_bau) bs = BLOCK_BAUS(last_block);
41
42        /* Chunk will not be shrunk out of existence if
43        ** 1.  There is at least one allocated block in the chunk
44        **     and the amount to shrink is exactly the size of the
45        **     last block, OR
46        ** 2.  After the last block is shrunk, there will be enough
47        **     BAUs left in it to form a minimal size block. */
48        int chunk_will_survive =
49          (PREV_BLOCK_BAUS(last_block) && (n_baus_to_shrink == bs)) ||
50          (n_baus_to_shrink <= (U(size_bau))(bs - MIN_BLOCK_BAUS));
51
52        if (chunk_will_survive ||
53            (!PREV_BLOCK_BAUS(last_block) &&
54             (n_baus_to_shrink ==
55              (U(size_bau))(bs + DUMMY_END_BLOCK_BAUS)))) {
56          desc->last_freed = 0;
57
58          if (chunk_will_survive) {
59            bs -= n_baus_to_shrink;
60
61            if (bs) {
62              /* The last (non-dummy) block was not completely
63              ** eliminated by the shrink. */
64
65              last_block->block_size = bs;
66
67              /* Create new dummy end record.
68              */
69              dummy_end_block =
70                (head_record *) BAUS_FORWARD(last_block, bs);
71              dummy_end_block->previous_block_size = bs;
72              dummy_end_block->block_size = 0;
73
74#ifdef HMM_AUDIT_FAIL
75
76              if (desc->avl_tree_root)
77                AUDIT_BLOCK(PTR_REC_TO_HEAD(desc->avl_tree_root))
78#endif
79
80                U(into_free_collection)(desc, last_block);
81            } else {
82              /* The last (non-dummy) block was completely
83              ** eliminated by the shrink.  Make its head
84              ** the new dummy end block.
85              */
86              last_block->block_size = 0;
87              last_block->previous_block_size &= ~HIGH_BIT_BAU_SIZE;
88            }
89          }
90        }
91
92#ifdef HMM_AUDIT_FAIL
93        else
94          HMM_AUDIT_FAIL
95#endif
96        }
97
98#ifdef HMM_AUDIT_FAIL
99      else
100        HMM_AUDIT_FAIL
101#endif
102      }
103}
104