mirror of
https://github.com/google/brotli.git
synced 2024-11-26 21:30:10 +00:00
parent
19d86fb9a6
commit
68f1b90ad0
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -1,6 +0,0 @@
|
|||||||
[submodule "research/esaxx"]
|
|
||||||
path = research/esaxx
|
|
||||||
url = https://github.com/hillbig/esaxx
|
|
||||||
[submodule "research/libdivsufsort"]
|
|
||||||
path = research/libdivsufsort
|
|
||||||
url = https://github.com/y-256/libdivsufsort.git
|
|
@ -166,9 +166,9 @@ matrix:
|
|||||||
- os: osx
|
- os: osx
|
||||||
osx_image: xcode12.2
|
osx_image: xcode12.2
|
||||||
env: BUILD_SYSTEM=cmake C_COMPILER=gcc CXX_COMPILER=g++
|
env: BUILD_SYSTEM=cmake C_COMPILER=gcc CXX_COMPILER=g++
|
||||||
- os: osx
|
#- os: osx
|
||||||
osx_image: xcode12.2
|
# osx_image: xcode12.2
|
||||||
env: BUILD_SYSTEM=cmake C_COMPILER=gcc-4.9 CXX_COMPILER=g++-4.9
|
# env: BUILD_SYSTEM=cmake C_COMPILER=gcc-4.9 CXX_COMPILER=g++-4.9
|
||||||
- os: osx
|
- os: osx
|
||||||
osx_image: xcode12.2
|
osx_image: xcode12.2
|
||||||
env: BUILD_SYSTEM=cmake
|
env: BUILD_SYSTEM=cmake
|
||||||
|
4
BUILD
4
BUILD
@ -1,6 +1,8 @@
|
|||||||
# Description:
|
# Description:
|
||||||
# Brotli is a generic-purpose lossless compression algorithm.
|
# Brotli is a generic-purpose lossless compression algorithm.
|
||||||
|
|
||||||
|
load(":compiler_config_setting.bzl", "create_msvc_config")
|
||||||
|
|
||||||
package(
|
package(
|
||||||
default_visibility = ["//visibility:public"],
|
default_visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
@ -39,8 +41,6 @@ config_setting(
|
|||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
||||||
load(":compiler_config_setting.bzl", "create_msvc_config")
|
|
||||||
|
|
||||||
create_msvc_config()
|
create_msvc_config()
|
||||||
|
|
||||||
STRICT_C_OPTIONS = select({
|
STRICT_C_OPTIONS = select({
|
||||||
|
@ -1238,7 +1238,7 @@ static size_t WriteMetadataHeader(
|
|||||||
return (storage_ix + 7u) >> 3;
|
return (storage_ix + 7u) >> 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_BOOL BrotliCompressBufferQuality10(
|
static BROTLI_NOINLINE BROTLI_BOOL BrotliCompressBufferQuality10(
|
||||||
int lgwin, size_t input_size, const uint8_t* input_buffer,
|
int lgwin, size_t input_size, const uint8_t* input_buffer,
|
||||||
size_t* encoded_size, uint8_t* encoded_buffer) {
|
size_t* encoded_size, uint8_t* encoded_buffer) {
|
||||||
MemoryManager* m =
|
MemoryManager* m =
|
||||||
|
@ -40,7 +40,7 @@ typedef struct BrotliEncoderParams {
|
|||||||
BROTLI_BOOL large_window;
|
BROTLI_BOOL large_window;
|
||||||
BrotliHasherParams hasher;
|
BrotliHasherParams hasher;
|
||||||
BrotliDistanceParams dist;
|
BrotliDistanceParams dist;
|
||||||
/* TODO(eustas): rename to BrotliShared... */
|
/* TODO: rename to BrotliShared... */
|
||||||
SharedEncoderDictionary dictionary;
|
SharedEncoderDictionary dictionary;
|
||||||
} BrotliEncoderParams;
|
} BrotliEncoderParams;
|
||||||
|
|
||||||
|
@ -247,9 +247,10 @@
|
|||||||
#define BROTLI_PUBLIC
|
#define BROTLI_PUBLIC
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
|
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
|
||||||
!defined(__STDC_NO_VLA__) && !defined(__cplusplus) && \
|
!defined(__STDC_NO_VLA__) && !defined(__cplusplus) && \
|
||||||
!defined(__PGI) && !defined(__PGIC__) && !defined(__TINYC__)
|
!defined(__PGI) && !defined(__PGIC__) && !defined(__TINYC__) && \
|
||||||
|
!defined(__clang__)
|
||||||
#define BROTLI_ARRAY_PARAM(name) (name)
|
#define BROTLI_ARRAY_PARAM(name) (name)
|
||||||
#else
|
#else
|
||||||
#define BROTLI_ARRAY_PARAM(name)
|
#define BROTLI_ARRAY_PARAM(name)
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||||
|
|
||||||
package(default_visibility = ["//visibility:public"])
|
package(default_visibility = ["//visibility:public"])
|
||||||
|
|
||||||
licenses(["notice"]) # MIT
|
licenses(["notice"]) # MIT
|
||||||
|
|
||||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
|
||||||
|
|
||||||
go_library(
|
go_library(
|
||||||
name = "cbrotli",
|
name = "cbrotli",
|
||||||
srcs = [
|
srcs = [
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
# Description:
|
# Description:
|
||||||
# Java port of Brotli decoder.
|
# Java port of Brotli decoder.
|
||||||
|
|
||||||
|
load(":build_defs.bzl", "brotli_java_test")
|
||||||
|
|
||||||
package(default_visibility = ["//visibility:public"])
|
package(default_visibility = ["//visibility:public"])
|
||||||
|
|
||||||
licenses(["notice"]) # MIT
|
licenses(["notice"]) # MIT
|
||||||
@ -14,14 +16,15 @@ java_library(
|
|||||||
name = "dec",
|
name = "dec",
|
||||||
srcs = glob(
|
srcs = glob(
|
||||||
["*.java"],
|
["*.java"],
|
||||||
exclude = ["*Test*.java"],
|
exclude = [
|
||||||
|
"Decoder.java",
|
||||||
|
"*Test*.java",
|
||||||
|
],
|
||||||
),
|
),
|
||||||
proguard_specs = ["proguard.pgcfg"],
|
proguard_specs = ["proguard.pgcfg"],
|
||||||
resource_jars = ["//:license"],
|
resource_jars = ["//:license"],
|
||||||
)
|
)
|
||||||
|
|
||||||
load(":build_defs.bzl", "brotli_java_test")
|
|
||||||
|
|
||||||
brotli_java_test(
|
brotli_java_test(
|
||||||
name = "BitReaderTest",
|
name = "BitReaderTest",
|
||||||
srcs = ["BitReaderTest.java"],
|
srcs = ["BitReaderTest.java"],
|
||||||
|
61
java/org/brotli/dec/Decoder.java
Normal file
61
java/org/brotli/dec/Decoder.java
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package org.brotli.dec;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
public class Decoder {
|
||||||
|
private static long decodeBytes(InputStream input, OutputStream output, byte[] buffer)
|
||||||
|
throws IOException {
|
||||||
|
long totalOut = 0;
|
||||||
|
int readBytes;
|
||||||
|
BrotliInputStream in = new BrotliInputStream(input);
|
||||||
|
in.enableLargeWindow();
|
||||||
|
try {
|
||||||
|
while ((readBytes = in.read(buffer)) >= 0) {
|
||||||
|
output.write(buffer, 0, readBytes);
|
||||||
|
totalOut += readBytes;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
return totalOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String... args) throws IOException {
|
||||||
|
if (args.length != 2) {
|
||||||
|
System.out.println("Usage: decoder <compressed_in> <decompressed_out>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] buffer = new byte[1024 * 1024];
|
||||||
|
long start;
|
||||||
|
long bytesDecoded;
|
||||||
|
long end;
|
||||||
|
InputStream in = null;
|
||||||
|
OutputStream out = null;
|
||||||
|
try {
|
||||||
|
in = new FileInputStream(args[0]);
|
||||||
|
out = new FileOutputStream(args[1]);
|
||||||
|
start = System.nanoTime();
|
||||||
|
bytesDecoded = decodeBytes(in, out, buffer);
|
||||||
|
end = System.nanoTime();
|
||||||
|
} finally {
|
||||||
|
if (in != null) {
|
||||||
|
in.close(); // Hopefully, does not throw exception.
|
||||||
|
}
|
||||||
|
if (out != null) {
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double timeDelta = (end - start) / 1000000000.0;
|
||||||
|
if (timeDelta <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
double mbDecoded = bytesDecoded / (1024.0 * 1024.0);
|
||||||
|
System.out.println(mbDecoded / timeDelta + " MiB/s");
|
||||||
|
}
|
||||||
|
}
|
117
java/org/brotli/integration/Benchmark.java
Normal file
117
java/org/brotli/integration/Benchmark.java
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
package org.brotli.integration;
|
||||||
|
|
||||||
|
import org.brotli.dec.BrotliInputStream;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Measures decompression speed on the given corpus.
|
||||||
|
*/
|
||||||
|
public class Benchmark {
|
||||||
|
private static byte[] readFile(String fileName) throws IOException {
|
||||||
|
int bufferLength = 65536;
|
||||||
|
byte[] buffer = new byte[bufferLength];
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
FileInputStream fin = new FileInputStream(fileName);
|
||||||
|
try {
|
||||||
|
int bytesRead;
|
||||||
|
while ((bytesRead = fin.read(buffer)) >= 0) {
|
||||||
|
baos.write(buffer, 0, bytesRead);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
fin.close();
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long decodeBytes(InputStream input, OutputStream output, byte[] buffer)
|
||||||
|
throws IOException {
|
||||||
|
long totalOut = 0;
|
||||||
|
int readBytes;
|
||||||
|
BrotliInputStream in = new BrotliInputStream(input);
|
||||||
|
try {
|
||||||
|
while ((readBytes = in.read(buffer)) >= 0) {
|
||||||
|
output.write(buffer, 0, readBytes);
|
||||||
|
totalOut += readBytes;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
return totalOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String... args) throws IOException {
|
||||||
|
if (args.length == 0) {
|
||||||
|
System.out.println("Usage: benchmark <corpus>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
File corpusDir = new File(args[0]);
|
||||||
|
ArrayList<String> fileNames = new ArrayList<String>();
|
||||||
|
File[] filesList = corpusDir.listFiles();
|
||||||
|
if (filesList == null) {
|
||||||
|
System.out.println("'" + args[0] + "' is not a directory");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (File file : filesList) {
|
||||||
|
if (!file.isFile()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String fileName = file.getAbsolutePath();
|
||||||
|
if (!fileName.endsWith(".brotli")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fileNames.add(fileName);
|
||||||
|
}
|
||||||
|
int fileCount = fileNames.size();
|
||||||
|
if (fileCount == 0) {
|
||||||
|
System.out.println("No files found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
byte[][] files = new byte[fileCount][];
|
||||||
|
for (int i = 0; i < fileCount; ++i) {
|
||||||
|
files[i] = readFile(fileNames.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream(65536);
|
||||||
|
byte[] buffer = new byte[65536];
|
||||||
|
|
||||||
|
int warmupRepeat = 10;
|
||||||
|
long bytesDecoded = 0;
|
||||||
|
for (int i = 0; i < warmupRepeat; ++i) {
|
||||||
|
bytesDecoded = 0;
|
||||||
|
for (int j = 0; j < fileCount; ++j) {
|
||||||
|
baos.reset();
|
||||||
|
bytesDecoded += decodeBytes(new ByteArrayInputStream(files[j]), baos, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int repeat = 100;
|
||||||
|
|
||||||
|
long bestTime = Long.MAX_VALUE;
|
||||||
|
for (int i = 0; i < repeat; ++i) {
|
||||||
|
long start = System.nanoTime();
|
||||||
|
for (int j = 0; j < fileCount; ++j) {
|
||||||
|
baos.reset();
|
||||||
|
decodeBytes(new ByteArrayInputStream(files[j]), baos, buffer);
|
||||||
|
}
|
||||||
|
long end = System.nanoTime();
|
||||||
|
long timeDelta = end - start;
|
||||||
|
if (timeDelta < bestTime) {
|
||||||
|
bestTime = timeDelta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double timeDeltaSeconds = bestTime / 1000000000.0;
|
||||||
|
if (timeDeltaSeconds <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
double mbDecoded = bytesDecoded / (1024.0 * 1024.0);
|
||||||
|
System.out.println(mbDecoded / timeDeltaSeconds);
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
83
java/org/brotli/wrapper/android/JniHelper.java
Normal file
83
java/org/brotli/wrapper/android/JniHelper.java
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
package org.brotli.wrapper.android;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
public class JniHelper {
|
||||||
|
|
||||||
|
// Should be set on application start.
|
||||||
|
static Context context = null;
|
||||||
|
|
||||||
|
private static final String LIB_NAME = "native";
|
||||||
|
|
||||||
|
private static void tryInitialize() {
|
||||||
|
try {
|
||||||
|
System.loadLibrary(LIB_NAME);
|
||||||
|
} catch (UnsatisfiedLinkError e) {
|
||||||
|
if (context == null) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
int sdk = Build.VERSION.SDK_INT;
|
||||||
|
boolean tryFallback =
|
||||||
|
(sdk >= Build.VERSION_CODES.JELLY_BEAN) && (sdk <= Build.VERSION_CODES.KITKAT);
|
||||||
|
if (!tryFallback) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String libraryFileName = "lib" + LIB_NAME + ".so";
|
||||||
|
String libraryFullPath = context.getFilesDir() + File.separator + libraryFileName;
|
||||||
|
File file = new File(libraryFullPath);
|
||||||
|
if (!file.exists()) {
|
||||||
|
String apkPath = context.getApplicationInfo().sourceDir;
|
||||||
|
String pathInApk = "lib/" + Build.CPU_ABI + "/lib" + LIB_NAME + ".so";
|
||||||
|
unzip(apkPath, pathInApk, libraryFullPath);
|
||||||
|
}
|
||||||
|
System.load(libraryFullPath);
|
||||||
|
} catch (UnsatisfiedLinkError unsatisfiedLinkError) {
|
||||||
|
throw unsatisfiedLinkError;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
UnsatisfiedLinkError unsatisfiedLinkError = new UnsatisfiedLinkError(
|
||||||
|
"Exception while extracting native library: " + t.getMessage());
|
||||||
|
unsatisfiedLinkError.initCause(t);
|
||||||
|
throw unsatisfiedLinkError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Object mutex = new Object();
|
||||||
|
private static volatile boolean alreadyInitialized;
|
||||||
|
|
||||||
|
public static void ensureInitialized() {
|
||||||
|
synchronized (mutex) {
|
||||||
|
if (!alreadyInitialized) {
|
||||||
|
// If failed, do not retry.
|
||||||
|
alreadyInitialized = true;
|
||||||
|
tryInitialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void unzip(String zipFileName, String entryName, String outputFileName)
|
||||||
|
throws IOException {
|
||||||
|
ZipFile zipFile = new ZipFile(zipFileName);
|
||||||
|
try {
|
||||||
|
InputStream input = zipFile.getInputStream(zipFile.getEntry(entryName));
|
||||||
|
OutputStream output = new FileOutputStream(outputFileName);
|
||||||
|
byte[] data = new byte[16384];
|
||||||
|
int len;
|
||||||
|
while ((len = input.read(data)) != -1) {
|
||||||
|
output.write(data, 0, len);
|
||||||
|
}
|
||||||
|
output.close();
|
||||||
|
input.close();
|
||||||
|
} finally {
|
||||||
|
zipFile.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
java/org/brotli/wrapper/android/UseJni.java
Normal file
22
java/org/brotli/wrapper/android/UseJni.java
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package org.brotli.wrapper.android;
|
||||||
|
|
||||||
|
import org.brotli.wrapper.dec.Decoder;
|
||||||
|
import org.brotli.wrapper.enc.Encoder;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public final class UseJni {
|
||||||
|
|
||||||
|
static {
|
||||||
|
JniHelper.ensureInitialized();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int deepThought() {
|
||||||
|
String theUltimateQuestion = "What do you get when you multiply six by 9";
|
||||||
|
try {
|
||||||
|
return Decoder.decompress(
|
||||||
|
Encoder.compress(new byte[theUltimateQuestion.length()])).length;
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new RuntimeException("Please wait 7.5 million years");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
java/org/brotli/wrapper/android/UseJniTest.java
Normal file
23
java/org/brotli/wrapper/android/UseJniTest.java
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package org.brotli.wrapper.android;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertEquals;
|
||||||
|
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
import com.google.thirdparty.robolectric.GoogleRobolectricTestRunner;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
@RunWith(GoogleRobolectricTestRunner.class)
|
||||||
|
public final class UseJniTest {
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
JniHelper.context = ApplicationProvider.getApplicationContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything() {
|
||||||
|
assertEquals(42, UseJni.deepThought());
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,12 @@ licenses(["notice"]) # MIT
|
|||||||
|
|
||||||
filegroup(
|
filegroup(
|
||||||
name = "jni_src",
|
name = "jni_src",
|
||||||
srcs = ["decoder_jni.cc"],
|
srcs = [
|
||||||
|
"decoder_jni.cc",
|
||||||
|
"decoder_jni.h",
|
||||||
|
# TODO: investigate, why this prevents JNI library loading.
|
||||||
|
#"decoder_jni_onload.cc",
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
java_library(
|
java_library(
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <jni.h>
|
#include "./decoder_jni.h"
|
||||||
|
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
|
75
java/org/brotli/wrapper/dec/decoder_jni.h
Normal file
75
java/org/brotli/wrapper/dec/decoder_jni.h
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
Distributed under MIT license.
|
||||||
|
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BROTLI_WRAPPER_DEC_DECODER_JNI_H_
|
||||||
|
#define BROTLI_WRAPPER_DEC_DECODER_JNI_H_
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Decoder.
|
||||||
|
*
|
||||||
|
* Cookie to address created decoder is stored in out_cookie. In case of failure
|
||||||
|
* cookie is 0.
|
||||||
|
*
|
||||||
|
* @param ctx {out_cookie, in_directBufferSize} tuple
|
||||||
|
* @returns direct ByteBuffer if directBufferSize is not 0; otherwise null
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobject JNICALL
|
||||||
|
Java_org_brotli_wrapper_dec_DecoderJNI_nativeCreate(
|
||||||
|
JNIEnv* env, jobject /*jobj*/, jlongArray ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push data to decoder.
|
||||||
|
*
|
||||||
|
* status codes:
|
||||||
|
* - 0 error happened
|
||||||
|
* - 1 stream is finished, no more input / output expected
|
||||||
|
* - 2 needs more input to process further
|
||||||
|
* - 3 needs more output to process further
|
||||||
|
* - 4 ok, can proceed further without additional input
|
||||||
|
*
|
||||||
|
* @param ctx {in_cookie, out_status} tuple
|
||||||
|
* @param input_length number of bytes provided in input or direct input;
|
||||||
|
* 0 to process further previous input
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_org_brotli_wrapper_dec_DecoderJNI_nativePush(
|
||||||
|
JNIEnv* env, jobject /*jobj*/, jlongArray ctx, jint input_length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pull decompressed data from decoder.
|
||||||
|
*
|
||||||
|
* @param ctx {in_cookie, out_status} tuple
|
||||||
|
* @returns direct ByteBuffer; all the produced data MUST be consumed before
|
||||||
|
* any further invocation; null in case of error
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobject JNICALL
|
||||||
|
Java_org_brotli_wrapper_dec_DecoderJNI_nativePull(
|
||||||
|
JNIEnv* env, jobject /*jobj*/, jlongArray ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Releases all used resources.
|
||||||
|
*
|
||||||
|
* @param ctx {in_cookie} tuple
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_org_brotli_wrapper_dec_DecoderJNI_nativeDestroy(
|
||||||
|
JNIEnv* env, jobject /*jobj*/, jlongArray ctx);
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_org_brotli_wrapper_dec_DecoderJNI_nativeAttachDictionary(
|
||||||
|
JNIEnv* env, jobject /*jobj*/, jlongArray ctx, jobject dictionary);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // BROTLI_WRAPPER_DEC_DECODER_JNI_H_
|
55
java/org/brotli/wrapper/dec/decoder_jni_onload.cc
Normal file
55
java/org/brotli/wrapper/dec/decoder_jni_onload.cc
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
Distributed under MIT license.
|
||||||
|
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
#include "./decoder_jni.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const JNINativeMethod kDecoderMethods[] = {
|
||||||
|
{"nativeCreate", "([J)Ljava/nio/ByteBuffer;",
|
||||||
|
reinterpret_cast<void*>(
|
||||||
|
Java_org_brotli_wrapper_dec_DecoderJNI_nativeCreate)},
|
||||||
|
{"nativePush", "([JI)V",
|
||||||
|
reinterpret_cast<void*>(
|
||||||
|
Java_org_brotli_wrapper_dec_DecoderJNI_nativePush)},
|
||||||
|
{"nativePull", "([J)Ljava/nio/ByteBuffer;",
|
||||||
|
reinterpret_cast<void*>(
|
||||||
|
Java_org_brotli_wrapper_dec_DecoderJNI_nativePull)},
|
||||||
|
{"nativeDestroy", "([J)V",
|
||||||
|
reinterpret_cast<void*>(
|
||||||
|
Java_org_brotli_wrapper_dec_DecoderJNI_nativeDestroy)},
|
||||||
|
{"nativeAttachDictionary", "([JLjava/nio/ByteBuffer;)Z",
|
||||||
|
reinterpret_cast<void*>(
|
||||||
|
Java_org_brotli_wrapper_dec_DecoderJNI_nativeAttachDictionary)}};
|
||||||
|
|
||||||
|
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||||
|
JNIEnv* env;
|
||||||
|
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
jclass clazz =
|
||||||
|
env->FindClass("com/google/compression/brotli/wrapper/dec/DecoderJNI");
|
||||||
|
if (clazz == nullptr) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (env->RegisterNatives(
|
||||||
|
clazz, kDecoderMethods,
|
||||||
|
sizeof(kDecoderMethods) / sizeof(kDecoderMethods[0])) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return JNI_VERSION_1_6;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@ -69,6 +69,8 @@ public class Encoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Setup encoder quality.
|
||||||
|
*
|
||||||
* @param quality compression quality, or -1 for default
|
* @param quality compression quality, or -1 for default
|
||||||
*/
|
*/
|
||||||
public Parameters setQuality(int quality) {
|
public Parameters setQuality(int quality) {
|
||||||
@ -80,6 +82,8 @@ public class Encoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Setup encoder window size.
|
||||||
|
*
|
||||||
* @param lgwin log2(LZ window size), or -1 for default
|
* @param lgwin log2(LZ window size), or -1 for default
|
||||||
*/
|
*/
|
||||||
public Parameters setWindow(int lgwin) {
|
public Parameters setWindow(int lgwin) {
|
||||||
@ -91,6 +95,8 @@ public class Encoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Setup encoder compression mode.
|
||||||
|
*
|
||||||
* @param mode compression mode, or {@code null} for default
|
* @param mode compression mode, or {@code null} for default
|
||||||
*/
|
*/
|
||||||
public Parameters setMode(Mode mode) {
|
public Parameters setMode(Mode mode) {
|
||||||
@ -116,7 +122,8 @@ public class Encoder {
|
|||||||
}
|
}
|
||||||
this.dictionaries = new ArrayList<PreparedDictionary>();
|
this.dictionaries = new ArrayList<PreparedDictionary>();
|
||||||
this.destination = destination;
|
this.destination = destination;
|
||||||
this.encoder = new EncoderJNI.Wrapper(inputBufferSize, params.quality, params.lgwin, params.mode);
|
this.encoder =
|
||||||
|
new EncoderJNI.Wrapper(inputBufferSize, params.quality, params.lgwin, params.mode);
|
||||||
this.inputBuffer = this.encoder.getInputBuffer();
|
this.inputBuffer = this.encoder.getInputBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,7 +219,8 @@ public class Encoder {
|
|||||||
return empty;
|
return empty;
|
||||||
}
|
}
|
||||||
/* data.length > 0 */
|
/* data.length > 0 */
|
||||||
EncoderJNI.Wrapper encoder = new EncoderJNI.Wrapper(data.length, params.quality, params.lgwin, params.mode);
|
EncoderJNI.Wrapper encoder =
|
||||||
|
new EncoderJNI.Wrapper(data.length, params.quality, params.lgwin, params.mode);
|
||||||
ArrayList<byte[]> output = new ArrayList<byte[]>();
|
ArrayList<byte[]> output = new ArrayList<byte[]>();
|
||||||
int totalOutputSize = 0;
|
int totalOutputSize = 0;
|
||||||
try {
|
try {
|
||||||
|
6
js/BUILD
6
js/BUILD
@ -1,11 +1,11 @@
|
|||||||
|
load("@io_bazel_rules_closure//closure:defs.bzl", "closure_js_library", "closure_js_test")
|
||||||
|
|
||||||
package(
|
package(
|
||||||
default_visibility = ["//visibility:public"],
|
default_visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
||||||
licenses(["notice"]) # MIT
|
licenses(["notice"]) # MIT
|
||||||
|
|
||||||
load("@io_bazel_rules_closure//closure:defs.bzl", "closure_js_library")
|
|
||||||
|
|
||||||
# Not a real polyfill. Do NOT use for anything, but tests.
|
# Not a real polyfill. Do NOT use for anything, but tests.
|
||||||
closure_js_library(
|
closure_js_library(
|
||||||
name = "polyfill",
|
name = "polyfill",
|
||||||
@ -27,8 +27,6 @@ closure_js_library(
|
|||||||
deps = [":polyfill"],
|
deps = [":polyfill"],
|
||||||
)
|
)
|
||||||
|
|
||||||
load("@io_bazel_rules_closure//closure:defs.bzl", "closure_js_test")
|
|
||||||
|
|
||||||
closure_js_test(
|
closure_js_test(
|
||||||
name = "all_tests",
|
name = "all_tests",
|
||||||
srcs = ["decode_test.js"],
|
srcs = ["decode_test.js"],
|
||||||
|
72
js/bundle_test.js
Normal file
72
js/bundle_test.js
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
Distributed under MIT license.
|
||||||
|
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
import {BrotliDecode} from "./decode.js";
|
||||||
|
import {makeTestData} from "./test_data.js";
|
||||||
|
goog.require('goog.testing.asserts');
|
||||||
|
const testSuite = goog.require('goog.testing.testSuite');
|
||||||
|
|
||||||
|
const CRC_64_POLY = new Uint32Array([0xD7870F42, 0xC96C5795]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates binary data footprint.
|
||||||
|
*
|
||||||
|
* @param {!Int8Array} data binary data
|
||||||
|
* @return {string} footprint
|
||||||
|
*/
|
||||||
|
function calculateCrc64(data) {
|
||||||
|
let crc = new Uint32Array([0xFFFFFFFF, 0xFFFFFFFF]);
|
||||||
|
let c = new Uint32Array(2);
|
||||||
|
for (let i = 0; i < data.length; ++i) {
|
||||||
|
c[1] = 0;
|
||||||
|
c[0] = (crc[0] ^ data[i]) & 0xFF;
|
||||||
|
for (let k = 0; k < 8; ++k) {
|
||||||
|
const isOdd = c[0] & 1;
|
||||||
|
c[0] = (c[0] >>> 1) | ((c[1] & 1) << 31);
|
||||||
|
c[1] = c[1] >>> 1;
|
||||||
|
if (isOdd) {
|
||||||
|
c[0] = c[0] ^ CRC_64_POLY[0];
|
||||||
|
c[1] = c[1] ^ CRC_64_POLY[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
crc[0] = ((crc[0] >>> 8) | ((crc[1] & 0xFF) << 24)) ^ c[0];
|
||||||
|
crc[1] = (crc[1] >>> 8) ^ c[1];
|
||||||
|
}
|
||||||
|
crc[0] = ~crc[0];
|
||||||
|
crc[1] = ~crc[1];
|
||||||
|
|
||||||
|
let lo = crc[0].toString(16);
|
||||||
|
lo = "0".repeat(8 - lo.length) + lo;
|
||||||
|
let hi = crc[1].toString(16);
|
||||||
|
hi = "0".repeat(8 - hi.length) + hi;
|
||||||
|
|
||||||
|
return hi + lo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decompresses data and checks that output footprint is correct.
|
||||||
|
*
|
||||||
|
* @param {string} entry filename including footprint prefix
|
||||||
|
* @param {!Int8Array} data compressed data
|
||||||
|
*/
|
||||||
|
function checkEntry(entry, data) {
|
||||||
|
const expectedCrc = entry.substring(0, 16);
|
||||||
|
const decompressed = BrotliDecode(data);
|
||||||
|
const crc = calculateCrc64(decompressed);
|
||||||
|
assertEquals(expectedCrc, crc);
|
||||||
|
}
|
||||||
|
|
||||||
|
let allTests = {};
|
||||||
|
const testData = makeTestData();
|
||||||
|
for (let entry in testData) {
|
||||||
|
if (!testData.hasOwnProperty(entry)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const name = entry.substring(17);
|
||||||
|
const data = testData[entry];
|
||||||
|
allTests['test_' + name] = checkEntry.bind(null, entry, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
testSuite(allTests);
|
59
js/cli.js
Normal file
59
js/cli.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
let defaults =
|
||||||
|
{input: 'input.br', output: 'output.txt', test_iters: 0, test_repeat: 100};
|
||||||
|
|
||||||
|
/* Parse command line arguments. */
|
||||||
|
let argv =
|
||||||
|
require('yargs')
|
||||||
|
.usage('Usage: $0 -i file -o file')
|
||||||
|
.option(
|
||||||
|
'input',
|
||||||
|
{alias: 'i', default: defaults.input, describe: 'compressed file'})
|
||||||
|
.option('output', {
|
||||||
|
alias: 'o',
|
||||||
|
default: defaults.output,
|
||||||
|
describe: 'decompressed file'
|
||||||
|
})
|
||||||
|
.option('test_iters', {
|
||||||
|
default: defaults.test_iters,
|
||||||
|
describe: '# of times to run performance test'
|
||||||
|
})
|
||||||
|
.option('test_repeat', {
|
||||||
|
default: defaults.test_repeat,
|
||||||
|
describe: '# of times to decompress file in performance test'
|
||||||
|
})
|
||||||
|
.argv;
|
||||||
|
|
||||||
|
/* Read input. */
|
||||||
|
const fs = require('fs');
|
||||||
|
data = fs.readFileSync(argv.input);
|
||||||
|
if (!Buffer.isBuffer(data)) throw 'not a buffer';
|
||||||
|
const bytes = new Uint8Array(data);
|
||||||
|
|
||||||
|
/* Load and map brotli decoder module. */
|
||||||
|
global.window = {};
|
||||||
|
require('./decode.js')
|
||||||
|
const brotliDecode = window['BrotliDecode'];
|
||||||
|
|
||||||
|
/* Load "performance" module. */
|
||||||
|
const {PerformanceObserver, performance} = require('perf_hooks');
|
||||||
|
|
||||||
|
/* Performance test. */
|
||||||
|
for (let i = 0; i < argv.test_iters; ++i) {
|
||||||
|
const a = performance.now();
|
||||||
|
let result;
|
||||||
|
for (let j = 0; j < argv.test_repeat; ++j) {
|
||||||
|
result = brotliDecode(bytes);
|
||||||
|
}
|
||||||
|
const b = performance.now();
|
||||||
|
const total_length = argv.test_repeat * result.length / (1024 * 1024);
|
||||||
|
const total_time = (b - a) / 1000;
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
total_length + 'MB / ' + total_time +
|
||||||
|
's = ' + (total_length / total_time) + 'MB/s');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decode and write output file. */
|
||||||
|
fs.writeFileSync(argv.output, new Buffer(brotliDecode(bytes)));
|
2281
js/decode_synth_test.js
Normal file
2281
js/decode_synth_test.js
Normal file
File diff suppressed because it is too large
Load Diff
14
js/package.json
Normal file
14
js/package.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "brotli",
|
||||||
|
"description": "Pure JavaScript Brotli implementation",
|
||||||
|
"bin": {
|
||||||
|
"brotli": "cli.js"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"cli.js",
|
||||||
|
"decode.js",
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"yargs": "~8.0.2"
|
||||||
|
},
|
||||||
|
}
|
28
js/test_data.js
Normal file
28
js/test_data.js
Normal file
File diff suppressed because one or more lines are too long
BIN
js/test_data.tar
Normal file
BIN
js/test_data.tar
Normal file
Binary file not shown.
@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
import _brotli
|
import _brotli
|
||||||
|
|
||||||
|
|
||||||
# The library version.
|
# The library version.
|
||||||
__version__ = _brotli.__version__
|
__version__ = _brotli.__version__
|
||||||
|
|
||||||
|
@ -7,10 +7,8 @@ licenses(["notice"]) # MIT
|
|||||||
cc_library(
|
cc_library(
|
||||||
name = "dm",
|
name = "dm",
|
||||||
srcs = ["deorummolae.cc"],
|
srcs = ["deorummolae.cc"],
|
||||||
hdrs = [
|
deps = ["@esaxx//:sais"],
|
||||||
"deorummolae.h",
|
hdrs = ["deorummolae.h"],
|
||||||
"esaxx/sais.hxx",
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
cc_library(
|
cc_library(
|
||||||
|
@ -19,6 +19,7 @@ cc_library(
|
|||||||
"-DHAVE_CONFIG_H=1",
|
"-DHAVE_CONFIG_H=1",
|
||||||
],
|
],
|
||||||
includes = ["include"],
|
includes = ["include"],
|
||||||
|
include_prefix = "third_party/libdivsufsort",
|
||||||
)
|
)
|
||||||
|
|
||||||
commom_awk_replaces = (
|
commom_awk_replaces = (
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
CC = g++
|
|
||||||
CFLAGS += -O2
|
|
||||||
CPPFLAGS += -std=c++11
|
|
||||||
SOURCES = $(wildcard *.cc)
|
|
||||||
EXECUTABLES = $(SOURCES:.cc=)
|
|
||||||
BINDIR = bin
|
|
||||||
|
|
||||||
all: $(EXECUTABLES)
|
|
||||||
|
|
||||||
$(BINDIR):
|
|
||||||
mkdir -p $@
|
|
||||||
|
|
||||||
$(EXECUTABLES): $(BINDIR)
|
|
||||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(addsuffix .cc, $@) -o $(BINDIR)/$@ -lgflags_nothreads
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf $(BINDIR)
|
|
@ -1,12 +1,30 @@
|
|||||||
workspace(name = "org_brotli_research")
|
workspace(name = "org_brotli_research")
|
||||||
|
|
||||||
|
load("@bazel_tools//tools/build_defs/repo:git.bzl", "new_git_repository")
|
||||||
|
|
||||||
local_repository(
|
local_repository(
|
||||||
name = "org_brotli",
|
name = "org_brotli",
|
||||||
path = "..",
|
path = "..",
|
||||||
)
|
)
|
||||||
|
|
||||||
new_local_repository(
|
new_git_repository(
|
||||||
name = "divsufsort",
|
name = "divsufsort",
|
||||||
build_file = "BUILD.libdivsufsort",
|
build_file = "@//:BUILD.libdivsufsort",
|
||||||
path = "libdivsufsort",
|
commit = "5f60d6f026c30fb4ac296f696b3c8b0eb71bd428",
|
||||||
|
remote = "https://github.com/y-256/libdivsufsort",
|
||||||
|
)
|
||||||
|
|
||||||
|
new_git_repository(
|
||||||
|
name = "esaxx",
|
||||||
|
build_file_content = """
|
||||||
|
package(default_visibility = ["//visibility:public"])
|
||||||
|
cc_library(
|
||||||
|
name = "sais",
|
||||||
|
hdrs = ["sais.hxx"],
|
||||||
|
includes = ["."],
|
||||||
|
include_prefix = "third_party/esaxx",
|
||||||
|
)
|
||||||
|
""",
|
||||||
|
commit = "ca7cb332011ec37a8436487f210f396b84bd8273",
|
||||||
|
remote = "https://github.com/hillbig/esaxx",
|
||||||
)
|
)
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
#include "./esaxx/sais.hxx"
|
#include "third_party/esaxx/sais.hxx"
|
||||||
|
|
||||||
/* Used for quick SA-entry to file mapping. Each file is padded to size that
|
/* Used for quick SA-entry to file mapping. Each file is padded to size that
|
||||||
is a multiple of chunk size. */
|
is a multiple of chunk size. */
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include <gflags/gflags.h>
|
#include <gflags/gflags.h>
|
||||||
using gflags::ParseCommandLineFlags;
|
using gflags::ParseCommandLineFlags;
|
||||||
|
|
||||||
|
#include "third_party/absl/flags/flag.h"
|
||||||
#include "./read_dist.h"
|
#include "./read_dist.h"
|
||||||
|
|
||||||
DEFINE_int32(height, 1000, "Height of the resulting histogam.");
|
DEFINE_int32(height, 1000, "Height of the resulting histogam.");
|
||||||
@ -32,7 +33,7 @@ DEFINE_bool(linear, false, "True if using linear distance mapping.");
|
|||||||
DEFINE_uint64(skip, 0, "Number of bytes to skip.");
|
DEFINE_uint64(skip, 0, "Number of bytes to skip.");
|
||||||
|
|
||||||
inline double DistanceTransform(double x) {
|
inline double DistanceTransform(double x) {
|
||||||
static bool linear = FLAGS_linear;
|
static bool linear = absl::GetFlag(FLAGS_linear);
|
||||||
if (linear) {
|
if (linear) {
|
||||||
return x;
|
return x;
|
||||||
} else {
|
} else {
|
||||||
@ -48,14 +49,12 @@ inline double DensityTransform(double x) {
|
|||||||
return sqrt(255 * 255 - z * z);
|
return sqrt(255 * 255 - z * z);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int GetMaxDistance() {
|
inline int GetMaxDistance() { return absl::GetFlag(FLAGS_max_distance); }
|
||||||
return FLAGS_max_distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdjustPosition(int* pos) {
|
void AdjustPosition(int* pos) {
|
||||||
static uint32_t offset = 0;
|
static uint32_t offset = 0;
|
||||||
static int last = 0;
|
static int last = 0;
|
||||||
static uint32_t window_size = (1 << FLAGS_brotli_window);
|
static uint32_t window_size = (1 << absl::GetFlag(FLAGS_brotli_window));
|
||||||
assert(*pos >= 0 && *pos < window_size);
|
assert(*pos >= 0 && *pos < window_size);
|
||||||
if (*pos < last) {
|
if (*pos < last) {
|
||||||
offset += window_size;
|
offset += window_size;
|
||||||
@ -65,10 +64,10 @@ void AdjustPosition(int* pos) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BuildHistogram(FILE* fin, int** histo) {
|
void BuildHistogram(FILE* fin, int** histo) {
|
||||||
int height = FLAGS_height;
|
int height = absl::GetFlag(FLAGS_height);
|
||||||
int width = FLAGS_width;
|
int width = absl::GetFlag(FLAGS_width);
|
||||||
int skip = FLAGS_skip;
|
int skip = absl::GetFlag(FLAGS_skip);
|
||||||
size_t min_distance = FLAGS_min_distance;
|
size_t min_distance = absl::GetFlag(FLAGS_min_distance);
|
||||||
|
|
||||||
printf("height = %d, width = %d\n", height, width);
|
printf("height = %d, width = %d\n", height, width);
|
||||||
|
|
||||||
@ -78,7 +77,7 @@ void BuildHistogram(FILE* fin, int** histo) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int max_pos = FLAGS_size - skip;
|
int max_pos = absl::GetFlag(FLAGS_size) - skip;
|
||||||
double min_dist = min_distance > 0 ? DistanceTransform(min_distance) : 0;
|
double min_dist = min_distance > 0 ? DistanceTransform(min_distance) : 0;
|
||||||
double max_dist = DistanceTransform(GetMaxDistance()) - min_dist;
|
double max_dist = DistanceTransform(GetMaxDistance()) - min_dist;
|
||||||
int copy, pos, distance, x, y;
|
int copy, pos, distance, x, y;
|
||||||
@ -86,7 +85,7 @@ void BuildHistogram(FILE* fin, int** histo) {
|
|||||||
while (ReadBackwardReference(fin, ©, &pos, &distance)) {
|
while (ReadBackwardReference(fin, ©, &pos, &distance)) {
|
||||||
if (pos == -1) continue; // In case when only insert is present.
|
if (pos == -1) continue; // In case when only insert is present.
|
||||||
if (distance < min_distance || distance >= GetMaxDistance()) continue;
|
if (distance < min_distance || distance >= GetMaxDistance()) continue;
|
||||||
if (FLAGS_brotli_window != -1) {
|
if (absl::GetFlag(FLAGS_brotli_window) != -1) {
|
||||||
AdjustPosition(&pos);
|
AdjustPosition(&pos);
|
||||||
}
|
}
|
||||||
if (pos >= skip && distance <= pos) {
|
if (pos >= skip && distance <= pos) {
|
||||||
@ -102,7 +101,7 @@ void BuildHistogram(FILE* fin, int** histo) {
|
|||||||
assert(y >= 0 && y < width);
|
assert(y >= 0 && y < width);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FLAGS_with_copies) {
|
if (absl::GetFlag(FLAGS_with_copies)) {
|
||||||
int right = 1ul * (pos + copy - 1) * width / max_pos;
|
int right = 1ul * (pos + copy - 1) * width / max_pos;
|
||||||
if (right < 0) {
|
if (right < 0) {
|
||||||
printf("pos = %d, distance = %d, copy = %d, y = %d, right = %d\n",
|
printf("pos = %d, distance = %d, copy = %d, y = %d, right = %d\n",
|
||||||
@ -131,8 +130,8 @@ void BuildHistogram(FILE* fin, int** histo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ConvertToPixels(int** histo, uint8_t** pixel) {
|
void ConvertToPixels(int** histo, uint8_t** pixel) {
|
||||||
int height = FLAGS_height;
|
int height = absl::GetFlag(FLAGS_height);
|
||||||
int width = FLAGS_width;
|
int width = absl::GetFlag(FLAGS_width);
|
||||||
|
|
||||||
int maxs = 0;
|
int maxs = 0;
|
||||||
for (int i = 0; i < height; i++) {
|
for (int i = 0; i < height; i++) {
|
||||||
@ -141,7 +140,7 @@ void ConvertToPixels(int** histo, uint8_t** pixel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool simple = FLAGS_simple;
|
bool simple = absl::GetFlag(FLAGS_simple);
|
||||||
double max_histo = static_cast<double>(maxs);
|
double max_histo = static_cast<double>(maxs);
|
||||||
for (int i = 0; i < height; i++) {
|
for (int i = 0; i < height; i++) {
|
||||||
for (int j = 0; j < width; j++) {
|
for (int j = 0; j < width; j++) {
|
||||||
@ -156,8 +155,8 @@ void ConvertToPixels(int** histo, uint8_t** pixel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DrawPixels(uint8_t** pixel, FILE* fout) {
|
void DrawPixels(uint8_t** pixel, FILE* fout) {
|
||||||
int height = FLAGS_height;
|
int height = absl::GetFlag(FLAGS_height);
|
||||||
int width = FLAGS_width;
|
int width = absl::GetFlag(FLAGS_width);
|
||||||
|
|
||||||
fprintf(fout, "P5\n%d %d\n255\n", width, height);
|
fprintf(fout, "P5\n%d %d\n255\n", width, height);
|
||||||
for (int i = height - 1; i >= 0; i--) {
|
for (int i = height - 1; i >= 0; i--) {
|
||||||
@ -166,14 +165,14 @@ void DrawPixels(uint8_t** pixel, FILE* fout) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
ParseCommandLineFlags(&argc, &argv, true);
|
base::ParseCommandLine(&argc, &argv);
|
||||||
if (argc != 3) {
|
if (argc != 3) {
|
||||||
printf("usage: draw_histogram.cc data output_file\n");
|
printf("usage: draw_histogram.cc data output_file\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int height = FLAGS_height;
|
int height = absl::GetFlag(FLAGS_height);
|
||||||
int width = FLAGS_width;
|
int width = absl::GetFlag(FLAGS_width);
|
||||||
|
|
||||||
FILE* fin = fopen(argv[1], "r");
|
FILE* fin = fopen(argv[1], "r");
|
||||||
FILE* fout = fopen(argv[2], "wb");
|
FILE* fout = fopen(argv[2], "wb");
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <exception> /* terminate */
|
#include <exception> /* terminate */
|
||||||
|
|
||||||
#include "divsufsort.h"
|
#include "third_party/libdivsufsort/include/divsufsort.h"
|
||||||
|
|
||||||
/* Pointer to position in text. */
|
/* Pointer to position in text. */
|
||||||
typedef DurchschlagTextIdx TextIdx;
|
typedef DurchschlagTextIdx TextIdx;
|
||||||
|
@ -1 +0,0 @@
|
|||||||
Subproject commit ca7cb332011ec37a8436487f210f396b84bd8273
|
|
@ -19,7 +19,8 @@
|
|||||||
#include <gflags/gflags.h>
|
#include <gflags/gflags.h>
|
||||||
using gflags::ParseCommandLineFlags;
|
using gflags::ParseCommandLineFlags;
|
||||||
|
|
||||||
#include "./esaxx/sais.hxx"
|
#include "third_party/absl/flags/flag.h"
|
||||||
|
#include "third_party/esaxx/sais.hxx"
|
||||||
|
|
||||||
DEFINE_bool(advanced, false, "Advanced searching mode: finds all longest "
|
DEFINE_bool(advanced, false, "Advanced searching mode: finds all longest "
|
||||||
"matches at positions that are not covered by matches of length at least "
|
"matches at positions that are not covered by matches of length at least "
|
||||||
@ -91,7 +92,7 @@ inline void PrintReference(sarray_type* sarray, lcp_type* lcp, size_t size,
|
|||||||
inline void GoLeft(sarray_type* sarray, lcp_type* lcp, int idx, int left_ix,
|
inline void GoLeft(sarray_type* sarray, lcp_type* lcp, int idx, int left_ix,
|
||||||
int left_lcp, entry_type* entry) {
|
int left_lcp, entry_type* entry) {
|
||||||
entry->first = left_lcp;
|
entry->first = left_lcp;
|
||||||
if (left_lcp > FLAGS_long_length) return;
|
if (left_lcp > absl::GetFlag(FLAGS_long_length)) return;
|
||||||
for (; left_ix >= 0; --left_ix) {
|
for (; left_ix >= 0; --left_ix) {
|
||||||
if (lcp[left_ix] < left_lcp) break;
|
if (lcp[left_ix] < left_lcp) break;
|
||||||
if (sarray[left_ix] < idx) {
|
if (sarray[left_ix] < idx) {
|
||||||
@ -103,7 +104,7 @@ inline void GoLeft(sarray_type* sarray, lcp_type* lcp, int idx, int left_ix,
|
|||||||
inline void GoRight(sarray_type* sarray, lcp_type* lcp, int idx, size_t size,
|
inline void GoRight(sarray_type* sarray, lcp_type* lcp, int idx, size_t size,
|
||||||
int right_ix, int right_lcp, entry_type* entry) {
|
int right_ix, int right_lcp, entry_type* entry) {
|
||||||
entry->first = right_lcp;
|
entry->first = right_lcp;
|
||||||
if (right_lcp > FLAGS_long_length) return;
|
if (right_lcp > absl::GetFlag(FLAGS_long_length)) return;
|
||||||
for (; right_ix < size - 1; ++right_ix) {
|
for (; right_ix < size - 1; ++right_ix) {
|
||||||
if (lcp[right_ix] < right_lcp) break;
|
if (lcp[right_ix] < right_lcp) break;
|
||||||
if (sarray[right_ix] < idx) {
|
if (sarray[right_ix] < idx) {
|
||||||
@ -129,8 +130,8 @@ inline void StoreReference(sarray_type* sarray, lcp_type* lcp, size_t size,
|
|||||||
|
|
||||||
void ProcessReferences(sarray_type* sarray, lcp_type* lcp, size_t size,
|
void ProcessReferences(sarray_type* sarray, lcp_type* lcp, size_t size,
|
||||||
uint32_t* pos, const Fn& process_output) {
|
uint32_t* pos, const Fn& process_output) {
|
||||||
int min_length = FLAGS_min_length;
|
int min_length = absl::GetFlag(FLAGS_min_length);
|
||||||
for (int idx = FLAGS_skip; idx < size; ++idx) {
|
for (int idx = absl::GetFlag(FLAGS_skip); idx < size; ++idx) {
|
||||||
int left_lcp = -1;
|
int left_lcp = -1;
|
||||||
int left_ix;
|
int left_ix;
|
||||||
for (left_ix = pos[idx] - 1; left_ix >= 0; --left_ix) {
|
for (left_ix = pos[idx] - 1; left_ix >= 0; --left_ix) {
|
||||||
@ -162,7 +163,7 @@ void ProcessReferences(sarray_type* sarray, lcp_type* lcp, size_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ProcessEntries(entry_type* entries, size_t size, FILE* fout) {
|
void ProcessEntries(entry_type* entries, size_t size, FILE* fout) {
|
||||||
int long_length = FLAGS_long_length;
|
int long_length = absl::GetFlag(FLAGS_long_length);
|
||||||
std::vector<std::pair<int, int> > segments;
|
std::vector<std::pair<int, int> > segments;
|
||||||
size_t idx;
|
size_t idx;
|
||||||
for (idx = 0; idx < size;) {
|
for (idx = 0; idx < size;) {
|
||||||
@ -195,7 +196,7 @@ void ProcessEntries(entry_type* entries, size_t size, FILE* fout) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
ParseCommandLineFlags(&argc, &argv, true);
|
base::ParseCommandLine(&argc, &argv);
|
||||||
if (argc != 3) {
|
if (argc != 3) {
|
||||||
printf("usage: %s input_file output_file\n", argv[0]);
|
printf("usage: %s input_file output_file\n", argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
@ -235,7 +236,7 @@ int main(int argc, char* argv[]) {
|
|||||||
using std::placeholders::_7;
|
using std::placeholders::_7;
|
||||||
using std::placeholders::_8;
|
using std::placeholders::_8;
|
||||||
entry_type* entries;
|
entry_type* entries;
|
||||||
if (FLAGS_advanced) {
|
if (absl::GetFlag(FLAGS_advanced)) {
|
||||||
entries = new entry_type[input_size];
|
entries = new entry_type[input_size];
|
||||||
for (size_t i = 0; i < input_size; ++i) entries[i].first = -1;
|
for (size_t i = 0; i < input_size; ++i) entries[i].first = -1;
|
||||||
}
|
}
|
||||||
@ -243,10 +244,10 @@ int main(int argc, char* argv[]) {
|
|||||||
Fn store = std::bind(StoreReference, _1, _2, _3, _4, _5, _6, _7, _8, entries);
|
Fn store = std::bind(StoreReference, _1, _2, _3, _4, _5, _6, _7, _8, entries);
|
||||||
|
|
||||||
ProcessReferences(sarray, lcp, input_size, pos,
|
ProcessReferences(sarray, lcp, input_size, pos,
|
||||||
FLAGS_advanced ? store : print);
|
absl::GetFlag(FLAGS_advanced) ? store : print);
|
||||||
printf("References processed.\n");
|
printf("References processed.\n");
|
||||||
|
|
||||||
if (FLAGS_advanced) {
|
if (absl::GetFlag(FLAGS_advanced)) {
|
||||||
int good_cnt = 0;
|
int good_cnt = 0;
|
||||||
uint64_t avg_cnt = 0;
|
uint64_t avg_cnt = 0;
|
||||||
for (size_t i = 0; i < input_size; ++i) {
|
for (size_t i = 0; i < input_size; ++i) {
|
||||||
|
@ -1 +0,0 @@
|
|||||||
Subproject commit 5f60d6f026c30fb4ac296f696b3c8b0eb71bd428
|
|
Loading…
Reference in New Issue
Block a user