├── .bazelrc
├── .gitignore
├── BUILD.bazel
├── CMakeLists.txt
├── CONTRIBUTING.md
├── GoogleTest-CMakeLists.txt.in
├── LICENSE
├── README.md
├── WORKSPACE
├── cmake-format.json
├── include
└── astc-codec
│ └── astc-codec.h
├── src
├── .clang-format
├── base
│ ├── BUILD.bazel
│ ├── CMakeLists.txt
│ ├── bit_stream.h
│ ├── bottom_n.h
│ ├── math_utils.h
│ ├── optional.h
│ ├── string_utils.h
│ ├── test
│ │ ├── bit_stream_test.cpp
│ │ ├── bottom_n_test.cpp
│ │ ├── math_utils_test.cpp
│ │ ├── optional_test.cpp
│ │ ├── string_utils_test.cpp
│ │ ├── type_traits_test.cpp
│ │ └── uint128_test.cpp
│ ├── type_traits.h
│ ├── uint128.h
│ └── utils.h
└── decoder
│ ├── BUILD.bazel
│ ├── CMakeLists.txt
│ ├── astc_file.cc
│ ├── astc_file.h
│ ├── codec.cc
│ ├── codec.h
│ ├── endpoint_codec.cc
│ ├── endpoint_codec.h
│ ├── footprint.cc
│ ├── footprint.h
│ ├── integer_sequence_codec.cc
│ ├── integer_sequence_codec.h
│ ├── intermediate_astc_block.cc
│ ├── intermediate_astc_block.h
│ ├── logical_astc_block.cc
│ ├── logical_astc_block.h
│ ├── partition.cc
│ ├── partition.h
│ ├── physical_astc_block.cc
│ ├── physical_astc_block.h
│ ├── quantization.cc
│ ├── quantization.h
│ ├── test
│ ├── astc_fuzzer.cc
│ ├── codec_test.cc
│ ├── endpoint_codec_test.cc
│ ├── footprint_test.cc
│ ├── image_utils.h
│ ├── integer_sequence_codec_test.cc
│ ├── intermediate_astc_block_test.cc
│ ├── logical_astc_block_test.cc
│ ├── partition_test.cc
│ ├── physical_astc_block_test.cc
│ ├── quantization_test.cc
│ └── weight_infill_test.cc
│ ├── testdata
│ ├── atlas_small_4x4.astc
│ ├── atlas_small_4x4.bmp
│ ├── atlas_small_5x5.astc
│ ├── atlas_small_5x5.bmp
│ ├── atlas_small_6x6.astc
│ ├── atlas_small_6x6.bmp
│ ├── atlas_small_8x8.astc
│ ├── atlas_small_8x8.bmp
│ ├── checkerboard.astc
│ ├── checkered_10.astc
│ ├── checkered_11.astc
│ ├── checkered_12.astc
│ ├── checkered_4.astc
│ ├── checkered_5.astc
│ ├── checkered_6.astc
│ ├── checkered_7.astc
│ ├── checkered_8.astc
│ ├── checkered_9.astc
│ ├── footprint_10x10.astc
│ ├── footprint_10x10.bmp
│ ├── footprint_10x5.astc
│ ├── footprint_10x5.bmp
│ ├── footprint_10x6.astc
│ ├── footprint_10x6.bmp
│ ├── footprint_10x8.astc
│ ├── footprint_10x8.bmp
│ ├── footprint_12x10.astc
│ ├── footprint_12x10.bmp
│ ├── footprint_12x12.astc
│ ├── footprint_12x12.bmp
│ ├── footprint_4x4.astc
│ ├── footprint_4x4.bmp
│ ├── footprint_5x4.astc
│ ├── footprint_5x4.bmp
│ ├── footprint_5x5.astc
│ ├── footprint_5x5.bmp
│ ├── footprint_6x5.astc
│ ├── footprint_6x5.bmp
│ ├── footprint_6x6.astc
│ ├── footprint_6x6.bmp
│ ├── footprint_8x5.astc
│ ├── footprint_8x5.bmp
│ ├── footprint_8x6.astc
│ ├── footprint_8x6.bmp
│ ├── footprint_8x8.astc
│ ├── footprint_8x8.bmp
│ ├── rgb_12x12.astc
│ ├── rgb_12x12.bmp
│ ├── rgb_4x4.astc
│ ├── rgb_4x4.bmp
│ ├── rgb_5x4.astc
│ ├── rgb_5x4.bmp
│ ├── rgb_6x6.astc
│ ├── rgb_6x6.bmp
│ ├── rgb_8x8.astc
│ └── rgb_8x8.bmp
│ ├── tools
│ └── astc_inspector_cli.cc
│ ├── types.h
│ ├── weight_infill.cc
│ └── weight_infill.h
├── third_party
├── BUILD
└── honggfuzz.BUILD
└── tools
└── build-ci
└── linux
├── build.sh
├── continuous.cfg
└── presubmit.cfg
/.bazelrc:
--------------------------------------------------------------------------------
1 | # For building with the clang-specific flavor of ASAN.
2 | build:clang-asan --client_env=CC=clang-5.0
3 | build:clang-asan --copt -g3
4 | build:clang-asan --copt -fsanitize=address
5 | build:clang-asan --linkopt -fsanitize=address
6 | build:clang-asan --copt -fno-omit-frame-pointer
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bazel-*
2 | .bazelrc
3 | build
4 | .vs
5 | .vscode
6 |
--------------------------------------------------------------------------------
/BUILD.bazel:
--------------------------------------------------------------------------------
1 | # Copyright 2018 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | licenses(["notice"])
16 |
17 | cc_library(
18 | name = "api",
19 | hdrs = ["include/astc-codec/astc-codec.h"],
20 | visibility = ["//src/decoder:__pkg__"],
21 | )
22 |
23 | cc_library(
24 | name = "astc_codec",
25 | hdrs = ["include/astc-codec/astc-codec.h"],
26 | includes = ["include"],
27 | visibility = ["//visibility:public"],
28 | deps = ["//src/decoder:codec"],
29 | )
30 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright 2018 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 | # use this file except in compliance with the License. You may obtain a copy of
5 | # the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations under
13 | # the License.
14 | cmake_minimum_required(VERSION 3.1.0)
15 | project(astc-codec)
16 |
17 | option(OPTION_ASTC_TESTS "Build all the unit tests." ON)
18 |
19 | # TODO add support for the fuzzer, it has some additional dependencies we are not
20 | # yet bringing in.
21 | option(OPTION_BUILD_FUZZER "Build the fuzzer tests." OFF)
22 |
23 | set (CMAKE_CXX_STANDARD 11)
24 | if(OPTION_ASTC_TESTS)
25 | enable_testing()
26 |
27 | # No need to build gmock if an external project defines it.
28 | if(NOT TARGET gmock_main)
29 | # We use the approach suggested by https://crascit.com/2015/07/25/cmake-gtest/ to download gtest.
30 | include(ExternalProject)
31 | # Download and unpack googletest at configure time
32 | configure_file(GoogleTest-CMakeLists.txt.in googletest-download/CMakeLists.txt)
33 | execute_process(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" .
34 | WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/googletest-download")
35 | execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/googletest-download")
36 |
37 | # Prevent GoogleTest from overriding our compiler/linker options when building with Visual Studio
38 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
39 |
40 | # Add googletest directly to our build. This adds the following targets: gtest, gtest_main, gmock and gmock_main
41 | add_subdirectory("${CMAKE_BINARY_DIR}/googletest-src" "${CMAKE_BINARY_DIR}/googletest-build")
42 | endif()
43 | endif()
44 |
45 | add_subdirectory(src/base)
46 | add_subdirectory(src/decoder)
47 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to Contribute
2 |
3 | We'd love to accept your patches and contributions to this project. There are
4 | just a few small guidelines you need to follow.
5 |
6 | ## Contributor License Agreement
7 |
8 | Contributions to this project must be accompanied by a Contributor License
9 | Agreement. You (or your employer) retain the copyright to your contribution;
10 | this simply gives us permission to use and redistribute your contributions as
11 | part of the project. Head over to to see
12 | your current agreements on file or to sign a new one.
13 |
14 | You generally only need to submit a CLA once, so if you've already submitted one
15 | (even if it was for a different project), you probably don't need to do it
16 | again.
17 |
18 | ## Code reviews
19 |
20 | All submissions, including submissions by project members, require review. We
21 | use GitHub pull requests for this purpose. Consult
22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
23 | information on using pull requests.
24 |
25 | ## Community Guidelines
26 |
27 | This project follows [Google's Open Source Community
28 | Guidelines](https://opensource.google.com/conduct/).
29 |
--------------------------------------------------------------------------------
/GoogleTest-CMakeLists.txt.in:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.2)
2 |
3 | project(googletest-download NONE)
4 |
5 | include(ExternalProject)
6 | ExternalProject_Add(googletest
7 | GIT_REPOSITORY https://github.com/google/googletest.git
8 | GIT_TAG "release-1.8.1"
9 | SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src"
10 | BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build"
11 | CONFIGURE_COMMAND ""
12 | BUILD_COMMAND ""
13 | INSTALL_COMMAND ""
14 | TEST_COMMAND ""
15 | )
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # astc-codec
2 |
3 | astc-codec is a software ASTC decoder implementation, which supports the ASTC
4 | LDR profile.
5 |
6 | Example usage:
7 |
8 | ```
9 | #include
10 |
11 | // ...
12 |
13 | std::vector astc = LoadMyASTCData();
14 | const size_t width = 640;
15 | const size_t height = 480;
16 |
17 | std::vector result;
18 | result.resize(width * height * 4);
19 |
20 | bool success = astc_codec::ASTCDecompressToRGBA(
21 | astc.data(), astc.size(), width, height, astc_codec::FootprintType::k4x4,
22 | result.data(), result.size(), /* stride */ width * 4);
23 | ```
24 |
25 | ## Building
26 |
27 | ### With bazel
28 |
29 | Install [Bazel](https://bazel.build/), and then run:
30 |
31 | ```
32 | bazel build :astc_codec -c opt
33 | ```
34 |
35 | astc-codec has been tested on Mac and Linux.
36 |
37 | ### Run Tests
38 |
39 | ```
40 | bazel test //...
41 | ```
42 |
43 | ### With CMake
44 |
45 | Install [CMake](https://cmake.org/), and the run:
46 |
47 | ```
48 | mkdir build && cd build && cmake .. && make
49 | ```
50 |
51 | Or open the project in your favorite IDE and import CMakeLists.txt.
52 |
53 | ### Run Tests
54 |
55 | In the build directory, execute:
56 |
57 | ```
58 | ctest
59 | ```
60 |
61 |
62 | ## Contributing
63 |
64 | See [CONTRIBUTING.md](CONTRIBUTING.md) for important contributing requirements.
65 |
66 | ## License
67 |
68 | astc-codec project is licensed under the Apache License Version 2.0. You can
69 | find a copy of it in [LICENSE](LICENSE).
70 |
71 | This is not an officially supported Google product.
72 |
--------------------------------------------------------------------------------
/WORKSPACE:
--------------------------------------------------------------------------------
1 | # Copyright 2018 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
16 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
17 |
18 | git_repository(
19 | name = "gtest",
20 | remote = "https://github.com/google/googletest.git",
21 | commit = "ba96d0b1161f540656efdaed035b3c062b60e006",
22 | )
23 |
24 | http_archive(
25 | name = "honggfuzz",
26 | url = "https://github.com/google/honggfuzz/archive/1.7.zip",
27 | sha256 = "9d420326979fed4a065fa6176d5e09bd513cd2820fe216ae8b684aa6780d72b2",
28 | build_file = "//third_party:honggfuzz.BUILD",
29 | strip_prefix = "honggfuzz-1.7",
30 | )
31 |
32 | http_archive(
33 | name = "benchmark",
34 | url = "https://github.com/google/benchmark/archive/v1.4.1.zip",
35 | sha256 = "61ae07eb5d4a0b02753419eb17a82b7d322786bb36ab62bd3df331a4d47c00a7",
36 | strip_prefix = "benchmark-1.4.1",
37 | )
38 |
--------------------------------------------------------------------------------
/cmake-format.json:
--------------------------------------------------------------------------------
1 | {
2 | "line_width": 120,
3 | "dangle_parens": false,
4 | "first_comment_is_literal": true,
5 | "algorithm_order": [
6 | 0,
7 | 1,
8 | 2,
9 | 3
10 | ],
11 | "command_case": "lower",
12 | "additional_commands": {
13 | "foo": {
14 | "flags": [
15 | "BAR",
16 | "BAZ"
17 | ],
18 | "kwargs": {
19 | "HEADERS": "*",
20 | "DEPENDS": "*",
21 | "SOURCES": "*"
22 | }
23 | }
24 | },
25 | "separate_fn_name_with_space": false,
26 | "always_wrap": [],
27 | "separate_ctrl_name_with_space": false,
28 | "max_subargs_per_line": 5,
29 | "fence_pattern": "^\\s*([`~]{3}[`~]*)(.*)$",
30 | "enable_markup": true,
31 | "ruler_pattern": "^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$",
32 | "tab_size": 2,
33 | "keyword_case": "unchanged",
34 | "enum_char": ".",
35 | "literal_comment_pattern": null,
36 | "bullet_char": "*",
37 | "line_ending": "unix"
38 | }
39 |
--------------------------------------------------------------------------------
/include/astc-codec/astc-codec.h:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef ASTC_CODEC_ASTC_CODEC_H_
16 | #define ASTC_CODEC_ASTC_CODEC_H_
17 |
18 | #include
19 | #include
20 |
21 | namespace astc_codec {
22 |
23 | // These are the valid ASTC footprints according to the specification in
24 | // Section C.2.7.
25 | enum class FootprintType {
26 | k4x4,
27 | k5x4,
28 | k5x5,
29 | k6x5,
30 | k6x6,
31 | k8x5,
32 | k8x6,
33 | k10x5,
34 | k10x6,
35 | k8x8,
36 | k10x8,
37 | k10x10,
38 | k12x10,
39 | k12x12,
40 |
41 | kCount
42 | };
43 |
44 | // Decompresses ASTC LDR image data to a RGBA32 buffer.
45 | //
46 | // Supports formats defined in the KHR_texture_compression_astc_ldr spec and
47 | // returns UNORM8 values. sRGB is not supported, and should be implemented
48 | // by the caller.
49 | //
50 | // |astc_data| - Compressed ASTC image buffer, must be at least |astc_data_size|
51 | // bytes long.
52 | // |astc_data_size| - The size of |astc_data|, in bytes.
53 | // |width| - Image width, in pixels.
54 | // |height| - Image height, in pixels.
55 | // |footprint| - The ASTC footprint (block size) of the compressed image buffer.
56 | // |out_buffer| - Pointer to a buffer where the decompressed image will be
57 | // stored, must be at least |out_buffer_size| bytes long.
58 | // |out_buffer_size| - The size of |out_buffer|, in bytes, at least
59 | // height*out_buffer_stride. If this is too small, this
60 | // function will return false and no data will be
61 | // decompressed.
62 | // |out_buffer_stride| - The stride that should be used to store rows of the
63 | // decoded image, must be at least 4*width bytes.
64 | //
65 | // Returns true if the decompression succeeded, or false if decompression
66 | // failed, or if the astc_data_size was too small for the given width, height,
67 | // and footprint, or if out_buffer_size is too small.
68 | bool ASTCDecompressToRGBA(const uint8_t* astc_data, size_t astc_data_size,
69 | size_t width, size_t height, FootprintType footprint,
70 | uint8_t* out_buffer, size_t out_buffer_size,
71 | size_t out_buffer_stride);
72 |
73 | } // namespace astc_codec
74 |
75 | #endif // ASTC_CODEC_ASTC_CODEC_H_
76 |
--------------------------------------------------------------------------------
/src/.clang-format:
--------------------------------------------------------------------------------
1 | BasedOnStyle: Google
2 | AllowShortCaseLabelsOnASingleLine: true
3 | AllowShortFunctionsOnASingleLine: Inline
4 | SpaceAfterTemplateKeyword: false
5 |
--------------------------------------------------------------------------------
/src/base/BUILD.bazel:
--------------------------------------------------------------------------------
1 | # Copyright 2018 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | licenses(["notice"])
16 |
17 | cc_library(
18 | name = "base",
19 | hdrs = [
20 | "bit_stream.h",
21 | "bottom_n.h",
22 | "math_utils.h",
23 | "optional.h",
24 | "string_utils.h",
25 | "type_traits.h",
26 | "uint128.h",
27 | "utils.h",
28 | ],
29 | features = ["-parse_headers"],
30 | visibility = ["//src/decoder:__pkg__"],
31 | )
32 |
33 | cc_test(
34 | name = "base_test",
35 | srcs = [
36 | "test/bit_stream_test.cpp",
37 | "test/bottom_n_test.cpp",
38 | "test/math_utils_test.cpp",
39 | "test/optional_test.cpp",
40 | "test/string_utils_test.cpp",
41 | "test/type_traits_test.cpp",
42 | "test/uint128_test.cpp",
43 | ],
44 | deps = [
45 | "@gtest//:gtest_main",
46 | ":base",
47 | ],
48 | )
49 |
50 |
--------------------------------------------------------------------------------
/src/base/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright 2018 Google LLC
2 | #
3 | # Licensed under the Apache License Version 2.0 (the License); you may not use
4 | # this file except in compliance with the License. You may obtain a copy of the
5 | # License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing software distributed
10 | # under the License is distributed on an AS IS BASIS WITHOUT WARRANTIES OR
11 | # CONDITIONS OF ANY KIND either express or implied. See the License for the
12 | # specific language governing permissions and limitations under the License.
13 | add_library(base INTERFACE)
14 | target_include_directories(base INTERFACE ../..)
15 |
16 | if(OPTION_ASTC_TESTS)
17 | add_executable(base_test
18 | test/bit_stream_test.cpp
19 | test/bottom_n_test.cpp
20 | test/math_utils_test.cpp
21 | test/optional_test.cpp
22 | test/string_utils_test.cpp
23 | test/type_traits_test.cpp
24 | test/uint128_test.cpp)
25 | target_link_libraries(base_test base gmock_main)
26 | add_test(NAME base_test COMMAND base_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
27 | endif()
28 |
--------------------------------------------------------------------------------
/src/base/bit_stream.h:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef ASTC_CODEC_BASE_BIT_STREAM_H_
16 | #define ASTC_CODEC_BASE_BIT_STREAM_H_
17 |
18 | #include
19 | #include
20 |
21 | namespace astc_codec {
22 | namespace base {
23 |
24 | // Represents a stream of bits that can be read or written in arbitrary-sized
25 | // chunks.
26 | template
27 | class BitStream {
28 | public:
29 | // Creates an empty BitStream.
30 | BitStream() = default;
31 | BitStream(IntType data, uint32_t data_size)
32 | : data_(data), data_size_(data_size) {
33 | assert(data_size_ <= sizeof(data_) * 8);
34 | }
35 |
36 | // Return the number of bits in the stream.
37 | uint32_t Bits() const { return data_size_; }
38 |
39 | // Put |size| bits into the stream.
40 | // Fails if there is not enough space in the buffer to store the bits.
41 | template
42 | void PutBits(ResultType x, uint32_t size) {
43 | assert(data_size_ + size <= sizeof(data_) * 8);
44 |
45 | data_ |= (IntType(x) & MaskFor(size)) << data_size_;
46 | data_size_ += size;
47 | }
48 |
49 | // Get |count| bits from the stream.
50 | // Returns true if |count| bits were successfully retrieved.
51 | template
52 | bool GetBits(uint32_t count, ResultType* result) {
53 | if (count <= data_size_) {
54 | *result = static_cast(data_ & MaskFor(count));
55 | data_ = data_ >> count;
56 | data_size_ -= count;
57 | return true;
58 | } else {
59 | *result = ResultType();
60 | return false;
61 | }
62 | }
63 |
64 | private:
65 | IntType MaskFor(uint32_t bits) const {
66 | return (bits == sizeof(IntType) * 8) ? ~IntType(0)
67 | : (IntType(1) << bits) - 1;
68 | }
69 |
70 | IntType data_ = IntType();
71 | uint32_t data_size_ = 0;
72 | };
73 |
74 | } // namespace base
75 | } // namespace astc_codec
76 |
77 | #endif // ASTC_CODEC_BASE_BIT_STREAM_H_
78 |
--------------------------------------------------------------------------------
/src/base/bottom_n.h:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef ASTC_CODEC_BASE_BOTTOM_N_H_
16 | #define ASTC_CODEC_BASE_BOTTOM_N_H_
17 |
18 | #include
19 | #include
20 | #include
21 |
22 | namespace astc_codec {
23 | namespace base {
24 |
25 | // Used to aggregate the lowest N values of data supplied.
26 | template>
27 | class BottomN {
28 | public:
29 | typedef std::vector ContainerType;
30 |
31 | // Creates an empty BottomN with limit |max_size|.
32 | BottomN(size_t max_size) : max_size_(max_size) { }
33 |
34 | bool Empty() const { return data_.empty(); }
35 | size_t Size() const { return data_.size(); }
36 |
37 | const T& Top() const { return data_.front(); }
38 |
39 | void Push(const T& value) {
40 | if (data_.size() < max_size_ || compare_(value, Top())) {
41 | data_.push_back(value);
42 | std::push_heap(data_.begin(), data_.end(), compare_);
43 |
44 | if (Size() > max_size_) {
45 | PopTop();
46 | }
47 | }
48 | }
49 |
50 | std::vector Pop() {
51 | const size_t len = Size();
52 | std::vector result(len);
53 |
54 | for (size_t i = 0; i < len; ++i) {
55 | result[len - i - 1] = PopTop();
56 | }
57 |
58 | return result;
59 | }
60 |
61 | private:
62 | T PopTop() {
63 | std::pop_heap(data_.begin(), data_.end(), compare_);
64 | T result = data_.back();
65 | data_.pop_back();
66 | return result;
67 | }
68 |
69 | ContainerType data_;
70 | CompareFn compare_;
71 |
72 | const size_t max_size_;
73 | };
74 |
75 | } // namespace base
76 | } // namespace astc_codec
77 |
78 | #endif // ASTC_CODEC_BASE_BOTTOM_N_H_
79 |
--------------------------------------------------------------------------------
/src/base/math_utils.h:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef ASTC_CODEC_BASE_MATH_UTILS_H_
16 | #define ASTC_CODEC_BASE_MATH_UTILS_H_
17 |
18 | #include "src/base/uint128.h"
19 |
20 | #include
21 | #include
22 | #include
23 |
24 | namespace astc_codec {
25 | namespace base {
26 |
27 | inline int Log2Floor(uint32_t n) {
28 | if (n == 0) {
29 | return -1;
30 | }
31 |
32 | int log = 0;
33 | uint32_t value = n;
34 | for (int i = 4; i >= 0; --i) {
35 | int shift = (1 << i);
36 | uint32_t x = value >> shift;
37 | if (x != 0) {
38 | value = x;
39 | log += shift;
40 | }
41 | }
42 | assert(value == 1);
43 | return log;
44 | }
45 |
46 | inline int CountOnes(uint32_t n) {
47 | n -= ((n >> 1) & 0x55555555);
48 | n = ((n >> 2) & 0x33333333) + (n & 0x33333333);
49 | return static_cast((((n + (n >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24);
50 | }
51 |
52 | template
53 | inline T ReverseBits(T value) {
54 | uint32_t s = sizeof(value) * 8;
55 | T mask = ~T(0);
56 | while ((s >>= 1) > 0) {
57 | mask ^= (mask << s);
58 | value = ((value >> s) & mask) | ((value << s) & ~mask);
59 | }
60 |
61 | return value;
62 | }
63 |
64 | template
65 | inline T GetBits(T source, uint32_t offset, uint32_t count) {
66 | static_assert(std::is_same::value || std::is_unsigned::value,
67 | "T must be unsigned.");
68 |
69 | const uint32_t total_bits = sizeof(T) * 8;
70 | assert(count > 0);
71 | assert(offset + count <= total_bits);
72 |
73 | const T mask = count == total_bits ? ~T(0) : ~T(0) >> (total_bits - count);
74 | return (source >> offset) & mask;
75 | }
76 |
77 | } // namespace base
78 | } // namespace astc_codec
79 |
80 | #endif // ASTC_CODEC_BASE_MATH_UTILS_H_
81 |
--------------------------------------------------------------------------------
/src/base/string_utils.h:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef ASTC_CODEC_BASE_STRING_UTILS_H_
16 | #define ASTC_CODEC_BASE_STRING_UTILS_H_
17 |
18 | #include
19 | #include
20 |
21 | namespace astc_codec {
22 | namespace base {
23 |
24 | // Iterates over a string's parts using |splitBy| as a delimiter.
25 | // |splitBy| must be a nonempty string well, or it's a no-op.
26 | // Otherwise, |func| is called on each of the splits, excluding the
27 | // characters that are part of |splitBy|. If two |splitBy|'s occur in a row,
28 | // |func| will be called on a StringView("") in between. See
29 | // StringUtils_unittest.cpp for the full story.
30 | template
31 | void Split(const std::string& str, const std::string& splitBy, Func func) {
32 | if (splitBy.empty()) {
33 | return;
34 | }
35 |
36 | size_t splitSize = splitBy.size();
37 | size_t begin = 0;
38 | size_t end = str.find(splitBy);
39 |
40 | while (true) {
41 | func(str.substr(begin, end - begin));
42 | if (end == std::string::npos) {
43 | return;
44 | }
45 |
46 | begin = end + splitSize;
47 | end = str.find(splitBy, begin);
48 | }
49 | }
50 |
51 | static int32_t ParseInt32(const char* str, int32_t deflt) {
52 | using std::numeric_limits;
53 |
54 | char* error = nullptr;
55 | int64_t value = strtol(str, &error, 0);
56 | // Limit long values to int32 min/max. Needed for lp64; no-op on 32 bits.
57 | if (value > std::numeric_limits::max()) {
58 | value = std::numeric_limits::max();
59 | } else if (value < std::numeric_limits::min()) {
60 | value = std::numeric_limits::min();
61 | }
62 | return (error == str) ? deflt : static_cast(value);
63 | }
64 |
65 | } // namespace base
66 | } // namespace astc_codec
67 |
68 | #endif // ASTC_CODEC_BASE_STRING_UTILS_H_
69 |
--------------------------------------------------------------------------------
/src/base/test/bit_stream_test.cpp:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #include "src/base/bit_stream.h"
16 |
17 | #include
18 |
19 | namespace astc_codec {
20 | namespace base {
21 |
22 | namespace {
23 | static constexpr uint64_t kAllBits = 0xFFFFFFFFFFFFFFFF;
24 | static constexpr uint64_t k40Bits = 0x000000FFFFFFFFFF;
25 | }
26 |
27 | TEST(BitStream, Decode) {
28 | {
29 | BitStream stream(0, 1);
30 |
31 | uint64_t bits = kAllBits;
32 | EXPECT_TRUE(stream.GetBits(1, &bits));
33 | EXPECT_EQ(bits, 0);
34 | EXPECT_FALSE(stream.GetBits(1, &bits));
35 | }
36 |
37 | {
38 | BitStream stream(0b1010101010101010, 32);
39 | EXPECT_EQ(stream.Bits(), 32);
40 |
41 | uint64_t bits = 0;
42 | EXPECT_TRUE(stream.GetBits(1, &bits));
43 | EXPECT_EQ(bits, 0);
44 |
45 | EXPECT_TRUE(stream.GetBits(3, &bits));
46 | EXPECT_EQ(bits, 0b101);
47 |
48 | EXPECT_TRUE(stream.GetBits(8, &bits));
49 | EXPECT_EQ(bits, 0b10101010);
50 |
51 | EXPECT_EQ(stream.Bits(), 20);
52 |
53 | EXPECT_TRUE(stream.GetBits(20, &bits));
54 | EXPECT_EQ(bits, 0b1010);
55 | EXPECT_EQ(stream.Bits(), 0);
56 | }
57 |
58 | {
59 | BitStream stream(kAllBits, 64);
60 | EXPECT_EQ(stream.Bits(), 64);
61 |
62 | uint64_t bits = 0;
63 | EXPECT_TRUE(stream.GetBits(64, &bits));
64 | EXPECT_EQ(bits, kAllBits);
65 | EXPECT_EQ(stream.Bits(), 0);
66 | }
67 |
68 | {
69 | BitStream stream(kAllBits, 64);
70 | EXPECT_EQ(stream.Bits(), 64);
71 |
72 | uint64_t bits = 0;
73 | EXPECT_TRUE(stream.GetBits(40, &bits));
74 | EXPECT_EQ(bits, k40Bits);
75 | EXPECT_EQ(stream.Bits(), 24);
76 | }
77 |
78 | {
79 | BitStream stream(kAllBits, 32);
80 |
81 | uint64_t bits = 0;
82 | EXPECT_TRUE(stream.GetBits(0, &bits));
83 | EXPECT_EQ(bits, 0);
84 | EXPECT_TRUE(stream.GetBits(32, &bits));
85 | EXPECT_EQ(bits, k40Bits & 0xFFFFFFFF);
86 | EXPECT_TRUE(stream.GetBits(0, &bits));
87 | EXPECT_EQ(bits, 0);
88 | EXPECT_EQ(stream.Bits(), 0);
89 | }
90 | }
91 |
92 | TEST(BitStream, Encode) {
93 | {
94 | BitStream stream;
95 |
96 | stream.PutBits(0, 1);
97 | stream.PutBits(0b11, 2);
98 | EXPECT_EQ(stream.Bits(), 3);
99 |
100 | uint64_t bits = 0;
101 | EXPECT_TRUE(stream.GetBits(3, &bits));
102 | EXPECT_EQ(bits, 0b110);
103 | }
104 |
105 | {
106 | BitStream stream;
107 |
108 | uint64_t bits = 0;
109 | stream.PutBits(kAllBits, 64);
110 | EXPECT_EQ(stream.Bits(), 64);
111 |
112 | EXPECT_TRUE(stream.GetBits(64, &bits));
113 | EXPECT_EQ(bits, kAllBits);
114 | EXPECT_EQ(stream.Bits(), 0);
115 | }
116 |
117 | {
118 | BitStream stream;
119 | stream.PutBits(kAllBits, 40);
120 |
121 | uint64_t bits = 0;
122 | EXPECT_TRUE(stream.GetBits(40, &bits));
123 | EXPECT_EQ(bits, k40Bits);
124 | EXPECT_EQ(stream.Bits(), 0);
125 | }
126 |
127 | {
128 | BitStream stream;
129 | stream.PutBits(0, 0);
130 | stream.PutBits(kAllBits, 32);
131 | stream.PutBits(0, 0);
132 |
133 | uint64_t bits = 0;
134 | EXPECT_TRUE(stream.GetBits(32, &bits));
135 | EXPECT_EQ(bits, k40Bits & 0xFFFFFFFF);
136 | EXPECT_EQ(stream.Bits(), 0);
137 | }
138 | }
139 |
140 | } // namespace base
141 | } // namespace astc_codec
142 |
--------------------------------------------------------------------------------
/src/base/test/bottom_n_test.cpp:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #include "src/base/bottom_n.h"
16 |
17 | #include
18 | #include
19 |
20 | namespace astc_codec {
21 | namespace base {
22 |
23 | using ::testing::ElementsAre;
24 |
25 | template
26 | static void pushAll(BottomN& heap, const T (&arr)[N]) {
27 | for (auto i : arr) {
28 | heap.Push(i);
29 | }
30 | }
31 |
32 | TEST(BottomN, Sort) {
33 | {
34 | BottomN heap(10);
35 | EXPECT_TRUE(heap.Empty());
36 | int list[] = { 1,2 };
37 | pushAll(heap, list);
38 |
39 | EXPECT_EQ(heap.Size(), 2);
40 | EXPECT_FALSE(heap.Empty());
41 | EXPECT_THAT(heap.Pop(), ElementsAre(1, 2));
42 | }
43 |
44 | {
45 | BottomN heap(6);
46 | int list[] = {1, 4, 3, 2, 2, 1};
47 | pushAll(heap, list);
48 |
49 | EXPECT_EQ(heap.Size(), 6);
50 | EXPECT_THAT(heap.Pop(), ElementsAre(1, 1, 2, 2, 3, 4));
51 | }
52 | }
53 |
54 | TEST(BottomN, Bounds) {
55 | {
56 | BottomN heap(4);
57 | int list[] = { 1, 2, 3, 4 };
58 | pushAll(heap, list);
59 | EXPECT_EQ(heap.Size(), 4);
60 |
61 | heap.Push(0);
62 | EXPECT_EQ(heap.Size(), 4);
63 |
64 | EXPECT_THAT(heap.Pop(), ElementsAre(0, 1, 2, 3));
65 | }
66 |
67 | {
68 | BottomN heap(4);
69 | int list[] = { 4, 3, 2,1 };
70 | pushAll(heap, list);
71 | EXPECT_EQ(heap.Size(), 4);
72 |
73 | int list2[] = { 4,4,4,4 };
74 | pushAll(heap, list2);
75 | EXPECT_EQ(heap.Size(), 4);
76 |
77 | EXPECT_THAT(heap.Pop(), ElementsAre(1, 2, 3, 4));
78 | }
79 |
80 | {
81 | BottomN heap(4);
82 | int list[] = { 4, 3, 2, 1 };
83 | pushAll(heap, list);
84 | EXPECT_EQ(heap.Size(), 4);
85 |
86 | int list2[] = { 5, 5, 5, 5 };
87 | pushAll(heap, list2);
88 | EXPECT_EQ(heap.Size(), 4);
89 |
90 | EXPECT_THAT(heap.Pop(), ElementsAre(1, 2, 3, 4));
91 | }
92 |
93 | {
94 | BottomN heap(4);
95 | int list[] = { 4, 3, 2, 1 };
96 | pushAll(heap, list);
97 | EXPECT_EQ(heap.Size(), 4);
98 |
99 | int list2[] = { 0, 0, 0, 0 };
100 | pushAll(heap, list2);
101 | EXPECT_EQ(heap.Size(), 4);
102 |
103 | EXPECT_THAT(heap.Pop(), ElementsAre(0, 0, 0, 0));
104 | }
105 | }
106 |
107 | } // namespace base
108 | } // namespace astc_codec
109 |
--------------------------------------------------------------------------------
/src/base/test/math_utils_test.cpp:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #include "src/base/math_utils.h"
16 |
17 | #include
18 |
19 | namespace astc_codec {
20 | namespace base {
21 |
22 | TEST(MathUtils, Log2Floor) {
23 | EXPECT_EQ(-1, Log2Floor(0));
24 |
25 | for (int i = 0; i < 32; i++) {
26 | uint32_t n = 1U << i;
27 | EXPECT_EQ(i, Log2Floor(n));
28 | if (n > 2) {
29 | EXPECT_EQ(i - 1, Log2Floor(n - 1));
30 | EXPECT_EQ(i, Log2Floor(n + 1));
31 | }
32 | }
33 | }
34 |
35 | TEST(MathUtils, CountOnes) {
36 | EXPECT_EQ(0, CountOnes(0));
37 | EXPECT_EQ(1, CountOnes(1));
38 | EXPECT_EQ(32, CountOnes(static_cast(~0U)));
39 | EXPECT_EQ(1, CountOnes(0x8000000));
40 |
41 | for (int i = 0; i < 32; i++) {
42 | EXPECT_EQ(1, CountOnes(1U << i));
43 | EXPECT_EQ(31, CountOnes(static_cast(~0U) ^ (1U << i)));
44 | }
45 | }
46 |
47 | TEST(MathUtils, ReverseBits) {
48 | EXPECT_EQ(ReverseBits(0u), 0u);
49 | EXPECT_EQ(ReverseBits(1u), 1u << 31);
50 | EXPECT_EQ(ReverseBits(0xffffffff), 0xffffffff);
51 | EXPECT_EQ(ReverseBits(0x00000001), 0x80000000);
52 | EXPECT_EQ(ReverseBits(0x80000000), 0x00000001);
53 | EXPECT_EQ(ReverseBits(0xaaaaaaaa), 0x55555555);
54 | EXPECT_EQ(ReverseBits(0x55555555), 0xaaaaaaaa);
55 | EXPECT_EQ(ReverseBits(0x7d5d7f53), 0xcafebabe);
56 | EXPECT_EQ(ReverseBits(0xcafebabe), 0x7d5d7f53);
57 | }
58 |
59 | TEST(MathUtils, GetBits) {
60 | EXPECT_EQ(GetBits(0u, 0, 1), 0u);
61 | EXPECT_EQ(GetBits(0u, 0, 32), 0u);
62 | EXPECT_EQ(GetBits(0x00000001u, 0, 1), 0x00000001);
63 | EXPECT_EQ(GetBits(0x00000001u, 0, 32), 0x00000001);
64 | EXPECT_EQ(GetBits(0x00000001u, 1, 31), 0x00000000);
65 | EXPECT_EQ(GetBits(0x00000001u, 31, 1), 0x00000000);
66 |
67 | EXPECT_DEBUG_DEATH(GetBits(0x00000000u, 1, 32), "");
68 | EXPECT_DEBUG_DEATH(GetBits(0x00000000u, 32, 0), "");
69 | EXPECT_DEBUG_DEATH(GetBits(0x00000000u, 32, 1), "");
70 |
71 | EXPECT_EQ(GetBits(0XFFFFFFFFu, 0, 4), 0x0000000F);
72 | EXPECT_EQ(GetBits(0XFFFFFFFFu, 16, 16), 0xFFFF);
73 | EXPECT_EQ(GetBits(0x80000000u, 31, 1), 1);
74 | EXPECT_EQ(GetBits(0xCAFEBABEu, 24, 8), 0xCA);
75 | }
76 |
77 | } // namespace base
78 | } // namespace astc_codec
79 |
--------------------------------------------------------------------------------
/src/base/test/string_utils_test.cpp:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #include "src/base/string_utils.h"
16 |
17 | #include
18 |
19 | #include
20 | #include
21 | #include
22 |
23 | namespace astc_codec {
24 | namespace base {
25 |
26 | TEST(StringUtils, Split) {
27 | std::vector results;
28 |
29 | auto testFunc = [&results](std::string&& s) {
30 | results.push_back(std::move(s));
31 | };
32 |
33 | Split("", "abc", testFunc);
34 | EXPECT_EQ(results.size(), 1);
35 |
36 | Split("abc", "", testFunc);
37 | EXPECT_EQ(results.size(), 1);
38 |
39 | results.clear();
40 | Split("abc", "a", testFunc);
41 | EXPECT_EQ(results.size(), 2);
42 | EXPECT_EQ(results[0], "");
43 | EXPECT_EQ(results[1], "bc");
44 |
45 | results.clear();
46 | Split("aaa", "a", testFunc);
47 | EXPECT_EQ(4, results.size());
48 | EXPECT_EQ("", results[0]);
49 | EXPECT_EQ("", results[1]);
50 | EXPECT_EQ("", results[2]);
51 | EXPECT_EQ("", results[3]);
52 |
53 | results.clear();
54 | Split("1a2a3a4", "a", testFunc);
55 | EXPECT_EQ(4, results.size());
56 | EXPECT_EQ("1", results[0]);
57 | EXPECT_EQ("2", results[1]);
58 | EXPECT_EQ("3", results[2]);
59 | EXPECT_EQ("4", results[3]);
60 |
61 | results.clear();
62 | Split("1a2aa3a4", "a", testFunc);
63 | EXPECT_EQ(5, results.size());
64 | EXPECT_EQ("1", results[0]);
65 | EXPECT_EQ("2", results[1]);
66 | EXPECT_EQ("", results[2]);
67 | EXPECT_EQ("3", results[3]);
68 | EXPECT_EQ("4", results[4]);
69 |
70 | results.clear();
71 | Split("The quick brown fox jumped over the lazy dog",
72 | " ", testFunc);
73 | EXPECT_EQ(9, results.size());
74 | EXPECT_EQ("The", results[0]);
75 | EXPECT_EQ("quick", results[1]);
76 | EXPECT_EQ("brown", results[2]);
77 | EXPECT_EQ("fox", results[3]);
78 | EXPECT_EQ("jumped", results[4]);
79 | EXPECT_EQ("over", results[5]);
80 | EXPECT_EQ("the", results[6]);
81 | EXPECT_EQ("lazy", results[7]);
82 | EXPECT_EQ("dog", results[8]);
83 |
84 | results.clear();
85 | Split("a; b; c; d", "; ", testFunc);
86 | EXPECT_EQ(4, results.size());
87 | EXPECT_EQ("a", results[0]);
88 | EXPECT_EQ("b", results[1]);
89 | EXPECT_EQ("c", results[2]);
90 | EXPECT_EQ("d", results[3]);
91 | }
92 |
93 | TEST(StringUtils, ParseInt32) {
94 | EXPECT_EQ(ParseInt32("0", -1), 0);
95 | EXPECT_EQ(ParseInt32("100", -1), 100);
96 | EXPECT_EQ(ParseInt32("-100", -1), -100);
97 |
98 | EXPECT_EQ(ParseInt32("", -1), -1);
99 | EXPECT_EQ(ParseInt32("a", -1), -1);
100 | EXPECT_EQ(ParseInt32("10x1", -1), 10);
101 |
102 | EXPECT_EQ(ParseInt32("2147483647", -1), 2147483647);
103 | EXPECT_EQ(ParseInt32("2147483648", -1), 2147483647);
104 |
105 | EXPECT_EQ(ParseInt32("-2147483648", -1), -2147483648);
106 | EXPECT_EQ(ParseInt32("-2147483649", -1), -2147483648);
107 | }
108 |
109 | } // namespace base
110 | } // namespace astc_codec
111 |
--------------------------------------------------------------------------------
/src/base/test/type_traits_test.cpp:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #include "src/base/type_traits.h"
16 |
17 | #include
18 |
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | namespace astc_codec {
25 | namespace base {
26 |
27 | TEST(TypeTraits, IsCallable) {
28 | class C;
29 | C* c = nullptr;
30 |
31 | auto lambda = [c](bool) -> C* { return nullptr; };
32 |
33 | static_assert(is_callable_as::value, "simple function");
34 | static_assert(is_callable_as::value,
35 | "function reference");
36 | static_assert(is_callable_as::value, "function pointer");
37 | static_assert(is_callable_as::value,
38 | "function with arguments and return type");
39 | static_assert(is_callable_as::value, "lambda");
40 | static_assert(is_callable_as, bool(int)>::value,
41 | "std::function");
42 |
43 | static_assert(!is_callable_as::value,
44 | "int should not be callable");
45 | static_assert(!is_callable_as::value, "incomplete type");
46 | static_assert(!is_callable_as::value,
47 | "different arguments");
48 | static_assert(!is_callable_as::value,
49 | "different return types");
50 | static_assert(!is_callable_as::value,
51 | "slightly different return types");
52 | static_assert(!is_callable_as::value,
53 | "more arguments");
54 | static_assert(!is_callable_as::value,
55 | "less arguments");
56 |
57 | static_assert(!is_callable_as::value,
58 | "bad required signature");
59 |
60 | static_assert(is_callable_with_args::value,
61 | "simple function");
62 | static_assert(is_callable_with_args::value,
63 | "function reference");
64 | static_assert(is_callable_with_args::value,
65 | "function pointer");
66 | static_assert(is_callable_with_args::value,
67 | "function with arguments and return type");
68 | static_assert(is_callable_with_args::value,
69 | "lambda");
70 | static_assert(
71 | is_callable_with_args, bool(int)>::value,
72 | "std::function");
73 |
74 | static_assert(!is_callable_with_args::value,
75 | "int should not be callable");
76 | static_assert(!is_callable_with_args::value, "incomplete type");
77 | static_assert(!is_callable_with_args::value,
78 | "different arguments");
79 | static_assert(is_callable_with_args::value,
80 | "different return types are ignored");
81 | static_assert(is_callable_with_args::value,
82 | "slightly different return types are ignored");
83 | static_assert(!is_callable_with_args::value,
84 | "more arguments");
85 | static_assert(!is_callable_with_args::value,
86 | "less arguments");
87 |
88 | static_assert(!is_callable_with_args::value,
89 | "bad required signature");
90 | }
91 |
92 | TEST(TypeTraits, IsTemplateInstantiation) {
93 | static_assert(!is_template_instantiation_of::value,
94 | "int is not an instance of vector");
95 | static_assert(!is_template_instantiation_of>,
96 | std::vector>::value,
97 | "list is not an instance of vector");
98 |
99 | static_assert(
100 | is_template_instantiation_of, std::vector>::value,
101 | "std::vector is an instance of vector");
102 | static_assert(
103 | is_template_instantiation_of>>,
104 | std::vector>::value,
105 | "nested std::vector<> is an instance of vector");
106 | }
107 |
108 | #ifndef _MSC_VER
109 | TEST(TypeTraits, IsRange) {
110 | static_assert(is_range>::value,
111 | "vector<> should be detected as a range");
112 | static_assert(is_range>>::value,
113 | "const list<> should be detected as a range");
114 | static_assert(is_range, 10>>::value,
115 | "array<> should be detected as a range");
116 | char arr[100];
117 | static_assert(is_range::value,
118 | "C array should be detected as a range");
119 | static_assert(is_range::value,
120 | "String literal should be detected as a range");
121 |
122 | static_assert(!is_range::value, "int shouldn't be a range");
123 | static_assert(!is_range::value, "int* shouldn't be a range");
124 | static_assert(!is_range::value,
125 | "even const int* shouldn't be a range");
126 | }
127 | #endif
128 |
129 | } // namespace base
130 | } // namespace astc_codec
131 |
--------------------------------------------------------------------------------
/src/base/test/uint128_test.cpp:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #include "src/base/uint128.h"
16 |
17 | #include
18 |
19 | namespace astc_codec {
20 | namespace base {
21 |
22 | TEST(UInt128, Equality) {
23 | const UInt128 zero(0);
24 | const UInt128 max64(~0ULL);
25 |
26 | EXPECT_EQ(zero, zero);
27 | EXPECT_NE(zero, max64);
28 | EXPECT_EQ(zero, UInt128(0));
29 | EXPECT_NE(zero, UInt128(1));
30 | EXPECT_EQ(max64, max64);
31 | }
32 |
33 | TEST(UInt128, Shifting) {
34 | const UInt128 max64(~0ULL);
35 | const UInt128 upper64(~0ULL, 0);
36 | EXPECT_EQ(upper64.HighBits(), ~0ULL);
37 | EXPECT_EQ(upper64.LowBits(), 0);
38 |
39 | EXPECT_EQ(upper64 >> 64, max64);
40 |
41 | EXPECT_EQ(UInt128(1) << 1, UInt128(2));
42 | EXPECT_EQ(UInt128(0) << 0, UInt128(0));
43 | EXPECT_EQ(max64 << 0, max64);
44 | EXPECT_EQ(max64 >> 0, max64);
45 | EXPECT_EQ(upper64 << 0, upper64);
46 | EXPECT_EQ(upper64 >> 0, upper64);
47 |
48 | {
49 | const UInt128 bit63 = UInt128(1ULL << 62) << 1;
50 | EXPECT_EQ(bit63.LowBits(), 1ULL << 63);
51 | EXPECT_EQ(bit63.HighBits(), 0);
52 | }
53 |
54 | {
55 | const UInt128 bit64 = UInt128(1ULL << 63) << 1;
56 | EXPECT_EQ(bit64.LowBits(), 0);
57 | EXPECT_EQ(bit64.HighBits(), 1);
58 | EXPECT_EQ(bit64 >> 1, UInt128(1ULL << 63));
59 | }
60 |
61 | {
62 | const UInt128 overshift = max64 << 128;
63 | EXPECT_EQ(overshift.HighBits(), 0);
64 | EXPECT_EQ(overshift.LowBits(), 0);
65 | }
66 |
67 | {
68 | const UInt128 overlap = upper64 >> 32;
69 | EXPECT_EQ(overlap.HighBits(), 0x00000000FFFFFFFF);
70 | EXPECT_EQ(overlap.LowBits(), 0xFFFFFFFF00000000);
71 | }
72 |
73 | {
74 | const UInt128 overlap = max64 << 32;
75 | EXPECT_EQ(overlap.HighBits(), 0x00000000FFFFFFFF);
76 | EXPECT_EQ(overlap.LowBits(), 0xFFFFFFFF00000000);
77 | }
78 | }
79 |
80 | TEST(UInt128, LargeShift) {
81 | const UInt128 base(0xFF);
82 | EXPECT_EQ(base << 64, UInt128(0xFFULL, 0));
83 | EXPECT_EQ(base << 72, UInt128(0xFF00ULL, 0));
84 | EXPECT_EQ(base << 80, UInt128(0xFF0000ULL, 0));
85 | EXPECT_EQ(base << 88, UInt128(0xFF000000ULL, 0));
86 | EXPECT_EQ(base << 96, UInt128(0xFF00000000ULL, 0));
87 | EXPECT_EQ(base << 104, UInt128(0xFF0000000000ULL, 0));
88 | EXPECT_EQ(base << 112, UInt128(0xFF000000000000ULL, 0));
89 | EXPECT_EQ(base << 120, UInt128(0xFF00000000000000ULL, 0));
90 |
91 | const UInt128 upper(0xFF00000000000000ULL, 0);
92 | EXPECT_EQ(upper >> 64, UInt128(0, 0xFF00000000000000ULL));
93 | EXPECT_EQ(upper >> 72, UInt128(0, 0xFF000000000000ULL));
94 | EXPECT_EQ(upper >> 80, UInt128(0, 0xFF0000000000ULL));
95 | EXPECT_EQ(upper >> 88, UInt128(0, 0xFF00000000ULL));
96 | EXPECT_EQ(upper >> 96, UInt128(0, 0xFF000000ULL));
97 | EXPECT_EQ(upper >> 104, UInt128(0, 0xFF0000ULL));
98 | EXPECT_EQ(upper >> 112, UInt128(0, 0xFF00ULL));
99 | EXPECT_EQ(upper >> 120, UInt128(0, 0xFFULL));
100 | }
101 |
102 | TEST(UInt128, BooleanOperators) {
103 | const UInt128 allOnes(~0ULL, ~0ULL);
104 | EXPECT_EQ(allOnes.HighBits(), ~0ULL);
105 | EXPECT_EQ(allOnes.LowBits(), ~0ULL);
106 |
107 | EXPECT_EQ(~allOnes, UInt128(0));
108 | EXPECT_EQ(~UInt128(0), allOnes);
109 |
110 | EXPECT_EQ(UInt128(0xFFFF00) & UInt128(0x00FFFF), UInt128(0x00FF00));
111 | EXPECT_EQ(UInt128(0xFFFF00) | UInt128(0x00FFFF), UInt128(0xFFFFFF));
112 | EXPECT_EQ(UInt128(0xFFFF00) ^ UInt128(0x00FFFF), UInt128(0xFF00FF));
113 | }
114 |
115 | TEST(UInt128, Addition) {
116 | const UInt128 bit63(1ULL << 63);
117 |
118 | EXPECT_EQ(UInt128(1) + 1, UInt128(2));
119 | EXPECT_EQ(bit63 + bit63, UInt128(1) << 64);
120 |
121 | const UInt128 carryUp = UInt128(~0ULL) + 1;
122 | EXPECT_EQ(carryUp.HighBits(), 1);
123 | EXPECT_EQ(carryUp.LowBits(), 0);
124 |
125 | const UInt128 allOnes(~0ULL, ~0ULL);
126 | EXPECT_EQ(allOnes + 1, UInt128(0));
127 | }
128 |
129 | TEST(UInt128, Subtraction) {
130 | const UInt128 bit64 = UInt128(1) << 64;
131 | EXPECT_EQ(bit64 - 1, UInt128(~0ULL));
132 |
133 | EXPECT_EQ(UInt128(1) - 1, UInt128(0));
134 |
135 | const UInt128 allOnes(~0ULL, ~0ULL);
136 | EXPECT_EQ(UInt128(0) - 1, allOnes);
137 | }
138 |
139 | } // namespace base
140 | } // namespace astc_codec
141 |
--------------------------------------------------------------------------------
/src/base/type_traits.h:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef ASTC_CODEC_BASE_TYPE_TRAITS_H_
16 | #define ASTC_CODEC_BASE_TYPE_TRAITS_H_
17 |
18 | #include
19 | #include
20 |
21 | namespace astc_codec {
22 | namespace base {
23 |
24 | namespace details {
25 |
26 | // a simple helper class for SFINAE below.
27 | template
28 | struct dummy {
29 | using type = X;
30 | };
31 |
32 | } // namespace details
33 |
34 | // add some convenience shortcuts for an overly complex std::enable_if syntax
35 |
36 | // Use 'enable_if' instead of
37 | // 'typename std::enable_if::type'
38 | template
39 | using enable_if = typename std::enable_if::type;
40 |
41 | // Use 'enable_if_c' instead of
42 | // 'typename std::enable_if::type'
43 | template
44 | using enable_if_c = typename std::enable_if::type;
45 |
46 | // Use 'enable_if_convertible' instead of
47 | // 'typename std::enable_if::value, Type>::type'
48 | template
49 | using enable_if_convertible = enable_if>;
50 |
51 | // -----------------------------------------------------------------------------
52 | // A predicate for checking if some object is callable with a specific
53 | // signature. Examples:
54 | //
55 | // is_callable_as::value == false.
56 | // is_callable_as::value == false.
57 | // is_callable_as::value == true
58 | //
59 | template
60 | struct is_callable_as : std::false_type {};
61 |
62 | // This specialization is SFINAE-d out if template arguments can't be combined
63 | // into a call expression F(), or if the result of that call is not |R|
64 | template
65 | struct is_callable_as()(
68 | std::declval()...))>::type,
69 | R>::value>::type> : std::true_type {};
70 |
71 | //
72 | // A similar predicate to only check arguments of the function call and ignore
73 | // the specified return type
74 | //
75 | // is_callable_as::value == true
76 | // is_callable_as::value == false
77 | // is_callable_with_args::value == true
78 | //
79 | template
80 | struct is_callable_with_args : std::false_type {};
81 |
82 | template
83 | struct is_callable_with_args<
84 | F, R(Args...),
85 | typename std::enable_if<
86 | !std::is_same()(std::declval()...))>::type,
88 | F>::value>::type> : std::true_type {};
89 |
90 | // -----------------------------------------------------------------------------
91 | // Check if a type |T| is any instantiation of a template |U|. Examples:
92 | //
93 | // is_template_instantiation_of::value == false
94 | // is_template_instantiation_of<
95 | // std::list>, std::vector>::value == false
96 | // is_template_instantiation_of, std::vector>::value == true
97 | // is_template_instantiation_of<
98 | // std::vector>, std::vector>::value == true
99 | //
100 | template class U>
101 | struct is_template_instantiation_of : std::false_type {};
102 |
103 | template class U, class... Args>
104 | struct is_template_instantiation_of, U> : std::true_type {};
105 | // -----------------------------------------------------------------------------
106 |
107 | //
108 | // is_range - check if type |T| is a range-like type.
109 | //
110 | // It makes sure that expressions std::begin(t) and std::end(t) are well-formed
111 | // and those return the same type.
112 | //
113 | // Note: with expression SFINAE from C++14 is_range_helper<> could be renamed to
114 | // is_range<> with no extra code. C++11 needs an extra level of enable_if<>
115 | // to make it work when the type isn't a range.
116 | //
117 |
118 | namespace details {
119 |
120 | template
121 | using is_range_helper = std::is_same<
122 | decltype(std::begin(
123 | std::declval::type>())),
124 | decltype(
125 | std::end(std::declval::type>()))>;
126 |
127 | } // namespace details
128 |
129 | template
130 | struct is_range : std::false_type {};
131 |
132 | template
133 | struct is_range<
134 | T, typename std::enable_if::value>::type>
135 | : std::true_type {};
136 |
137 | ////////////////////////////////////////////////////////////////////////////////
138 | //
139 | // A class to incapsulate integer sequence 0, 1, ...,
140 | // Seq
141 | // Useful to pass function parameters in an array/tuple to call it later.
142 | //
143 |
144 | template
145 | struct Seq {};
146 |
147 | // A 'maker' class to construct Seq given only
148 | // value.
149 | // MakeSeq works this way, e.g.
150 | //
151 | // MakeSeq<2> inherits MakeSeq<2 - 1, 2 - 1> == MakeSeq<1, 1>
152 | // MakeSeq<1, 1> : MakeSeq<1 - 1, 1 - 1, 1> == MakeSeq<0, 0, 1>
153 | // MakeSeq<0, 0, 1> == MakeSeq<0, S...> and defines |type| = Seq<0, 1>
154 |
155 | template
156 | struct MakeSeq : MakeSeq {};
157 |
158 | template
159 | struct MakeSeq<0, S...> {
160 | using type = Seq;
161 | };
162 |
163 | //
164 | // MakeSeqT alias to quickly create Seq<...>:
165 | // MakeSeqT<3> == Seq<0, 1, 2>
166 | template
167 | using MakeSeqT = typename MakeSeq::type;
168 |
169 | } // namespace base
170 | } // namespace astc_codec
171 |
172 | #endif // ASTC_CODEC_BASE_TYPE_TRAITS_H_
173 |
--------------------------------------------------------------------------------
/src/base/uint128.h:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef ASTC_CODEC_BASE_UINT128_H_
16 | #define ASTC_CODEC_BASE_UINT128_H_
17 |
18 | #include
19 | #include
20 |
21 | namespace astc_codec {
22 | namespace base {
23 |
24 | class UInt128 {
25 | public:
26 | UInt128() = default;
27 | UInt128(uint64_t low) : low_(low) { }
28 | UInt128(uint64_t high, uint64_t low) : low_(low), high_(high) { }
29 | UInt128(const UInt128& other) : low_(other.low_), high_(other.high_) { }
30 |
31 | uint64_t LowBits() const { return low_; }
32 | uint64_t HighBits() const { return high_; }
33 |
34 | // Allow explicit casts to uint64_t.
35 | explicit operator uint64_t() const { return low_; }
36 |
37 | // Copy operators.
38 | UInt128& operator=(const UInt128& other) {
39 | high_ = other.high_;
40 | low_ = other.low_;
41 | return *this;
42 | }
43 |
44 | // Equality operators.
45 | bool operator==(const UInt128& other) const {
46 | return high_ == other.high_ && low_ == other.low_;
47 | }
48 |
49 | bool operator!=(const UInt128& other) const {
50 | return high_ != other.high_ || low_ != other.low_;
51 | }
52 |
53 | // Shifting.
54 | UInt128& operator<<=(int shift) {
55 | high_ = shift >= 64 ? (shift >= 128 ? 0 : low_ << (shift - 64))
56 | : high_ << shift;
57 |
58 | if (shift > 0 && shift < 64) {
59 | const uint64_t overlappingBits = low_ >> (64 - shift);
60 | high_ |= overlappingBits;
61 | }
62 |
63 | low_ = shift >= 64 ? 0 : low_ << shift;
64 | return *this;
65 | }
66 |
67 | UInt128 operator<<(int shift) const {
68 | UInt128 result = *this;
69 | result <<= shift;
70 | return result;
71 | }
72 |
73 | UInt128& operator>>=(int shift) {
74 | low_ = shift >= 64 ? (shift >= 128 ? 0 : high_ >> (shift - 64))
75 | : low_ >> shift;
76 |
77 | if (shift > 0 && shift < 64) {
78 | const uint64_t overlappingBits = high_ << (64 - shift);
79 | low_ |= overlappingBits;
80 | }
81 |
82 | high_ = shift >= 64 ? 0 : high_ >> shift;
83 |
84 | return *this;
85 | }
86 |
87 | UInt128 operator>>(int shift) const {
88 | UInt128 result = *this;
89 | result >>= shift;
90 | return result;
91 | }
92 |
93 | // Binary operations.
94 | UInt128& operator|=(const UInt128& other) {
95 | high_ |= other.high_;
96 | low_ |= other.low_;
97 | return *this;
98 | }
99 |
100 | UInt128 operator|(const UInt128& other) const {
101 | UInt128 result = *this;
102 | result |= other;
103 | return result;
104 | }
105 |
106 | UInt128& operator&=(const UInt128& other) {
107 | high_ &= other.high_;
108 | low_ &= other.low_;
109 | return *this;
110 | }
111 |
112 | UInt128 operator&(const UInt128& other) const {
113 | UInt128 result = *this;
114 | result &= other;
115 | return result;
116 | }
117 |
118 | UInt128& operator^=(const UInt128& other) {
119 | high_ ^= other.high_;
120 | low_ ^= other.low_;
121 | return *this;
122 | }
123 |
124 | UInt128 operator^(const UInt128& other) const {
125 | UInt128 result = *this;
126 | result ^= other;
127 | return result;
128 | }
129 |
130 | UInt128 operator~() const {
131 | UInt128 result = *this;
132 | result.high_ = ~high_;
133 | result.low_ = ~low_;
134 | return result;
135 | }
136 |
137 | // Addition/subtraction.
138 | UInt128& operator+=(const UInt128& other) {
139 | const uint64_t carry =
140 | (((low_ & other.low_) & 1) + (low_ >> 1) + (other.low_ >> 1)) >> 63;
141 | high_ += other.high_ + carry;
142 | low_ += other.low_;
143 | return *this;
144 | }
145 |
146 | UInt128 operator+(const UInt128& other) const {
147 | UInt128 result = *this;
148 | result += other;
149 | return result;
150 | }
151 |
152 | UInt128& operator-=(const UInt128& other) {
153 | low_ -= other.low_;
154 | const uint64_t carry =
155 | (((low_ & other.low_) & 1) + (low_ >> 1) + (other.low_ >> 1)) >> 63;
156 | high_ -= other.high_ + carry;
157 | return *this;
158 | }
159 |
160 | UInt128 operator-(const UInt128& other) const {
161 | UInt128 result = *this;
162 | result -= other;
163 | return result;
164 | }
165 |
166 | private:
167 | // TODO(google): Different order for little endian.
168 | uint64_t low_ = 0;
169 | uint64_t high_ = 0;
170 | };
171 |
172 | } // namespace base
173 | } // namespace astc_codec
174 |
175 | #endif // ASTC_CODEC_BASE_UINT128_H_
176 |
--------------------------------------------------------------------------------
/src/base/utils.h:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef ASTC_CODEC_BASE_UTILS_H_
16 | #define ASTC_CODEC_BASE_UTILS_H_
17 |
18 | #include
19 | #include
20 | #include
21 |
22 | #ifdef NDEBUG
23 | #define UTILS_RELEASE_ASSERT(x) \
24 | do { \
25 | const bool result = (x); \
26 | if (!result) { \
27 | fprintf(stderr, "Error: UTILS_RELEASE_ASSERT failed: %s\n", #x); \
28 | abort(); \
29 | } \
30 | } while (false)
31 | #else
32 | #define UTILS_RELEASE_ASSERT(x) assert(x)
33 | #endif
34 |
35 | // In C++11, `assert` can't be used portably within constexpr functions.
36 | // ASTC_CONSTEXPR_ASSERT functions as a runtime assert but works in C++11
37 | // constexpr functions. Example:
38 | //
39 | // constexpr double Divide(double a, double b) {
40 | // return ASTC_CONSTEXPR_ASSERT(b != 0), a / b;
41 | // }
42 | //
43 | // This macro is based on ABSL_ASSERT.
44 | #ifdef NDEBUG
45 | #define ASTC_CONSTEXPR_ASSERT(expr) \
46 | (false ? static_cast(expr) : static_cast(0))
47 | #else
48 | #define ASTC_CONSTEXPR_ASSERT(expr) \
49 | ((expr) ? static_cast(0) : [] { assert(false && #expr); }())
50 | #endif
51 |
52 | #endif // ASTC_CODEC_BASE_UTILS_H_
53 |
--------------------------------------------------------------------------------
/src/decoder/BUILD.bazel:
--------------------------------------------------------------------------------
1 | # Copyright 2018 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | licenses(["notice"])
16 |
17 | cc_library(
18 | name = "footprint",
19 | srcs = ["footprint.cc"],
20 | hdrs = ["footprint.h"],
21 | deps = [
22 | "//:api",
23 | "//src/base",
24 | ],
25 | )
26 |
27 | cc_library(
28 | name = "astc_utils",
29 | srcs = [
30 | "astc_file.cc",
31 | "endpoint_codec.cc",
32 | "integer_sequence_codec.cc",
33 | "intermediate_astc_block.cc",
34 | "logical_astc_block.cc",
35 | "partition.cc",
36 | "physical_astc_block.cc",
37 | "quantization.cc",
38 | "weight_infill.cc",
39 | ],
40 | hdrs = [
41 | "astc_file.h",
42 | "endpoint_codec.h",
43 | "integer_sequence_codec.h",
44 | "intermediate_astc_block.h",
45 | "logical_astc_block.h",
46 | "partition.h",
47 | "physical_astc_block.h",
48 | "quantization.h",
49 | "types.h",
50 | "weight_infill.h",
51 | ],
52 | copts = [
53 | "-Wno-unused-variable",
54 | "-O3",
55 | ],
56 | deps = [
57 | ":footprint",
58 | "//src/base",
59 | ],
60 | )
61 |
62 | cc_library(
63 | name = "codec",
64 | srcs = ["codec.cc"],
65 | hdrs = ["codec.h"],
66 | visibility = ["//:__pkg__"],
67 | deps = [
68 | ":astc_utils",
69 | ":footprint",
70 | "//src/base",
71 | ],
72 | )
73 |
74 | cc_binary(
75 | name = "astc_inspector_cli",
76 | srcs = ["tools/astc_inspector_cli.cc"],
77 | deps = [
78 | ":astc_utils",
79 | "//src/base",
80 | ],
81 | )
82 |
83 | ################################################################################
84 | ##
85 | ## Testing
86 | ##
87 | ################################################################################
88 |
89 | cc_library(
90 | name = "test",
91 | testonly = 1,
92 | hdrs = ["test/image_utils.h"],
93 | deps = ["@gtest//:gtest"],
94 | )
95 |
96 | cc_test(
97 | name = "physical_astc_block_test",
98 | size = "small",
99 | srcs = ["test/physical_astc_block_test.cc"],
100 | deps = [
101 | ":astc_utils",
102 | "@gtest//:gtest_main",
103 | "//src/base",
104 | ],
105 | )
106 |
107 | cc_test(
108 | name = "partition_test",
109 | size = "medium",
110 | srcs = ["test/partition_test.cc"],
111 | deps = [
112 | ":astc_utils",
113 | "@gtest//:gtest_main",
114 | ],
115 | )
116 |
117 | cc_test(
118 | name = "integer_sequence_codec_test",
119 | size = "small",
120 | srcs = ["test/integer_sequence_codec_test.cc"],
121 | deps = [
122 | ":astc_utils",
123 | "@gtest//:gtest_main",
124 | "//src/base",
125 | ],
126 | )
127 |
128 | cc_test(
129 | name = "intermediate_astc_block_test",
130 | size = "small",
131 | srcs = ["test/intermediate_astc_block_test.cc"],
132 | data = glob([
133 | "testdata/checkered_*.astc",
134 | ]),
135 | deps = [
136 | ":astc_utils",
137 | ":test",
138 | "@gtest//:gtest_main",
139 | ],
140 | )
141 |
142 | cc_test(
143 | name = "quantization_test",
144 | size = "medium",
145 | srcs = ["test/quantization_test.cc"],
146 | deps = [
147 | ":astc_utils",
148 | "@gtest//:gtest_main",
149 | ],
150 | )
151 |
152 | cc_test(
153 | name = "weight_infill_test",
154 | size = "small",
155 | srcs = ["test/weight_infill_test.cc"],
156 | deps = [
157 | ":astc_utils",
158 | ":footprint",
159 | "@gtest//:gtest_main",
160 | ],
161 | )
162 |
163 | cc_test(
164 | name = "endpoint_codec_test",
165 | size = "small",
166 | srcs = ["test/endpoint_codec_test.cc"],
167 | data = [
168 | ":testdata/checkerboard.astc",
169 | ],
170 | deps = [
171 | ":astc_utils",
172 | ":test",
173 | "@gtest//:gtest_main",
174 | ],
175 | )
176 |
177 | cc_test(
178 | name = "logical_astc_block_test",
179 | size = "large",
180 | srcs = ["test/logical_astc_block_test.cc"],
181 | data = glob([
182 | "testdata/atlas_small_*.astc",
183 | "testdata/atlas_small_*.bmp",
184 | "testdata/footprint_*.astc",
185 | "testdata/footprint_*.bmp",
186 | "testdata/rgb_*.astc",
187 | "testdata/rgb_*.bmp",
188 | ]),
189 | deps = [
190 | ":astc_utils",
191 | ":test",
192 | "@gtest//:gtest_main",
193 | ],
194 | )
195 |
196 | cc_test(
197 | name = "codec_test",
198 | size = "large",
199 | srcs = ["test/codec_test.cc"],
200 | data = glob([
201 | "testdata/atlas_small_*.astc",
202 | "testdata/atlas_small_*.bmp",
203 | ]),
204 | deps = [
205 | ":codec",
206 | ":test",
207 | "@gtest//:gtest_main",
208 | "//:api",
209 | ],
210 | )
211 |
212 | cc_test(
213 | name = "footprint_test",
214 | size = "small",
215 | srcs = ["test/footprint_test.cc"],
216 | deps = [
217 | ":footprint",
218 | "@gtest//:gtest_main",
219 | ],
220 | )
221 |
222 | cc_test(
223 | name = "astc_fuzzer",
224 | srcs = ["test/astc_fuzzer.cc"],
225 | copts = select({
226 | # Clang-only flags. TODO: Find a better way to detect GCC/clang.
227 | "@bazel_tools//src/conditions:darwin_x86_64": [
228 | "-fsanitize-coverage=trace-pc-guard,indirect-calls,trace-cmp",
229 | "-fsanitize-coverage=bb",
230 | ],
231 | "@bazel_tools//src/conditions:darwin": [
232 | "-fsanitize-coverage=trace-pc-guard,indirect-calls,trace-cmp",
233 | "-fsanitize-coverage=bb",
234 | ],
235 | # GCC-only flags.
236 | "//conditions:default": [
237 | "-finstrument-functions"
238 | ],
239 | }),
240 | deps = [
241 | ":codec",
242 | "@honggfuzz//:honggfuzz",
243 | "@benchmark//:benchmark",
244 | ],
245 | linkstatic = 1,
246 | )
247 |
--------------------------------------------------------------------------------
/src/decoder/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright 2018 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 | # use this file except in compliance with the License. You may obtain a copy of
5 | # the License at
6 | #
7 | # https://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 | # License for the specific language governing permissions and limitations under
13 | # the License.
14 | add_library(footprint footprint.cc)
15 | target_link_libraries(footprint base)
16 |
17 | add_library(astc_utils
18 | astc_file.cc
19 | endpoint_codec.cc
20 | integer_sequence_codec.cc
21 | intermediate_astc_block.cc
22 | logical_astc_block.cc
23 | partition.cc
24 | physical_astc_block.cc
25 | quantization.cc
26 | weight_infill.cc)
27 | target_link_libraries(astc_utils PRIVATE base footprint)
28 | target_include_directories(astc_utils PRIVATE ../..)
29 |
30 | add_library(astc-codec codec.cc)
31 | target_link_libraries(astc-codec PRIVATE astc_utils)
32 | target_include_directories(astc-codec PUBLIC ../../include)
33 | target_include_directories(astc-codec PRIVATE ../..)
34 |
35 | add_executable(astc_inspector_cli tools/astc_inspector_cli.cc)
36 | target_include_directories(astc_inspector_cli PRIVATE ../..)
37 | target_link_libraries(astc_inspector_cli PRIVATE astc_utils)
38 |
39 | #
40 | # Testing
41 | #
42 | if(OPTION_ASTC_TESTS)
43 | # Note that we will execute all the tests in the project directory.
44 | # We do this to ensure the unit tests can pick up the required test data
45 |
46 | # Create interface library exposing the root as an include directory
47 | add_library(codec_test_dependencies INTERFACE)
48 | target_include_directories(codec_test_dependencies INTERFACE ../..)
49 |
50 | add_executable(physical_astc_block_test test/physical_astc_block_test.cc)
51 | add_test(NAME physical_astc_block_test COMMAND physical_astc_block_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
52 | target_link_libraries(physical_astc_block_test astc_utils codec_test_dependencies gmock_main)
53 |
54 | add_executable(partition_test test/partition_test.cc)
55 | add_test(NAME partition_test COMMAND partition_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
56 | target_link_libraries(partition_test PRIVATE astc_utils codec_test_dependencies gmock_main)
57 |
58 | add_executable(integer_sequence_codec_test test/integer_sequence_codec_test.cc)
59 | target_link_libraries(integer_sequence_codec_test PRIVATE astc_utils codec_test_dependencies gmock_main)
60 |
61 | add_executable(intermediate_astc_block_test test/intermediate_astc_block_test.cc)
62 | add_test(NAME intermediate_astc_block_test COMMAND intermediate_astc_block_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
63 | target_link_libraries(intermediate_astc_block_test PRIVATE astc_utils codec_test_dependencies gmock_main)
64 |
65 | add_executable(quantization_test test/quantization_test.cc)
66 | add_test(NAME quantization_test COMMAND quantization_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
67 | target_link_libraries(quantization_test PRIVATE astc_utils codec_test_dependencies gmock_main)
68 |
69 | add_executable(weight_infill_test test/weight_infill_test.cc)
70 | add_test(NAME weight_infill_test COMMAND weight_infill_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
71 | target_link_libraries(weight_infill_test PRIVATE astc_utils footprint codec_test_dependencies gmock_main)
72 |
73 | add_executable(endpoint_codec_test test/endpoint_codec_test.cc)
74 | add_test(NAME endpoint_codec_test COMMAND endpoint_codec_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
75 | target_link_libraries(endpoint_codec_test PRIVATE astc_utils codec_test_dependencies gmock_main)
76 |
77 | add_executable(logical_astc_block_test test/logical_astc_block_test.cc)
78 | add_test(NAME logical_astc_block_test COMMAND logical_astc_block_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
79 | target_link_libraries(logical_astc_block_test PRIVATE astc_utils codec_test_dependencies gmock_main)
80 |
81 | add_executable(codec_test test/codec_test.cc)
82 | add_test(NAME codec_test COMMAND codec_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
83 |
84 | target_link_libraries(codec_test PRIVATE astc-codec codec_test_dependencies gmock_main)
85 |
86 | add_executable(footprint_test test/footprint_test.cc)
87 | add_test(NAME footprint_test COMMAND footprint_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
88 | target_link_libraries(footprint_test PRIVATE footprint codec_test_dependencies gmock_main)
89 |
90 | if(OPTION_BUILD_FUZZER)
91 | message(FATAL_ERROR "Not yet supported due to missing dependencies")
92 | add_executable(astc_fuzzer test/astc_fuzzer.cc codec_test_dependencies gmock_main)
93 | target_link_libraries(astc_fuzzer PRIVATE astc-codec honggfuzz benchmark)
94 | endif()
95 | endif()
96 |
--------------------------------------------------------------------------------
/src/decoder/astc_file.cc:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #include "src/decoder/astc_file.h"
16 |
17 | #include
18 | #include
19 | #include
20 | #include
21 |
22 | namespace astc_codec {
23 |
24 | namespace {
25 | static constexpr size_t kASTCHeaderSize = 16;
26 |
27 | // Reads a value of size T from the buffer at the current offset, then
28 | // increments the offset.
29 | template
30 | inline T ReadVal(const char* file_data, size_t& offset) {
31 | T x;
32 | memcpy(&x, &file_data[offset], sizeof(T));
33 | offset += sizeof(T);
34 | return x;
35 | }
36 | } // namespace
37 |
38 | ASTCFile::ASTCFile(Header&& header, std::string&& blocks)
39 | : header_(std::move(header)), blocks_(std::move(blocks)) {}
40 |
41 | std::unique_ptr ASTCFile::LoadFromMemory(const char* data,
42 | size_t length,
43 | std::string* error) {
44 | if (length < kASTCHeaderSize) {
45 | *error = "Incomplete header.";
46 | return nullptr;
47 | }
48 |
49 | base::Optional header_opt = ParseHeader(data);
50 | if (!header_opt) {
51 | *error = "Invalid ASTC header.";
52 | return nullptr;
53 | }
54 |
55 | Header header = header_opt.value();
56 |
57 | if (header.block_width_ == 0 || header.block_height_ == 0) {
58 | *error = "Invalid block size.";
59 | return nullptr;
60 | }
61 |
62 | std::string blocks(data + kASTCHeaderSize, data + length);
63 |
64 | // Check that this file has the expected number of blocks.
65 | const size_t expected_block_count =
66 | ((header.width_ + header.block_width_ - 1) / header.block_width_) *
67 | ((header.height_ + header.block_height_ - 1) / header.block_height_);
68 |
69 | if (blocks.size() % PhysicalASTCBlock::kSizeInBytes != 0 ||
70 | blocks.size() / PhysicalASTCBlock::kSizeInBytes != expected_block_count) {
71 | std::stringstream ss;
72 | ss << "Unexpected file length " << blocks.size() << " expected "
73 | << kASTCHeaderSize +
74 | expected_block_count * PhysicalASTCBlock::kSizeInBytes
75 | << " bytes.";
76 | *error = ss.str();
77 | return nullptr;
78 | }
79 |
80 | return std::unique_ptr(
81 | new ASTCFile(std::move(header), std::move(blocks)));
82 | }
83 |
84 | std::unique_ptr ASTCFile::LoadFile(const std::string& path,
85 | std::string* error) {
86 | std::ifstream is(path, std::ios::binary);
87 | if (!is) {
88 | *error = "File not found: " + path;
89 | return nullptr;
90 | }
91 |
92 | char header_data[kASTCHeaderSize] = {};
93 | if (!is.read(header_data, kASTCHeaderSize)) {
94 | *error = "Failed to load ASTC header.";
95 | return nullptr;
96 | }
97 |
98 | base::Optional header_opt = ParseHeader(header_data);
99 | if (!header_opt) {
100 | *error = "Invalid ASTC header.";
101 | return nullptr;
102 | }
103 |
104 | Header header = header_opt.value();
105 |
106 | std::string blocks;
107 | {
108 | std::ostringstream ss;
109 | ss << is.rdbuf();
110 | blocks = ss.str();
111 | }
112 |
113 | // Check that this file has the expected number of blocks.
114 | const size_t expected_block_count =
115 | ((header.width_ + header.block_width_ - 1) / header.block_width_) *
116 | ((header.height_ + header.block_height_ - 1) / header.block_height_);
117 |
118 | if (blocks.size() % PhysicalASTCBlock::kSizeInBytes != 0 ||
119 | blocks.size() / PhysicalASTCBlock::kSizeInBytes != expected_block_count) {
120 | std::stringstream ss;
121 | ss << "Unexpected file length " << blocks.size() << " expected "
122 | << kASTCHeaderSize +
123 | expected_block_count * PhysicalASTCBlock::kSizeInBytes
124 | << " bytes.";
125 | *error = ss.str();
126 | return nullptr;
127 | }
128 |
129 | return std::unique_ptr(
130 | new ASTCFile(std::move(header), std::move(blocks)));
131 | }
132 |
133 | base::Optional ASTCFile::GetFootprint() const {
134 | return Footprint::FromDimensions(header_.block_width_, header_.block_height_);
135 | }
136 |
137 | std::string ASTCFile::GetFootprintString() const {
138 | std::stringstream footprint;
139 | footprint << header_.block_width_ << "x" << header_.block_height_;
140 | return footprint.str();
141 | }
142 |
143 | const std::string& ASTCFile::GetRawBlockData() const {
144 | return blocks_;
145 | }
146 |
147 | PhysicalASTCBlock ASTCFile::GetBlock(size_t block_idx) const {
148 | const size_t sz = PhysicalASTCBlock::kSizeInBytes;
149 | const size_t offset = PhysicalASTCBlock::kSizeInBytes * block_idx;
150 | assert(offset <= blocks_.size() - sz);
151 | return PhysicalASTCBlock(blocks_.substr(offset, sz));
152 | }
153 |
154 | base::Optional ASTCFile::ParseHeader(const char* header) {
155 | size_t offset = 0;
156 | // TODO(google): Handle endianness.
157 | const uint32_t magic = ReadVal(header, offset);
158 | if (magic != 0x5CA1AB13) {
159 | return {};
160 | }
161 |
162 | const uint32_t block_width = ReadVal(header, offset);
163 | const uint32_t block_height = ReadVal(header, offset);
164 | const uint32_t block_depth = ReadVal(header, offset);
165 |
166 | uint32_t width = 0;
167 | width |= ReadVal(header, offset);
168 | width |= ReadVal(header, offset) << 8;
169 | width |= ReadVal(header, offset) << 16;
170 |
171 | uint32_t height = 0;
172 | height |= ReadVal(header, offset);
173 | height |= ReadVal(header, offset) << 8;
174 | height |= ReadVal(header, offset) << 16;
175 |
176 | uint32_t depth = 0;
177 | depth |= ReadVal(header, offset);
178 | depth |= ReadVal(header, offset) << 8;
179 | depth |= ReadVal(header, offset) << 16;
180 | assert(offset == kASTCHeaderSize);
181 |
182 | return Header(width, height, depth, block_width, block_height, block_depth);
183 | }
184 |
185 | } // namespace astc_codec
186 |
--------------------------------------------------------------------------------
/src/decoder/astc_file.h:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef ASTC_CODEC_DECODER_ASTC_FILE_H_
16 | #define ASTC_CODEC_DECODER_ASTC_FILE_H_
17 |
18 | #include "src/base/optional.h"
19 | #include "src/decoder/footprint.h"
20 | #include "src/decoder/physical_astc_block.h"
21 |
22 | #include
23 | #include
24 |
25 | namespace astc_codec {
26 |
27 | // A thin wrapper around a .astc file on disk. This class simply reads the ASTC
28 | // header, and stores the block data in memory.
29 | class ASTCFile {
30 | private:
31 | struct Header {
32 | Header(size_t width, size_t height, size_t depth, size_t block_width,
33 | size_t block_height, size_t block_depth)
34 | : width_(width),
35 | height_(height),
36 | depth_(depth),
37 | block_width_(block_width),
38 | block_height_(block_height),
39 | block_depth_(block_depth) {}
40 |
41 | size_t width_;
42 | size_t height_;
43 | size_t depth_;
44 |
45 | size_t block_width_;
46 | size_t block_height_;
47 | size_t block_depth_;
48 | };
49 |
50 | ASTCFile(ASTCFile::Header&& header, std::string&& blocks);
51 |
52 | public:
53 | // Load an ASTC file from memory.
54 | // If loading failed, nullptr is returned and an error string is populated
55 | // in the error parameter.
56 | static std::unique_ptr LoadFromMemory(const char* data,
57 | size_t length,
58 | std::string* error);
59 |
60 | // Load an ASTC file from file.
61 | // If loading failed, nullptr is returned and an error string is populated
62 | // in the error parameter.
63 | static std::unique_ptr LoadFile(const std::string& path,
64 | std::string* error);
65 |
66 | // Returns the footprint for the file, if it is considered to be a valid
67 | // footprint.
68 | base::Optional GetFootprint() const;
69 |
70 | // Returns the string of the form "NxM" where N and M are the width and height
71 | // of the block footprint, respectively.
72 | std::string GetFootprintString() const;
73 |
74 | // Get the raw block data for the astc file.
75 | const std::string& GetRawBlockData() const;
76 |
77 | // Returns the physical block at the associated block index.
78 | PhysicalASTCBlock GetBlock(size_t block_idx) const;
79 |
80 | size_t GetWidth() const { return header_.width_; }
81 | size_t GetHeight() const { return header_.height_; }
82 | size_t GetDepth() const { return header_.depth_; }
83 |
84 | size_t NumBlocks() const {
85 | return blocks_.size() / PhysicalASTCBlock::kSizeInBytes;
86 | }
87 |
88 | private:
89 | static base::Optional ParseHeader(const char* header);
90 |
91 | const Header header_;
92 | const std::string blocks_;
93 | };
94 |
95 | } // namespace astc_codec
96 |
97 | #endif // ASTC_CODEC_DECODER_ASTC_FILE_H_
98 |
--------------------------------------------------------------------------------
/src/decoder/codec.cc:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #include "src/decoder/codec.h"
16 | #include "src/base/uint128.h"
17 | #include "src/decoder/logical_astc_block.h"
18 | #include "src/decoder/physical_astc_block.h"
19 |
20 | #include
21 |
22 | namespace astc_codec {
23 |
24 | namespace {
25 | static constexpr size_t kBytesPerPixelUNORM8 = 4;
26 | }
27 |
28 | bool DecompressToImage(const uint8_t* astc_data, size_t astc_data_size,
29 | size_t width, size_t height, Footprint footprint,
30 | uint8_t* out_buffer, size_t out_buffer_size,
31 | size_t out_buffer_stride) {
32 | const size_t block_width = footprint.Width();
33 | const size_t block_height = footprint.Height();
34 | assert(block_width != 0);
35 | assert(block_height != 0);
36 |
37 | if (width == 0 || height == 0) {
38 | return false;
39 | }
40 |
41 | const size_t blocks_wide = (width + block_width - 1) / block_width;
42 | assert(blocks_wide != 0);
43 |
44 | // Check that this buffer has the expected number of blocks.
45 | const size_t expected_block_count =
46 | ((width + block_width - 1) / block_width) *
47 | ((height + block_height - 1) / block_height);
48 |
49 | if (astc_data_size % PhysicalASTCBlock::kSizeInBytes != 0 ||
50 | astc_data_size / PhysicalASTCBlock::kSizeInBytes !=
51 | expected_block_count) {
52 | // TODO(google): Expose error?
53 | return false;
54 | }
55 |
56 | if (kBytesPerPixelUNORM8 * width > out_buffer_stride ||
57 | out_buffer_stride * height < out_buffer_size) {
58 | // Output buffer too small.
59 | return false;
60 | }
61 |
62 | base::UInt128 block;
63 | static_assert(sizeof(block) == PhysicalASTCBlock::kSizeInBytes,
64 | "Block size mismatch");
65 |
66 | for (size_t i = 0; i < astc_data_size; i += PhysicalASTCBlock::kSizeInBytes) {
67 | const size_t block_index = i / PhysicalASTCBlock::kSizeInBytes;
68 | const size_t block_x = block_index % blocks_wide;
69 | const size_t block_y = block_index / blocks_wide;
70 | memcpy(&block, astc_data + i, sizeof(block));
71 |
72 | PhysicalASTCBlock physical_block(block);
73 | auto lb = UnpackLogicalBlock(footprint, physical_block);
74 | if (!lb) {
75 | return false;
76 | }
77 |
78 | LogicalASTCBlock logical_block = lb.value();
79 |
80 | for (size_t y = 0; y < block_height; ++y) {
81 | const size_t py = block_height * block_y + y;
82 | uint8_t* out_row = out_buffer + py * out_buffer_stride;
83 |
84 | for (size_t x = 0; x < block_width; ++x) {
85 | const size_t px = block_width * block_x + x;
86 |
87 | // Skip out of bounds.
88 | if (px >= width || py >= height) {
89 | continue;
90 | }
91 |
92 | uint8_t* pixel = out_row + px * kBytesPerPixelUNORM8;
93 | const RgbaColor decoded_color = logical_block.ColorAt(x, y);
94 | for (size_t i = 0; i < kBytesPerPixelUNORM8; ++i) {
95 | pixel[i] = static_cast(decoded_color[i]);
96 | }
97 | }
98 | }
99 | }
100 |
101 | return true;
102 | }
103 |
104 | bool DecompressToImage(const ASTCFile& file, uint8_t* out_buffer,
105 | size_t out_buffer_size, size_t out_buffer_stride) {
106 | base::Optional footprint = file.GetFootprint();
107 | if (!footprint) {
108 | return false;
109 | }
110 |
111 | return DecompressToImage(
112 | reinterpret_cast(file.GetRawBlockData().c_str()),
113 | file.GetRawBlockData().size(), file.GetWidth(), file.GetHeight(),
114 | footprint.value(), out_buffer, out_buffer_size, out_buffer_stride);
115 | }
116 |
117 | bool ASTCDecompressToRGBA(const uint8_t* astc_data, size_t astc_data_size,
118 | size_t width, size_t height, FootprintType footprint,
119 | uint8_t* out_buffer, size_t out_buffer_size,
120 | size_t out_buffer_stride) {
121 | base::Optional footprint_opt =
122 | Footprint::FromFootprintType(footprint);
123 | if (!footprint_opt) {
124 | return false;
125 | }
126 |
127 | return DecompressToImage(astc_data, astc_data_size, width, height,
128 | footprint_opt.value(), out_buffer, out_buffer_size,
129 | out_buffer_stride);
130 | }
131 |
132 | } // namespace astc_codec
133 |
--------------------------------------------------------------------------------
/src/decoder/codec.h:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef ASTC_CODEC_DECODER_CODEC_H_
16 | #define ASTC_CODEC_DECODER_CODEC_H_
17 |
18 | #include "src/decoder/astc_file.h"
19 | #include "src/decoder/footprint.h"
20 |
21 | #include
22 |
23 | namespace astc_codec {
24 |
25 | // Decompresses ASTC blocks to an image buffer.
26 | // Returns true if the decompression succeeded and the out buffer has been
27 | // filled.
28 | bool DecompressToImage(const uint8_t* astc_data, size_t astc_data_size,
29 | size_t width, size_t height, Footprint footprint,
30 | uint8_t* out_buffer, size_t out_buffer_size,
31 | size_t out_buffer_stride);
32 |
33 | // Decompresses an ASTC file to an image buffer.
34 | // Returns true if the decompression succeeded and the out buffer has been
35 | // filled.
36 | bool DecompressToImage(const ASTCFile& file, uint8_t* out_buffer,
37 | size_t out_buffer_size, size_t out_buffer_stride);
38 |
39 | } // namespace astc_codec
40 |
41 | #endif // ASTC_CODEC_DECODER_CODEC_H_
42 |
--------------------------------------------------------------------------------
/src/decoder/endpoint_codec.h:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef ASTC_CODEC_DECODER_ENDPOINT_CODEC_H_
16 | #define ASTC_CODEC_DECODER_ENDPOINT_CODEC_H_
17 |
18 | #include "src/decoder/physical_astc_block.h"
19 | #include "src/decoder/types.h"
20 |
21 | #include
22 | #include
23 |
24 | namespace astc_codec {
25 |
26 | // We use a special distinction for encode modes used to pass to the
27 | // EncodeColorsForMode function below. The reason is that some of the color
28 | // modes have sub-modes (like blue-contract) that change whether or not it is
29 | // useful to encode an endpoint pair using one mode versus another. To avoid
30 | // this problem, we approach the problem of encoding by specifying some
31 | // high-level encoding modes. These eventually choose one of the low level
32 | // ColorEndpointModes from Section C.2.14 when used in EncodeColorsForMode.
33 | enum class EndpointEncodingMode {
34 | kDirectLuma,
35 | kDirectLumaAlpha,
36 | kBaseScaleRGB,
37 | kBaseScaleRGBA,
38 | kDirectRGB,
39 | kDirectRGBA
40 | };
41 |
42 | // Returns the number of values in the encoded endpoint pair after encoding
43 | // to a specific high-level encoding mode.
44 | constexpr int NumValuesForEncodingMode(EndpointEncodingMode mode) {
45 | return
46 | mode == EndpointEncodingMode::kDirectLuma ? 2 :
47 | mode == EndpointEncodingMode::kDirectLumaAlpha ? 4 :
48 | mode == EndpointEncodingMode::kBaseScaleRGB ? 4 :
49 | mode == EndpointEncodingMode::kBaseScaleRGBA ? 6 :
50 | mode == EndpointEncodingMode::kDirectRGB ? 6 : 8;
51 | }
52 |
53 | // Fills |vals| with the quantized endpoint colors values defined in the ASTC
54 | // specification. The values are quantized to the range [0, max_value]. These
55 | // quantization limits can be obtained by querying the associated functions in
56 | // integer_sequence_codec. The returned |astc_mode| will be the ASTC mode used
57 | // to encode the resulting sequence.
58 | //
59 | // The |encoding_mode| is used to determine the way that we encode the values.
60 | // Each encoding mode is used to determine which ASTC mode best corresponds
61 | // to the pair of endpoints. It is a necessary hint to the encoding function
62 | // in order to process the endpoints. Each encoding mode gurantees a certain
63 | // number of values generated per endpoints.
64 | //
65 | // The return value will be true if the endpoints have been switched in order to
66 | // reap the most benefit from the way the hardware decodes the given mode. In
67 | // this case, the associated weights that interpolate this color must also be
68 | // switched. In other words, for each w, it should change to 64 - w.
69 | bool EncodeColorsForMode(
70 | const RgbaColor& endpoint_low_rgba, const RgbaColor& endpoint_high_rgba,
71 | int max_value, EndpointEncodingMode encoding_mode,
72 | ColorEndpointMode* astc_mode, std::vector* vals);
73 |
74 | // Decodes the color values quantized to the range [0, max_value] into RGBA
75 | // endpoints for the given mode. This function is the inverse of
76 | // EncodeColorsForMode -- see that function for details. This function should
77 | // work on all LDR endpoint modes, but no HDR modes.
78 | void DecodeColorsForMode(const std::vector& vals,
79 | int max_value, ColorEndpointMode mode,
80 | RgbaColor* endpoint_low_rgba,
81 | RgbaColor* endpoint_high_rgba);
82 |
83 | // Returns true if the quantized |vals| in the range [0, max_value] use the
84 | // 'blue_contract' modification during decoding for the given |mode|.
85 | bool UsesBlueContract(int max_value, ColorEndpointMode mode,
86 | const std::vector& vals);
87 |
88 | } // namespace astc_codec
89 |
90 | #endif // ASTC_CODEC_DECODER_ENDPOINT_CODEC_H_
91 |
--------------------------------------------------------------------------------
/src/decoder/footprint.cc:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #include "src/decoder/footprint.h"
16 | #include "src/base/string_utils.h"
17 |
18 | #include