]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/memory_usage.c
Imported to git.
[icculus/xz.git] / src / liblzma / common / memory_usage.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       memory_usage.c
4 /// \brief      Calculate rough amount of memory required by filters
5 //
6 //  Copyright (C) 2007 Lasse Collin
7 //
8 //  This library is free software; you can redistribute it and/or
9 //  modify it under the terms of the GNU Lesser General Public
10 //  License as published by the Free Software Foundation; either
11 //  version 2.1 of the License, or (at your option) any later version.
12 //
13 //  This library is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 //  Lesser General Public License for more details.
17 //
18 ///////////////////////////////////////////////////////////////////////////////
19
20 #include "common.h"
21 #include "lz_encoder.h"
22 #include "lzma_literal.h"
23
24
25 static uint64_t
26 get_usage(const lzma_options_filter *filter, bool is_encoder)
27 {
28         uint64_t ret;
29
30         switch (filter->id) {
31         case LZMA_FILTER_COPY:
32         case LZMA_FILTER_X86:
33         case LZMA_FILTER_POWERPC:
34         case LZMA_FILTER_IA64:
35         case LZMA_FILTER_ARM:
36         case LZMA_FILTER_ARMTHUMB:
37         case LZMA_FILTER_SPARC:
38         case LZMA_FILTER_DELTA:
39                 // These don't require any significant amount of memory.
40                 ret = 0;
41                 break;
42
43         case LZMA_FILTER_SUBBLOCK:
44                 if (is_encoder) {
45                         const lzma_options_subblock *options = filter->options;
46                         ret = options->subblock_data_size;
47                 } else {
48                         ret = 0;
49                 }
50                 break;
51
52 #ifdef HAVE_FILTER_LZMA
53         case LZMA_FILTER_LZMA: {
54                 const lzma_options_lzma *options = filter->options;
55
56                 // Literal coder - this can be signficant if both values are
57                 // big, or if sizeof(probability) is big.
58                 ret = literal_states(options->literal_context_bits,
59                                 options->literal_pos_bits) * LIT_SIZE
60                                 * sizeof(probability);
61
62                 // Dictionary base size
63                 ret += options->dictionary_size;
64
65                 if (is_encoder) {
66 #       ifdef HAVE_ENCODER
67                         // This is rough, but should be accurate enough
68                         // in practice.
69                         ret += options->dictionary_size / 2;
70
71                         uint32_t dummy1;
72                         uint32_t dummy2;
73                         uint32_t num_items;
74                         if (lzma_lz_encoder_hash_properties(
75                                         options->match_finder,
76                                         options->dictionary_size,
77                                         &dummy1, &dummy2, &num_items))
78                                 return UINT64_MAX;
79
80                         ret += (uint64_t)(num_items) * sizeof(uint32_t);
81 #       else
82                         return UINT64_MAX;
83 #       endif
84                 }
85
86                 break;
87         }
88 #endif
89
90         default:
91                 return UINT64_MAX;
92         }
93
94         return ret;
95 }
96
97
98 extern LZMA_API uint32_t
99 lzma_memory_usage(const lzma_options_filter *filters, lzma_bool is_encoder)
100 {
101         uint64_t usage = 0;
102
103         for (size_t i = 0; filters[i].id != UINT64_MAX; ++i) {
104                 const uint64_t ret = get_usage(filters + i, is_encoder);
105                 if (ret == UINT64_MAX)
106                         return UINT32_MAX;
107
108                 usage += ret;
109         }
110
111         // Convert to mebibytes with rounding.
112         return usage / (1024 * 1024) + (usage % (1024 * 1024) >= 512 ? 1 : 0);
113 }