Skip to main content

libzstd_rs_sys/lib/compress/
zstd_preSplit.rs

1use core::ptr;
2
3use libc::size_t;
4
5use crate::lib::common::mem::MEM_read16;
6use crate::lib::compress::hist::HIST_add;
7
8#[repr(C)]
9pub struct Fingerprint {
10    pub events: [core::ffi::c_uint; 1024],
11    pub nbEvents: size_t,
12}
13#[repr(C)]
14pub struct FPStats {
15    pub pastEvents: Fingerprint,
16    pub newEvents: Fingerprint,
17}
18pub type RecordEvents_f =
19    Option<unsafe fn(*mut Fingerprint, *const core::ffi::c_void, size_t) -> ()>;
20pub const THRESHOLD_PENALTY_RATE: core::ffi::c_int = 16;
21pub const THRESHOLD_BASE: core::ffi::c_int = THRESHOLD_PENALTY_RATE - 2;
22pub const THRESHOLD_PENALTY: core::ffi::c_int = 3;
23pub const HASHLENGTH: core::ffi::c_int = 2;
24pub const HASHLOG_MAX: core::ffi::c_int = 10;
25pub const HASHTABLESIZE: core::ffi::c_int = (1) << HASHLOG_MAX;
26pub const KNUTH: core::ffi::c_uint = 0x9e3779b9;
27#[inline(always)]
28unsafe fn hash2(p: *const core::ffi::c_void, hashLog: core::ffi::c_uint) -> core::ffi::c_uint {
29    if hashLog == 8 {
30        return *(p as *const u8).offset(0) as u32;
31    }
32    (MEM_read16(p) as u32).wrapping_mul(KNUTH) >> (32 as core::ffi::c_uint).wrapping_sub(hashLog)
33}
34unsafe fn initStats(fpstats: *mut FPStats) {
35    ptr::write_bytes(fpstats as *mut u8, 0, ::core::mem::size_of::<FPStats>());
36}
37#[inline(always)]
38unsafe fn addEvents_generic(
39    fp: *mut Fingerprint,
40    src: *const core::ffi::c_void,
41    srcSize: size_t,
42    samplingRate: size_t,
43    hashLog: core::ffi::c_uint,
44) {
45    let p = src as *const core::ffi::c_char;
46    let limit = srcSize.wrapping_sub(HASHLENGTH as size_t).wrapping_add(1);
47    let mut n: size_t = 0;
48    n = 0;
49    while n < limit {
50        let fresh0 = &mut (*((*fp).events)
51            .as_mut_ptr()
52            .offset(hash2(p.add(n) as *const core::ffi::c_void, hashLog) as isize));
53        *fresh0 = (*fresh0).wrapping_add(1);
54        n = n.wrapping_add(samplingRate);
55    }
56    (*fp).nbEvents = ((*fp).nbEvents).wrapping_add(limit / samplingRate);
57}
58#[inline(always)]
59unsafe fn recordFingerprint_generic(
60    fp: *mut Fingerprint,
61    src: *const core::ffi::c_void,
62    srcSize: size_t,
63    samplingRate: size_t,
64    hashLog: core::ffi::c_uint,
65) {
66    ptr::write_bytes(
67        fp as *mut u8,
68        0,
69        ::core::mem::size_of::<core::ffi::c_uint>() << hashLog,
70    );
71    (*fp).nbEvents = 0;
72    addEvents_generic(fp, src, srcSize, samplingRate, hashLog);
73}
74unsafe fn ZSTD_recordFingerprint_1(
75    fp: *mut Fingerprint,
76    src: *const core::ffi::c_void,
77    srcSize: size_t,
78) {
79    recordFingerprint_generic(fp, src, srcSize, 1, 10);
80}
81unsafe fn ZSTD_recordFingerprint_5(
82    fp: *mut Fingerprint,
83    src: *const core::ffi::c_void,
84    srcSize: size_t,
85) {
86    recordFingerprint_generic(fp, src, srcSize, 5, 10);
87}
88unsafe fn ZSTD_recordFingerprint_11(
89    fp: *mut Fingerprint,
90    src: *const core::ffi::c_void,
91    srcSize: size_t,
92) {
93    recordFingerprint_generic(fp, src, srcSize, 11, 9);
94}
95unsafe fn ZSTD_recordFingerprint_43(
96    fp: *mut Fingerprint,
97    src: *const core::ffi::c_void,
98    srcSize: size_t,
99) {
100    recordFingerprint_generic(fp, src, srcSize, 43, 8);
101}
102unsafe fn abs64(s64: i64) -> u64 {
103    (if s64 < 0 { -s64 } else { s64 }) as u64
104}
105unsafe fn fpDistance(
106    fp1: *const Fingerprint,
107    fp2: *const Fingerprint,
108    hashLog: core::ffi::c_uint,
109) -> u64 {
110    let mut distance = 0u64;
111    let mut n: size_t = 0;
112    n = 0;
113    while n < (1) << hashLog {
114        distance = distance.wrapping_add(abs64(
115            *((*fp1).events).as_ptr().add(n) as i64 * (*fp2).nbEvents as i64
116                - *((*fp2).events).as_ptr().add(n) as i64 * (*fp1).nbEvents as i64,
117        ));
118        n = n.wrapping_add(1);
119    }
120    distance
121}
122unsafe fn compareFingerprints(
123    ref_0: *const Fingerprint,
124    newfp: *const Fingerprint,
125    penalty: core::ffi::c_int,
126    hashLog: core::ffi::c_uint,
127) -> core::ffi::c_int {
128    let p50 = (*ref_0).nbEvents * (*newfp).nbEvents;
129    let deviation = fpDistance(ref_0, newfp, hashLog);
130    let threshold = p50 as u64 * (THRESHOLD_BASE + penalty) as u64 / THRESHOLD_PENALTY_RATE as u64;
131    (deviation >= threshold) as core::ffi::c_int
132}
133unsafe fn mergeEvents(acc: *mut Fingerprint, newfp: *const Fingerprint) {
134    let mut n: size_t = 0;
135    n = 0;
136    while n < HASHTABLESIZE as size_t {
137        let fresh1 = &mut (*((*acc).events).as_mut_ptr().add(n));
138        *fresh1 = (*fresh1).wrapping_add(*((*newfp).events).as_ptr().add(n));
139        n = n.wrapping_add(1);
140    }
141    (*acc).nbEvents = ((*acc).nbEvents).wrapping_add((*newfp).nbEvents);
142}
143unsafe fn flushEvents(fpstats: *mut FPStats) {
144    let mut n: size_t = 0;
145    n = 0;
146    while n < HASHTABLESIZE as size_t {
147        *((*fpstats).pastEvents.events).as_mut_ptr().add(n) =
148            *((*fpstats).newEvents.events).as_mut_ptr().add(n);
149        n = n.wrapping_add(1);
150    }
151    (*fpstats).pastEvents.nbEvents = (*fpstats).newEvents.nbEvents;
152    ptr::write_bytes(
153        &mut (*fpstats).newEvents as *mut Fingerprint as *mut u8,
154        0,
155        ::core::mem::size_of::<Fingerprint>(),
156    );
157}
158unsafe fn removeEvents(acc: *mut Fingerprint, slice: *const Fingerprint) {
159    let mut n: size_t = 0;
160    n = 0;
161    while n < HASHTABLESIZE as size_t {
162        let fresh2 = &mut (*((*acc).events).as_mut_ptr().add(n));
163        *fresh2 = (*fresh2).wrapping_sub(*((*slice).events).as_ptr().add(n));
164        n = n.wrapping_add(1);
165    }
166    (*acc).nbEvents = ((*acc).nbEvents).wrapping_sub((*slice).nbEvents);
167}
168pub const CHUNKSIZE: core::ffi::c_int = (8) << 10;
169unsafe fn ZSTD_splitBlock_byChunks(
170    blockStart: *const core::ffi::c_void,
171    blockSize: size_t,
172    level: core::ffi::c_int,
173    workspace: *mut core::ffi::c_void,
174    wkspSize: size_t,
175) -> size_t {
176    static records_fs: [RecordEvents_f; 4] = [
177        Some(
178            ZSTD_recordFingerprint_43
179                as unsafe fn(*mut Fingerprint, *const core::ffi::c_void, size_t) -> (),
180        ),
181        Some(
182            ZSTD_recordFingerprint_11
183                as unsafe fn(*mut Fingerprint, *const core::ffi::c_void, size_t) -> (),
184        ),
185        Some(
186            ZSTD_recordFingerprint_5
187                as unsafe fn(*mut Fingerprint, *const core::ffi::c_void, size_t) -> (),
188        ),
189        Some(
190            ZSTD_recordFingerprint_1
191                as unsafe fn(*mut Fingerprint, *const core::ffi::c_void, size_t) -> (),
192        ),
193    ];
194    static hashParams: [core::ffi::c_uint; 4] = [8, 9, 10, 10];
195    let record_f: RecordEvents_f = *records_fs.as_ptr().offset(level as isize);
196    let fpstats = workspace as *mut FPStats;
197    let p = blockStart as *const core::ffi::c_char;
198    let mut penalty = THRESHOLD_PENALTY;
199    let mut pos = 0;
200    initStats(fpstats);
201    record_f.unwrap_unchecked()(
202        &mut (*fpstats).pastEvents,
203        p as *const core::ffi::c_void,
204        CHUNKSIZE as size_t,
205    );
206    pos = CHUNKSIZE as size_t;
207    while pos <= blockSize.wrapping_sub(CHUNKSIZE as size_t) {
208        record_f.unwrap_unchecked()(
209            &mut (*fpstats).newEvents,
210            p.add(pos) as *const core::ffi::c_void,
211            CHUNKSIZE as size_t,
212        );
213        if compareFingerprints(
214            &(*fpstats).pastEvents,
215            &(*fpstats).newEvents,
216            penalty,
217            *hashParams.as_ptr().offset(level as isize),
218        ) != 0
219        {
220            return pos;
221        } else {
222            mergeEvents(&mut (*fpstats).pastEvents, &(*fpstats).newEvents);
223            if penalty > 0 {
224                penalty -= 1;
225            }
226        }
227        pos = pos.wrapping_add(CHUNKSIZE as size_t);
228    }
229    blockSize
230}
231unsafe fn ZSTD_splitBlock_fromBorders(
232    blockStart: *const core::ffi::c_void,
233    blockSize: size_t,
234    workspace: *mut core::ffi::c_void,
235    wkspSize: size_t,
236) -> size_t {
237    let fpstats = workspace as *mut FPStats;
238    let middleEvents = (workspace as *mut core::ffi::c_char).offset(
239        (512 as core::ffi::c_ulong)
240            .wrapping_mul(::core::mem::size_of::<core::ffi::c_uint>() as core::ffi::c_ulong)
241            as isize,
242    ) as *mut core::ffi::c_void as *mut Fingerprint;
243    initStats(fpstats);
244    HIST_add(
245        ((*fpstats).pastEvents.events).as_mut_ptr(),
246        blockStart,
247        SEGMENT_SIZE as size_t,
248    );
249    HIST_add(
250        ((*fpstats).newEvents.events).as_mut_ptr(),
251        (blockStart as *const core::ffi::c_char)
252            .add(blockSize)
253            .offset(-(SEGMENT_SIZE as isize)) as *const core::ffi::c_void,
254        SEGMENT_SIZE as size_t,
255    );
256    (*fpstats).newEvents.nbEvents = SEGMENT_SIZE as size_t;
257    (*fpstats).pastEvents.nbEvents = (*fpstats).newEvents.nbEvents;
258    if compareFingerprints(&(*fpstats).pastEvents, &(*fpstats).newEvents, 0, 8) == 0 {
259        return blockSize;
260    }
261    HIST_add(
262        ((*middleEvents).events).as_mut_ptr(),
263        (blockStart as *const core::ffi::c_char)
264            .add(blockSize / 2)
265            .offset(-((SEGMENT_SIZE / 2) as isize)) as *const core::ffi::c_void,
266        SEGMENT_SIZE as size_t,
267    );
268    (*middleEvents).nbEvents = SEGMENT_SIZE as size_t;
269    let distFromBegin = fpDistance(&(*fpstats).pastEvents, middleEvents, 8);
270    let distFromEnd = fpDistance(&(*fpstats).newEvents, middleEvents, 8);
271    let minDistance = (SEGMENT_SIZE * SEGMENT_SIZE / 3) as u64;
272    if abs64(distFromBegin as i64 - distFromEnd as i64) < minDistance {
273        return (64 * ((1) << 10)) as size_t;
274    }
275    (if distFromBegin > distFromEnd {
276        32 * ((1) << 10)
277    } else {
278        96 * ((1) << 10)
279    }) as size_t
280}
281pub const SEGMENT_SIZE: core::ffi::c_int = 512;
282pub unsafe fn ZSTD_splitBlock(
283    blockStart: *const core::ffi::c_void,
284    blockSize: size_t,
285    level: core::ffi::c_int,
286    workspace: *mut core::ffi::c_void,
287    wkspSize: size_t,
288) -> size_t {
289    if level == 0 {
290        return ZSTD_splitBlock_fromBorders(blockStart, blockSize, workspace, wkspSize);
291    }
292    ZSTD_splitBlock_byChunks(blockStart, blockSize, level - 1, workspace, wkspSize)
293}