aboutsummaryrefslogtreecommitdiffstats
path: root/vespalib/src/vespa/vespalib/util/compress.h
blob: 66234da0e32e6c5c1cc984bbe7fc58ab1c9e8bd9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#pragma once

#include <cstdint>
#include <cstddef>

namespace vespalib::compress {

class Integer {
public:
    /**
     * Will compress a positive integer to either 1,2 or 4 bytes
     * @param n Number to compress
     * @param destination Where to put the compressed number
     * @return number of bytes used.
     */
    static size_t compressPositive(uint64_t n, void *destination);
    /**
     * Will compress an integer to either 1,2 or 4 bytes
     * @param n Number to compress
     * @param destination Where to put the compressed number
     * @return number of bytes used.
     */
    static size_t compress(int64_t n, void *destination);
    /**
     * @param unsigned number to compute compressed size of in bytes.
     * @return Will return the number of bytes this positive number will require
     **/
    static size_t compressedPositiveLength(uint64_t n) {
        if (n < (0x1 << 6)) {
            return 1;
        } else if (n < (0x1 << 14)) {
            return 2;
        } else if ( n < (0x1 << 30)) {
            return 4;
        } else {
            throw_too_big(n);
        }
    }
    /**
     * @param number to compute compressed size of in bytes.
     * @return Will return the number of bytes this number will require
     **/
    static size_t compressedLength(int64_t n) {
        if (n < 0) {
            n = -n;
        }
        if (n < (0x1 << 5)) {
            return 1;
        } else if (n < (0x1 << 13)) {
            return 2;
        } else if ( n < (0x1 << 29)) {
            return 4;
        } else {
            throw_too_big(n);
        }
    }
    /**
     * Will decompress an integer.
     * @param pointer to buffer. pointer is automatically advanced.
     * @return decompressed number
     */
    static size_t decompress(int64_t & n, const void * srcv) {
        const uint8_t * src = static_cast<const uint8_t *>(srcv);
        const uint8_t c = src[0];
        size_t numbytes;
        if (__builtin_expect(c & 0x40, false)) {
           if (c & 0x20) {
               n = ((c & 0x1f) << 24) + (src[1] << 16) + (src[2] << 8) + src[3];
               numbytes = 4;
            } else {
               n = ((c & 0x1f) << 8) + src[1];
               numbytes = 2;
            }
        } else {
           n = c & 0x1f;
           numbytes = 1;
        }
        if (c & 0x80) {
            n = -n;
        }
        return numbytes;
    }
    /**
     * Will decompress a positive integer.
     * @param pointer to buffer. pointer is automatically advanced.
     * @return decompressed number
     */
    static size_t decompressPositive(uint64_t & n, const void * srcv) {
        const uint8_t * src = static_cast<const uint8_t *>(srcv);
        const uint8_t c = src[0];
        size_t numbytes;
        if (c & 0x80) {
           if (c & 0x40) {
               n = ((c & 0x3f) << 24) + (src[1] << 16) + (src[2] << 8) + src[3];
               numbytes = 4;
           } else {
               n = ((c & 0x3f) << 8) + src[1];
               numbytes = 2;
           }
        } else {
           n = c & 0x3f;
           numbytes = 1;
        }
        return numbytes;
    }

    static bool check_decompress_space(const void* srcv, size_t len) {
        if (len == 0u) {
            return false;
        }
        const uint8_t * src = static_cast<const uint8_t *>(srcv);
        const uint8_t c = src[0];
        if ((c & 0x40) != 0) {
            return (((c & 0x20) != 0) ? (len >= 4u) : (len >= 2u));
        } else {
            return true;
        }
    }

    static bool check_decompress_positive_space(const void* srcv, size_t len) {
        if (len == 0u) {
            return false;
        }
        const uint8_t * src = static_cast<const uint8_t *>(srcv);
        const uint8_t c = src[0];
        if ((c & 0x80) != 0) {
            return (((c & 0x40) != 0) ? (len >= 4u) : (len >= 2u));
        } else {
            return true;
        }
    }
private:
    [[ noreturn ]] static void throw_too_big(int64_t n);
    [[ noreturn ]] static void throw_too_big(uint64_t n);
};

}