This is an automated email from the ASF dual-hosted git repository.
chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory.git
The following commit(s) were added to refs/heads/main by this push:
new 389b66c81 chore: clean up code and add compiler warning checks (#3660)
389b66c81 is described below
commit 389b66c81d197bc7a03129e4dfefde34dd2fcf1d
Author: Shawn Yang <[email protected]>
AuthorDate: Fri May 8 14:43:42 2026 +0800
chore: clean up code and add compiler warning checks (#3660)
## Why?
## What does this PR do?
## Related issues
## AI Contribution Checklist
- [ ] Substantial AI assistance was used in this PR: `yes` / `no`
- [ ] If `yes`, I included a completed [AI Contribution
Checklist](https://github.com/apache/fory/blob/main/AI_POLICY.md#9-contributor-checklist-for-ai-assisted-prs)
in this PR description and the required `AI Usage Disclosure`.
- [ ] If `yes`, my PR description includes the required `ai_review`
summary and screenshot evidence of the final clean AI review results
from both fresh reviewers on the current PR diff or current HEAD after
the latest code changes.
## Does this PR introduce any user-facing change?
- [ ] Does this PR introduce any public API change?
- [ ] Does this PR introduce any binary protocol compatibility change?
## Benchmark
---
.bazelrc | 5 +
.github/workflows/ci.yml | 2 +-
AGENTS.md | 5 +
ci/run_ci.sh | 4 +-
ci/tasks/cpp.py | 19 +-
compiler/README.md | 2 +-
compiler/fory_compiler/generators/dart.py | 12 +-
.../fory_compiler/tests/test_dart_generator.py | 26 ++
cpp/CMakeLists.txt | 43 +++-
cpp/fory/encoder/CMakeLists.txt | 1 +
cpp/fory/meta/CMakeLists.txt | 7 +
cpp/fory/meta/field_info.h | 8 +-
cpp/fory/row/CMakeLists.txt | 2 +
cpp/fory/serialization/CMakeLists.txt | 13 +
cpp/fory/serialization/type_resolver.cc | 4 +-
cpp/fory/serialization/variant_serializer_test.cc | 19 +-
cpp/fory/thirdparty/CMakeLists.txt | 1 +
cpp/fory/util/CMakeLists.txt | 10 +
cpp/fory/util/logging.h | 4 +-
cpp/fory/util/result.h | 57 ++---
dart/README.md | 3 +-
.../fory-test/lib/entity/xlang_test_models.dart | 15 +-
dart/packages/fory/README.md | 24 +-
.../fory/lib/src/codegen/fory_generator.dart | 19 +-
.../fory/lib/src/context/read_context.dart | 6 +-
.../fory/lib/src/context/write_context.dart | 4 +-
.../packages/fory/lib/src/memory/buffer_mixin.dart | 8 +-
.../fory/lib/src/resolver/type_resolver.dart | 16 +-
.../lib/src/serializer/collection_serializers.dart | 4 +-
.../lib/src/serializer/primitive_serializers.dart | 14 +-
dart/packages/fory/lib/src/types/bfloat16.dart | 244 +++++--------------
dart/packages/fory/lib/src/types/float16.dart | 266 ++++++---------------
dart/packages/fory/test/buffer_test.dart | 4 +-
.../scalar_and_typed_array_serializer_test.dart | 136 ++++++-----
dart/packages/fory/test/xlang_protocol_test.dart | 39 +--
docs/compiler/schema-idl.md | 12 +-
docs/guide/dart/cross-language.md | 5 +-
docs/guide/dart/index.md | 4 +-
docs/guide/dart/supported-types.md | 11 +-
docs/guide/java/advanced-features.md | 7 +-
docs/guide/javascript/supported-types.md | 26 +-
docs/guide/xlang/serialization.md | 2 +-
docs/specification/xlang_type_mapping.md | 9 +-
.../idl_tests/dart/test/idl_roundtrip_test.dart | 29 +--
.../idl_tests/javascript/roundtrip.ts | 4 -
.../idl_tests/javascript/test/roundtrip.test.ts | 4 -
.../org/apache/fory/memory/MemoryAllocator.java | 3 +-
.../java/org/apache/fory/memory/MemoryBuffer.java | 6 +-
.../apache/fory/memory/MemoryAllocatorTest.java | 10 +-
javascript/packages/core/index.ts | 3 +-
javascript/packages/core/lib/reader/index.ts | 6 +-
javascript/packages/core/lib/typeInfo.ts | 10 +-
javascript/packages/core/lib/types/bfloat16.ts | 62 ++---
javascript/packages/core/lib/writer/index.ts | 4 +-
javascript/test/number.test.ts | 25 +-
55 files changed, 553 insertions(+), 735 deletions(-)
diff --git a/.bazelrc b/.bazelrc
index 0e67e8f6b..a26b6815b 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -47,6 +47,11 @@ test --build_tests_only
test --cache_test_results=no
test --test_output=all
+# Fory C++ validation config. This is opt-in so downstream Bazel users do not
+# inherit Fory's warning-as-error policy when they consume Fory as source.
+test:fory_cpp_werror --per_file_copt=^cpp/fory/.*@-Werror
+test:fory_cpp_werror_msvc --per_file_copt=^cpp/fory/.*@/WX
+
# Platform-specific C++ options
build:linux --cxxopt="-std=c++17" --linkopt="-pthread"
build:macos --cxxopt="-std=c++17" --linkopt="-pthread"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9acd0c42c..b17b1abc2 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -858,7 +858,7 @@ jobs:
- name: Run C++ ${{ matrix.sanitizer }} tests
run: |
ARCH="$(uname -m)"
- BAZEL_CONFIGS="--config=${{ matrix.sanitizer }}"
+ BAZEL_CONFIGS="--config=fory_cpp_werror --config=${{
matrix.sanitizer }}"
if [[ "${ARCH}" == "x86_64" || "${ARCH}" == "amd64" ]]; then
BAZEL_CONFIGS="--config=x86_64 ${BAZEL_CONFIGS}"
fi
diff --git a/AGENTS.md b/AGENTS.md
index 33ae3be7e..3f7548ecf 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -103,6 +103,11 @@ This is the entry point for AI guidance in Apache Fory.
Read this file first, th
- Preserve protocol compatibility across languages.
- Read and respect `docs/specification/xlang_type_mapping.md` when changing
cross-language type behavior.
- Handle byte order correctly for cross-platform compatibility.
+- When a target language exposes one public integer type for narrower integer
+ widths or one public floating type for reduced-precision floats, use schema
+ metadata or field annotations to carry the exact Fory wire type. Do not add
+ scalar carrier wrappers for `int8`, `int16`, `int32`, `uint8`, `uint16`,
+ `uint32`, `float16`, or `bfloat16`.
- If the reference implementation is not right, do not tweak another
language's correct implementation to align with a wrong reference
implementation just to make tests pass; fix the runtime that diverged from the
spec.
## Git And Review Rules
diff --git a/ci/run_ci.sh b/ci/run_ci.sh
index d2585231b..6318a7448 100755
--- a/ci/run_ci.sh
+++ b/ci/run_ci.sh
@@ -255,10 +255,10 @@ case $1 in
export PATH=~/bin:$PATH
echo "bazel version: $(bazel version)"
ARCH="$(uname -m)"
- BAZEL_TEST_CONFIG=""
+ BAZEL_TEST_CONFIG="--config=fory_cpp_werror"
case "${ARCH}" in
x86_64|amd64)
- BAZEL_TEST_CONFIG="--config=x86_64"
+ BAZEL_TEST_CONFIG="--config=x86_64 ${BAZEL_TEST_CONFIG}"
;;
esac
set +e
diff --git a/ci/tasks/cpp.py b/ci/tasks/cpp.py
index 4f27f7dc3..30d5c2acf 100644
--- a/ci/tasks/cpp.py
+++ b/ci/tasks/cpp.py
@@ -53,10 +53,17 @@ def run_doc_example_tests():
generate_doc_example_tests()
logging.info("Running documentation example tests")
- test_command = "test //cpp/doc_tests:doc_example_tests"
+ common.bazel(f"test {_cpp_test_configs()}
//cpp/doc_tests:doc_example_tests")
+
+
+def _cpp_test_configs():
+ if common.is_windows():
+ configs = ["--config=fory_cpp_werror_msvc"]
+ else:
+ configs = ["--config=fory_cpp_werror"]
if common.get_os_machine() == "x86_64":
- test_command = "test --config=x86_64 //cpp/doc_tests:doc_example_tests"
- common.bazel(test_command)
+ configs.insert(0, "--config=x86_64")
+ return " ".join(configs)
def run(install_deps_only=False, skip_doc_tests=False, doc_tests_only=False):
@@ -83,11 +90,7 @@ def run(install_deps_only=False, skip_doc_tests=False,
doc_tests_only=False):
query_result = common.bazel("query //...")
targets = query_result.replace("\n", " ").replace("\r", " ")
- test_command = "test"
- if common.get_os_machine() == "x86_64":
- test_command += " --config=x86_64"
-
- common.bazel(f"{test_command} {targets}")
+ common.bazel(f"test {_cpp_test_configs()} {targets}")
logging.info("C++ CI tasks completed successfully")
# Run documentation example tests
diff --git a/compiler/README.md b/compiler/README.md
index 3492dc7d2..0205707ee 100644
--- a/compiler/README.md
+++ b/compiler/README.md
@@ -193,7 +193,7 @@ message Config { ... } // Registered as "package.Config"
| `int32` | `int` | `pyfory.Int32` | `int32` | `i32`
| `int32_t` | `int` | `number` |
| `int64` | `long` | `pyfory.Int64` | `int64` | `i64`
| `int64_t` | `long` | `bigint \| number` |
| `float16` | `Float16` | `pyfory.Float16` | `float16` | `Float16`
| `fory::float16_t` | `Half` | `number` |
-| `bfloat16` | `BFloat16` | `pyfory.BFloat16` | `bfloat16` | `BFloat16`
| `fory::bfloat16_t` | `BFloat16` | `BFloat16` |
+| `bfloat16` | `BFloat16` | `pyfory.BFloat16` | `bfloat16` | `BFloat16`
| `fory::bfloat16_t` | `BFloat16` | `number` |
| `float32` | `float` | `pyfory.Float32` | `float32` | `f32`
| `float` | `float` | `number` |
| `float64` | `double` | `pyfory.Float64` | `float64` | `f64`
| `double` | `double` | `number` |
| `string` | `String` | `str` | `string` | `String`
| `std::string` | `string` | `string` |
diff --git a/compiler/fory_compiler/generators/dart.py
b/compiler/fory_compiler/generators/dart.py
index 713b17375..51d09e123 100644
--- a/compiler/fory_compiler/generators/dart.py
+++ b/compiler/fory_compiler/generators/dart.py
@@ -54,8 +54,8 @@ class DartGenerator(BaseGenerator):
PrimitiveKind.UINT16: "int",
PrimitiveKind.UINT32: "int",
PrimitiveKind.UINT64: "Uint64",
- PrimitiveKind.FLOAT16: "Float16",
- PrimitiveKind.BFLOAT16: "Bfloat16",
+ PrimitiveKind.FLOAT16: "double",
+ PrimitiveKind.BFLOAT16: "double",
PrimitiveKind.FLOAT32: "Float32",
PrimitiveKind.FLOAT64: "double",
PrimitiveKind.STRING: "String",
@@ -590,8 +590,8 @@ class DartGenerator(BaseGenerator):
PrimitiveKind.UINT16: "0",
PrimitiveKind.UINT32: "0",
PrimitiveKind.UINT64: "Uint64(0)",
- PrimitiveKind.FLOAT16: "Float16(0)",
- PrimitiveKind.BFLOAT16: "Bfloat16(0)",
+ PrimitiveKind.FLOAT16: "0.0",
+ PrimitiveKind.BFLOAT16: "0.0",
PrimitiveKind.FLOAT32: "Float32(0)",
PrimitiveKind.FLOAT64: "0.0",
PrimitiveKind.STRING: "''",
@@ -1152,8 +1152,8 @@ class DartGenerator(BaseGenerator):
PrimitiveKind.INT16: ("int", "TypeIds.int16"),
PrimitiveKind.UINT8: ("int", "TypeIds.uint8"),
PrimitiveKind.UINT16: ("int", "TypeIds.uint16"),
- PrimitiveKind.FLOAT16: ("Float16", "TypeIds.float16"),
- PrimitiveKind.BFLOAT16: ("Bfloat16", "TypeIds.bfloat16"),
+ PrimitiveKind.FLOAT16: ("double", "TypeIds.float16"),
+ PrimitiveKind.BFLOAT16: ("double", "TypeIds.bfloat16"),
PrimitiveKind.FLOAT32: ("Float32", "TypeIds.float32"),
PrimitiveKind.FLOAT64: ("double", "TypeIds.float64"),
PrimitiveKind.STRING: ("String", "TypeIds.string"),
diff --git a/compiler/fory_compiler/tests/test_dart_generator.py
b/compiler/fory_compiler/tests/test_dart_generator.py
index 423f568ff..821f50163 100644
--- a/compiler/fory_compiler/tests/test_dart_generator.py
+++ b/compiler/fory_compiler/tests/test_dart_generator.py
@@ -164,6 +164,32 @@ def
test_dart_generator_distinguishes_lists_from_dense_arrays():
assert "factory ValueUnion.values(Uint32List value)" in file.content
+def test_dart_generator_uses_double_for_reduced_precision_scalar_carriers():
+ file = generate_dart(
+ """
+ package demo;
+
+ message Holder {
+ float16 half = 1;
+ bfloat16 brain = 2;
+ list<float16> halves = 3;
+ array<bfloat16> brains = 4;
+ }
+ """
+ )
+
+ assert "@ForyField(type: Float16Type(), id: 1)" in file.content
+ assert "double half = 0.0;" in file.content
+ assert "@ForyField(type: Bfloat16Type(), id: 2)" in file.content
+ assert "double brain = 0.0;" in file.content
+ assert "@ForyField(type: ListType(element: Float16Type()), id: 3)" in
file.content
+ assert "List<double> halves = <double>[];" in file.content
+ assert "@ForyField(type: ArrayType(element: Bfloat16Type()), id: 4)" in
file.content
+ assert "Bfloat16List brains = Bfloat16List(0);" in file.content
+ assert "Float16 half" not in file.content
+ assert "Bfloat16 brain" not in file.content
+
+
def test_dart_generator_supports_decimal_fields_and_unions():
file = generate_dart(
"""
diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt
index 98accdba8..43bb1d6e0 100644
--- a/cpp/CMakeLists.txt
+++ b/cpp/CMakeLists.txt
@@ -33,6 +33,7 @@ option(FORY_BUILD_TESTS "Build Fory tests" OFF)
option(FORY_BUILD_SHARED "Build shared libraries" ON)
option(FORY_BUILD_STATIC "Build static libraries" ON)
option(FORY_USE_AVX2 "Enable AVX2 optimizations on x86_64" ON)
+option(FORY_WARNINGS_AS_ERRORS "Treat Fory compiler warnings as errors"
${FORY_BUILD_TESTS})
# Set default build type if not specified
if(NOT CMAKE_BUILD_TYPE)
@@ -51,18 +52,39 @@ else()
set(FORY_IS_X86_64 FALSE)
endif()
-# Compiler flags
-if(MSVC)
- add_compile_options(/W4)
- if(FORY_USE_AVX2 AND FORY_IS_X86_64)
- add_compile_options(/arch:AVX2)
+# Compiler flags for Fory-owned compiled targets. Keep these target-private so
+# Fory warning policy does not leak to consumers or fetched test dependencies.
+function(fory_configure_target target)
+ if(MSVC)
+ target_compile_options(${target} PRIVATE /W4)
+ if(FORY_WARNINGS_AS_ERRORS)
+ target_compile_options(${target} PRIVATE /WX)
+ else()
+ target_compile_options(${target} PRIVATE /WX-)
+ endif()
+ if(FORY_USE_AVX2 AND FORY_IS_X86_64)
+ target_compile_options(${target} PRIVATE /arch:AVX2)
+ endif()
+ else()
+ target_compile_options(${target} PRIVATE -Wall -Wextra -Wpedantic)
+ if(FORY_WARNINGS_AS_ERRORS)
+ target_compile_options(${target} PRIVATE -Werror)
+ else()
+ target_compile_options(${target} PRIVATE -Wno-error)
+ endif()
+ if(FORY_USE_AVX2 AND FORY_IS_X86_64)
+ target_compile_options(${target} PRIVATE -mavx2)
+ endif()
endif()
-else()
- add_compile_options(-Wall -Wextra -Wpedantic)
- if(FORY_USE_AVX2 AND FORY_IS_X86_64)
- add_compile_options(-mavx2)
+endfunction()
+
+function(fory_configure_dependency_target target)
+ if(MSVC)
+ target_compile_options(${target} PRIVATE /WX-)
+ else()
+ target_compile_options(${target} PRIVATE -Wno-error)
endif()
-endif()
+endfunction()
# Set Fory root directory for include paths (important when used as
subdirectory)
set(FORY_CPP_ROOT ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH "Fory C++ root
directory")
@@ -179,5 +201,6 @@ message(STATUS " Build type: ${CMAKE_BUILD_TYPE}")
message(STATUS " C++ standard: ${CMAKE_CXX_STANDARD}")
message(STATUS " Install prefix: ${CMAKE_INSTALL_PREFIX}")
message(STATUS " Build tests: ${FORY_BUILD_TESTS}")
+message(STATUS " Warnings as errors: ${FORY_WARNINGS_AS_ERRORS}")
message(STATUS " AVX2 enabled: ${FORY_USE_AVX2} (x86_64:
${FORY_IS_X86_64})")
message(STATUS "")
diff --git a/cpp/fory/encoder/CMakeLists.txt b/cpp/fory/encoder/CMakeLists.txt
index 2a4f687d2..e72b556d8 100644
--- a/cpp/fory/encoder/CMakeLists.txt
+++ b/cpp/fory/encoder/CMakeLists.txt
@@ -34,6 +34,7 @@ target_link_libraries(fory_encoder
# Tests
if(FORY_BUILD_TESTS)
add_executable(fory_encoder_test row_encoder_test.cc
row_encode_trait_test.cc)
+ fory_configure_target(fory_encoder_test)
target_link_libraries(fory_encoder_test fory_encoder GTest::gtest)
gtest_discover_tests(fory_encoder_test)
endif()
diff --git a/cpp/fory/meta/CMakeLists.txt b/cpp/fory/meta/CMakeLists.txt
index 65707d62d..096978240 100644
--- a/cpp/fory/meta/CMakeLists.txt
+++ b/cpp/fory/meta/CMakeLists.txt
@@ -30,6 +30,7 @@ set(FORY_META_HEADERS
add_library(fory_meta ${FORY_META_SOURCES})
add_library(fory::meta ALIAS fory_meta)
+fory_configure_target(fory_meta)
target_include_directories(fory_meta
PUBLIC
@@ -50,26 +51,32 @@ set_target_properties(fory_meta PROPERTIES
# Tests
if(FORY_BUILD_TESTS)
add_executable(fory_meta_preprocessor_test preprocessor_test.cc)
+ fory_configure_target(fory_meta_preprocessor_test)
target_link_libraries(fory_meta_preprocessor_test fory_meta GTest::gtest)
gtest_discover_tests(fory_meta_preprocessor_test)
add_executable(fory_meta_field_info_test field_info_test.cc)
+ fory_configure_target(fory_meta_field_info_test)
target_link_libraries(fory_meta_field_info_test fory_meta GTest::gtest)
gtest_discover_tests(fory_meta_field_info_test)
add_executable(fory_meta_enum_info_test enum_info_test.cc)
+ fory_configure_target(fory_meta_enum_info_test)
target_link_libraries(fory_meta_enum_info_test fory_meta GTest::gtest)
gtest_discover_tests(fory_meta_enum_info_test)
add_executable(fory_meta_type_traits_test type_traits_test.cc)
+ fory_configure_target(fory_meta_type_traits_test)
target_link_libraries(fory_meta_type_traits_test fory_meta GTest::gtest)
gtest_discover_tests(fory_meta_type_traits_test)
add_executable(fory_meta_string_test meta_string_test.cc)
+ fory_configure_target(fory_meta_string_test)
target_link_libraries(fory_meta_string_test fory_meta GTest::gtest
GTest::gtest_main)
gtest_discover_tests(fory_meta_string_test)
add_executable(fory_meta_field_test field_test.cc)
+ fory_configure_target(fory_meta_field_test)
target_link_libraries(fory_meta_field_test fory_meta GTest::gtest)
gtest_discover_tests(fory_meta_field_test)
endif()
diff --git a/cpp/fory/meta/field_info.h b/cpp/fory/meta/field_info.h
index 2a01cac66..fb3d8285e 100644
--- a/cpp/fory/meta/field_info.h
+++ b/cpp/fory/meta/field_info.h
@@ -366,8 +366,12 @@ constexpr const T &unwrap_tuple(const TupleWrapper<T>
&value) {
// it must be able to be executed in compile-time
template <typename FieldInfo, size_t... I>
constexpr bool is_valid_field_info_impl(std::index_sequence<I...>) {
- constexpr auto ptrs = FieldInfo::ptrs();
- return IsUnique<std::get<I>(ptrs)...>::value;
+ if constexpr (sizeof...(I) == 0) {
+ return true;
+ } else {
+ constexpr auto ptrs = FieldInfo::ptrs();
+ return IsUnique<std::get<I>(ptrs)...>::value;
+ }
}
} // namespace details
diff --git a/cpp/fory/row/CMakeLists.txt b/cpp/fory/row/CMakeLists.txt
index bf450f386..db4288fdb 100644
--- a/cpp/fory/row/CMakeLists.txt
+++ b/cpp/fory/row/CMakeLists.txt
@@ -31,6 +31,7 @@ set(FORY_ROW_HEADERS
add_library(fory_row_format ${FORY_ROW_SOURCES})
add_library(fory::row_format_impl ALIAS fory_row_format)
+fory_configure_target(fory_row_format)
target_include_directories(fory_row_format
PUBLIC
@@ -53,6 +54,7 @@ set_target_properties(fory_row_format PROPERTIES
# Tests
if(FORY_BUILD_TESTS)
add_executable(fory_row_test row_test.cc)
+ fory_configure_target(fory_row_test)
target_link_libraries(fory_row_test fory_row_format GTest::gtest)
gtest_discover_tests(fory_row_test)
endif()
diff --git a/cpp/fory/serialization/CMakeLists.txt
b/cpp/fory/serialization/CMakeLists.txt
index b65047b5c..f07e61244 100644
--- a/cpp/fory/serialization/CMakeLists.txt
+++ b/cpp/fory/serialization/CMakeLists.txt
@@ -51,6 +51,7 @@ set(FORY_SERIALIZATION_HEADERS
add_library(fory_serialization ${FORY_SERIALIZATION_SOURCES})
add_library(fory::serialization_impl ALIAS fory_serialization)
+fory_configure_target(fory_serialization)
target_include_directories(fory_serialization
PUBLIC
@@ -74,52 +75,64 @@ set_target_properties(fory_serialization PROPERTIES
# Tests
if(FORY_BUILD_TESTS)
add_executable(fory_serialization_test serialization_test.cc)
+ fory_configure_target(fory_serialization_test)
target_link_libraries(fory_serialization_test fory_serialization
GTest::gtest GTest::gtest_main)
gtest_discover_tests(fory_serialization_test)
add_executable(fory_serialization_struct_test struct_test.cc)
+ fory_configure_target(fory_serialization_struct_test)
target_link_libraries(fory_serialization_struct_test fory_serialization
GTest::gtest GTest::gtest_main)
gtest_discover_tests(fory_serialization_struct_test)
add_executable(fory_serialization_struct_compatible_test
struct_compatible_test.cc)
+ fory_configure_target(fory_serialization_struct_compatible_test)
target_link_libraries(fory_serialization_struct_compatible_test
fory_serialization GTest::gtest GTest::gtest_main)
gtest_discover_tests(fory_serialization_struct_compatible_test)
add_executable(fory_serialization_smart_ptr_test
smart_ptr_serializer_test.cc)
+ fory_configure_target(fory_serialization_smart_ptr_test)
target_link_libraries(fory_serialization_smart_ptr_test fory_serialization
GTest::gtest GTest::gtest_main)
gtest_discover_tests(fory_serialization_smart_ptr_test)
add_executable(fory_serialization_map_test map_serializer_test.cc)
+ fory_configure_target(fory_serialization_map_test)
target_link_libraries(fory_serialization_map_test fory_serialization
GTest::gtest GTest::gtest_main)
gtest_discover_tests(fory_serialization_map_test)
add_executable(fory_serialization_variant_test variant_serializer_test.cc)
+ fory_configure_target(fory_serialization_variant_test)
target_link_libraries(fory_serialization_variant_test fory_serialization
GTest::gtest GTest::gtest_main)
gtest_discover_tests(fory_serialization_variant_test)
add_executable(fory_serialization_field_test field_serializer_test.cc)
+ fory_configure_target(fory_serialization_field_test)
target_link_libraries(fory_serialization_field_test fory_serialization
GTest::gtest)
gtest_discover_tests(fory_serialization_field_test)
add_executable(fory_serialization_namespace_macro_test
namespace_macro_test.cc)
+ fory_configure_target(fory_serialization_namespace_macro_test)
target_link_libraries(fory_serialization_namespace_macro_test
fory_serialization GTest::gtest GTest::gtest_main)
gtest_discover_tests(fory_serialization_namespace_macro_test)
add_executable(fory_serialization_weak_ptr_test
weak_ptr_serializer_test.cc)
+ fory_configure_target(fory_serialization_weak_ptr_test)
target_link_libraries(fory_serialization_weak_ptr_test fory_serialization
GTest::gtest GTest::gtest_main)
gtest_discover_tests(fory_serialization_weak_ptr_test)
add_executable(fory_serialization_any_test any_serializer_test.cc)
+ fory_configure_target(fory_serialization_any_test)
target_link_libraries(fory_serialization_any_test fory_serialization
GTest::gtest GTest::gtest_main)
gtest_discover_tests(fory_serialization_any_test)
add_executable(fory_serialization_stream_test stream_test.cc)
+ fory_configure_target(fory_serialization_stream_test)
target_link_libraries(fory_serialization_stream_test fory_serialization
GTest::gtest GTest::gtest_main)
gtest_discover_tests(fory_serialization_stream_test)
endif()
# xlang test binary
add_executable(fory_xlang_test_main xlang_test_main.cc)
+fory_configure_target(fory_xlang_test_main)
target_link_libraries(fory_xlang_test_main fory_serialization fory_thirdparty)
set_target_properties(fory_xlang_test_main PROPERTIES
EXCLUDE_FROM_ALL TRUE
diff --git a/cpp/fory/serialization/type_resolver.cc
b/cpp/fory/serialization/type_resolver.cc
index 31252670d..65e922060 100644
--- a/cpp/fory/serialization/type_resolver.cc
+++ b/cpp/fory/serialization/type_resolver.cc
@@ -1595,11 +1595,11 @@ std::unique_ptr<TypeResolver> TypeResolver::clone()
const {
}
void TypeResolver::register_builtin_types() {
+ static_assert(sizeof(TypeId) == sizeof(uint8_t),
+ "TypeId must remain byte-sized for internal type ids");
// Register internal type IDs without harnesses (deserialization is static)
// These are needed so read_any_type_info can find them by type_id
auto register_type_id_only = [this](TypeId type_id) {
- FORY_CHECK(static_cast<uint32_t>(type_id) < 256)
- << "Internal type id overflow: " << static_cast<uint32_t>(type_id);
auto info = std::make_unique<TypeInfo>();
info->type_id = static_cast<uint32_t>(type_id);
info->register_by_name = false;
diff --git a/cpp/fory/serialization/variant_serializer_test.cc
b/cpp/fory/serialization/variant_serializer_test.cc
index e9e818b2e..d2649fd2a 100644
--- a/cpp/fory/serialization/variant_serializer_test.cc
+++ b/cpp/fory/serialization/variant_serializer_test.cc
@@ -57,16 +57,15 @@ Fory create_xlang_fory() {
// Test basic variant serialization with primitive types
TEST(VariantSerializerTest, BasicVariant) {
Fory fory = create_fory();
+ using BasicVariant = std::variant<int, std::string, double>;
// Test with int active
{
- std::variant<int, std::string, double> v1 = 42;
+ static const BasicVariant v1(std::in_place_index<0>, 42);
auto result1 = fory.serialize(v1);
ASSERT_TRUE(result1.has_value());
- auto read_result1 =
- fory.deserialize<std::variant<int, std::string, double>>(
- result1.value());
+ auto read_result1 = fory.deserialize<BasicVariant>(result1.value());
ASSERT_TRUE(read_result1.has_value()) << read_result1.error().message();
ASSERT_EQ(read_result1.value().index(), 0);
ASSERT_EQ(std::get<0>(read_result1.value()), 42);
@@ -74,13 +73,11 @@ TEST(VariantSerializerTest, BasicVariant) {
// Test with string active
{
- std::variant<int, std::string, double> v2 = std::string("hello");
+ static const BasicVariant v2(std::in_place_index<1>, "hello");
auto result2 = fory.serialize(v2);
ASSERT_TRUE(result2.has_value());
- auto read_result2 =
- fory.deserialize<std::variant<int, std::string, double>>(
- result2.value());
+ auto read_result2 = fory.deserialize<BasicVariant>(result2.value());
ASSERT_TRUE(read_result2.has_value());
ASSERT_EQ(read_result2.value().index(), 1);
ASSERT_EQ(std::get<1>(read_result2.value()), "hello");
@@ -88,13 +85,11 @@ TEST(VariantSerializerTest, BasicVariant) {
// Test with double active
{
- std::variant<int, std::string, double> v3 = 3.14;
+ static const BasicVariant v3(std::in_place_index<2>, 3.14);
auto result3 = fory.serialize(v3);
ASSERT_TRUE(result3.has_value());
- auto read_result3 =
- fory.deserialize<std::variant<int, std::string, double>>(
- result3.value());
+ auto read_result3 = fory.deserialize<BasicVariant>(result3.value());
ASSERT_TRUE(read_result3.has_value());
ASSERT_EQ(read_result3.value().index(), 2);
ASSERT_DOUBLE_EQ(std::get<2>(read_result3.value()), 3.14);
diff --git a/cpp/fory/thirdparty/CMakeLists.txt
b/cpp/fory/thirdparty/CMakeLists.txt
index ec0800ef4..8d78da3c3 100644
--- a/cpp/fory/thirdparty/CMakeLists.txt
+++ b/cpp/fory/thirdparty/CMakeLists.txt
@@ -19,6 +19,7 @@ add_library(fory_thirdparty
MurmurHash3.cc
)
add_library(fory::thirdparty ALIAS fory_thirdparty)
+fory_configure_dependency_target(fory_thirdparty)
target_include_directories(fory_thirdparty
PUBLIC
diff --git a/cpp/fory/util/CMakeLists.txt b/cpp/fory/util/CMakeLists.txt
index a543154cd..c59602475 100644
--- a/cpp/fory/util/CMakeLists.txt
+++ b/cpp/fory/util/CMakeLists.txt
@@ -43,6 +43,7 @@ set(FORY_UTIL_HEADERS
add_library(fory_util ${FORY_UTIL_SOURCES})
add_library(fory::util ALIAS fory_util)
+fory_configure_target(fory_util)
target_include_directories(fory_util
PUBLIC
@@ -58,38 +59,47 @@ set_target_properties(fory_util PROPERTIES
# Tests
if(FORY_BUILD_TESTS)
add_executable(fory_util_buffer_test buffer_test.cc)
+ fory_configure_target(fory_util_buffer_test)
target_link_libraries(fory_util_buffer_test fory_util GTest::gtest
GTest::gtest_main)
gtest_discover_tests(fory_util_buffer_test)
add_executable(fory_util_error_test error_test.cc)
+ fory_configure_target(fory_util_error_test)
target_link_libraries(fory_util_error_test fory_util GTest::gtest)
gtest_discover_tests(fory_util_error_test)
add_executable(fory_util_logging_test logging_test.cc)
+ fory_configure_target(fory_util_logging_test)
target_link_libraries(fory_util_logging_test fory_util GTest::gtest)
gtest_discover_tests(fory_util_logging_test)
add_executable(fory_util_pool_test pool_test.cc)
+ fory_configure_target(fory_util_pool_test)
target_link_libraries(fory_util_pool_test fory_util GTest::gtest
GTest::gtest_main)
gtest_discover_tests(fory_util_pool_test)
add_executable(fory_util_result_test result_test.cc)
+ fory_configure_target(fory_util_result_test)
target_link_libraries(fory_util_result_test fory_util GTest::gtest)
gtest_discover_tests(fory_util_result_test)
add_executable(fory_util_string_util_test string_util_test.cc)
+ fory_configure_target(fory_util_string_util_test)
target_link_libraries(fory_util_string_util_test fory_util GTest::gtest)
gtest_discover_tests(fory_util_string_util_test)
add_executable(fory_util_time_util_test time_util_test.cc)
+ fory_configure_target(fory_util_time_util_test)
target_link_libraries(fory_util_time_util_test fory_util GTest::gtest
GTest::gtest_main)
gtest_discover_tests(fory_util_time_util_test)
add_executable(fory_util_flat_int_map_test flat_int_map_test.cc)
+ fory_configure_target(fory_util_flat_int_map_test)
target_link_libraries(fory_util_flat_int_map_test fory_util GTest::gtest
GTest::gtest_main)
gtest_discover_tests(fory_util_flat_int_map_test)
add_executable(fory_util_float16_test float16_test.cc)
+ fory_configure_target(fory_util_float16_test)
target_link_libraries(fory_util_float16_test fory_util fory_serialization
GTest::gtest GTest::gtest_main)
gtest_discover_tests(fory_util_float16_test)
endif()
diff --git a/cpp/fory/util/logging.h b/cpp/fory/util/logging.h
index df9f1a093..9f42436dc 100644
--- a/cpp/fory/util/logging.h
+++ b/cpp/fory/util/logging.h
@@ -78,7 +78,7 @@ public:
template <typename T> ForyLog &operator<<(const T &t) {
stream() << t;
return *this;
- };
+ }
/// Return whether or not the log level is enabled in current setting.
///
@@ -89,7 +89,7 @@ public:
static ForyLogLevel get_log_level();
protected:
- virtual std::ostream &stream() { return std::cerr; };
+ virtual std::ostream &stream() { return std::cerr; }
private:
/// log level.
diff --git a/cpp/fory/util/result.h b/cpp/fory/util/result.h
index 33fa03a85..3d9673763 100644
--- a/cpp/fory/util/result.h
+++ b/cpp/fory/util/result.h
@@ -22,6 +22,7 @@
#include "fory/util/error.h"
#include "fory/util/logging.h"
#include "fory/util/macros.h"
+#include <new>
#include <type_traits>
#include <utility>
@@ -320,21 +321,23 @@ public:
/// ```
template <typename E> class Result<void, E> {
private:
- // Union-based storage avoids heap allocation
- union Storage {
- char dummy_; // Placeholder for success state (1 byte)
- E error_;
+ using ErrorStorage =
+ typename std::aligned_storage<sizeof(E), alignof(E)>::type;
- Storage() : dummy_(0) {}
- ~Storage() {}
- };
-
- Storage storage_;
+ ErrorStorage error_storage_;
bool has_value_;
+ E *error_ptr() noexcept {
+ return std::launder(reinterpret_cast<E *>(&error_storage_));
+ }
+
+ const E *error_ptr() const noexcept {
+ return std::launder(reinterpret_cast<const E *>(&error_storage_));
+ }
+
void destroy() {
if (!has_value_) {
- storage_.error_.~E();
+ error_ptr()->~E();
}
}
@@ -343,15 +346,15 @@ public:
using error_type = E;
// Construct success result
- Result() : has_value_(true) { storage_.dummy_ = 0; }
+ Result() : has_value_(true) {}
// Construct error result
Result(const Unexpected<E> &unexpected) : has_value_(false) {
- new (&storage_.error_) E(unexpected.error());
+ new (&error_storage_) E(unexpected.error());
}
Result(Unexpected<E> &&unexpected) : has_value_(false) {
- new (&storage_.error_) E(std::move(unexpected.error()));
+ new (&error_storage_) E(std::move(unexpected.error()));
}
// Destructor
@@ -360,9 +363,7 @@ public:
// copy constructor
Result(const Result &other) : has_value_(other.has_value_) {
if (!has_value_) {
- new (&storage_.error_) E(other.storage_.error_);
- } else {
- storage_.dummy_ = 0;
+ new (&error_storage_) E(*other.error_ptr());
}
}
@@ -370,9 +371,7 @@ public:
Result(Result &&other) noexcept(std::is_nothrow_move_constructible<E>::value)
: has_value_(other.has_value_) {
if (!has_value_) {
- new (&storage_.error_) E(std::move(other.storage_.error_));
- } else {
- storage_.dummy_ = 0;
+ new (&error_storage_) E(std::move(*other.error_ptr()));
}
}
@@ -381,15 +380,13 @@ public:
if (this != &other) {
if (has_value_ == other.has_value_) {
if (!has_value_) {
- storage_.error_ = other.storage_.error_;
+ *error_ptr() = *other.error_ptr();
}
} else {
destroy();
has_value_ = other.has_value_;
if (!has_value_) {
- new (&storage_.error_) E(other.storage_.error_);
- } else {
- storage_.dummy_ = 0;
+ new (&error_storage_) E(*other.error_ptr());
}
}
}
@@ -403,15 +400,13 @@ public:
if (this != &other) {
if (has_value_ == other.has_value_) {
if (!has_value_) {
- storage_.error_ = std::move(other.storage_.error_);
+ *error_ptr() = std::move(*other.error_ptr());
}
} else {
destroy();
has_value_ = other.has_value_;
if (!has_value_) {
- new (&storage_.error_) E(std::move(other.storage_.error_));
- } else {
- storage_.dummy_ = 0;
+ new (&error_storage_) E(std::move(*other.error_ptr()));
}
}
}
@@ -434,22 +429,22 @@ public:
/// Returns a reference to the contained error
E &error() & {
FORY_CHECK(!has_value_) << "Cannot access error of successful Result";
- return storage_.error_;
+ return *error_ptr();
}
const E &error() const & {
FORY_CHECK(!has_value_) << "Cannot access error of successful Result";
- return storage_.error_;
+ return *error_ptr();
}
E &&error() && {
FORY_CHECK(!has_value_) << "Cannot access error of successful Result";
- return std::move(storage_.error_);
+ return std::move(*error_ptr());
}
const E &&error() const && {
FORY_CHECK(!has_value_) << "Cannot access error of successful Result";
- return std::move(storage_.error_);
+ return std::move(*error_ptr());
}
};
diff --git a/dart/README.md b/dart/README.md
index 4f366d1be..7b0eb98f3 100644
--- a/dart/README.md
+++ b/dart/README.md
@@ -32,7 +32,8 @@ including getting started, API reference, and code examples.
| uint16 | `int` + `@ForyField(type: Uint16Type())` |
| uint32 | `int` + `@ForyField(type: Uint32Type())` |
| uint64 | `int` or `Uint64` |
-| float16 | `fory.Float16` (wrapper) |
+| float16 | `double` + `@ForyField(type: Float16Type())` |
+| bfloat16 | `double` + `@ForyField(type: Bfloat16Type())` |
| float32 | `fory.Float32` (wrapper) |
| float64 | `double` |
| string | `String` |
diff --git a/dart/packages/fory-test/lib/entity/xlang_test_models.dart
b/dart/packages/fory-test/lib/entity/xlang_test_models.dart
index e25b9292b..54540a6c7 100644
--- a/dart/packages/fory-test/lib/entity/xlang_test_models.dart
+++ b/dart/packages/fory-test/lib/entity/xlang_test_models.dart
@@ -332,10 +332,17 @@ class TwoStringFieldStruct {
class ReducedPrecisionFloatStruct {
ReducedPrecisionFloatStruct();
- Float16 float16Value = const Float16.fromBits(0);
- Bfloat16 bfloat16Value = const Bfloat16.fromBits(0);
- List<Float16> float16Array = <Float16>[];
- List<Bfloat16> bfloat16Array = <Bfloat16>[];
+ @ForyField(type: Float16Type())
+ double float16Value = 0.0;
+
+ @ForyField(type: Bfloat16Type())
+ double bfloat16Value = 0.0;
+
+ @ListField(element: Float16Type())
+ List<double> float16Array = <double>[];
+
+ @ListField(element: Bfloat16Type())
+ List<double> bfloat16Array = <double>[];
}
@ForyStruct()
diff --git a/dart/packages/fory/README.md b/dart/packages/fory/README.md
index 339684c16..78ea3ea30 100644
--- a/dart/packages/fory/README.md
+++ b/dart/packages/fory/README.md
@@ -14,8 +14,8 @@ cases.
- Compatible mode for schema evolution
- Optional reference tracking for shared and circular object graphs
- Manual serializers for external types, custom payloads, and unions
-- Explicit exact-width value classes for `Int64`, `Uint64`, `Float16`,
- `Bfloat16`, `Float32`, `LocalDate`, and `Timestamp`, plus `Duration` support
+- Explicit exact-width value classes for `Int64`, `Uint64`, `Float32`,
+ `LocalDate`, and `Timestamp`, plus `Duration` support
## Getting Started
@@ -234,11 +234,11 @@ void main() {
## Type Mapping
Dart has no native fixed-width 8/16/32-bit integer, unsigned 64-bit integer,
-or single-precision float types. Fory Dart uses plain Dart `int` plus field
-annotations for 8/16/32-bit integer fields, keeps `Int64` and `Uint64` for
-full-range 64-bit values, and uses wrapper value types for reduced-width
-floating point. For 16-bit floating-point arrays, Dart exposes `Float16List`
-and `Bfloat16List` as contiguous fixed-length buffers.
+or reduced/single-precision float scalar types. Fory Dart uses plain Dart `int`
+or `double` plus field annotations for exact wire widths, keeps `Int64` and
+`Uint64` for full-range 64-bit values, and keeps `Float32` for single-precision
+rounding. For 16-bit floating-point arrays, Dart exposes `Float16List` and
+`Bfloat16List` as contiguous fixed-length buffers.
| Fory xlang type | Dart type |
| --------------- | ----------------------------------------------- |
@@ -251,8 +251,8 @@ and `Bfloat16List` as contiguous fixed-length buffers.
| uint16 | `int` + `@ForyField(type: Uint16Type())` |
| uint32 | `int` + `@ForyField(type: Uint32Type())` |
| uint64 | `fory.Uint64` (wrapper) |
-| float16 | `fory.Float16` (wrapper) |
-| bfloat16 | `fory.Bfloat16` (wrapper) |
+| float16 | `double` + `@ForyField(type: Float16Type())` |
+| bfloat16 | `double` + `@ForyField(type: Bfloat16Type())` |
| float32 | `fory.Float32` (wrapper) |
| float64 | `double` |
| string | `String` |
@@ -294,7 +294,7 @@ The main exported API includes:
- `Int8Type`, `Int16Type`, `Int32Type`, `Int64Type`, `Uint8Type`, `Uint16Type`,
`Uint32Type`, `Uint64Type`, `Float16Type`, `Bfloat16Type`, `Float32Type` —
scalar wire-type overrides
-- Numeric value wrappers: `Int64`, `Uint64`, `Float16`, `Bfloat16`, `Float32`
+- Numeric value wrappers: `Int64`, `Uint64`, `Float32`
- Temporal types: `LocalDate`, `Timestamp`, `Duration`
## Cross-Language Notes
@@ -304,7 +304,9 @@ The main exported API includes:
- Keep numeric IDs or `namespace + typeName` mappings consistent across
languages.
- Use Dart `int` plus `@ForyField(type: ...)` for 8/16/32-bit integer fields,
- and `Int64` / `Uint64` when full-range 64-bit values matter.
+ Dart `double` plus `Float16Type` or `Bfloat16Type` for 16-bit
+ floating-point fields, and `Int64` / `Uint64` when full-range 64-bit values
+ matter.
For the xlang wire format and type mapping details, see the
[Apache Fory
specification](https://github.com/apache/fory/tree/main/docs/specification).
diff --git a/dart/packages/fory/lib/src/codegen/fory_generator.dart
b/dart/packages/fory/lib/src/codegen/fory_generator.dart
index 8ca52f903..738f170ed 100644
--- a/dart/packages/fory/lib/src/codegen/fory_generator.dart
+++ b/dart/packages/fory/lib/src/codegen/fory_generator.dart
@@ -1557,13 +1557,13 @@ GeneratedFieldType(
case TypeIds.float16:
output
..writeln(
- '$indent$view.setUint16($offset, $valueExpression.toBits(),
generatedLittleEndian);',
+ '$indent$view.setUint16($offset, toFloat16Bits($valueExpression),
generatedLittleEndian);',
)
..writeln('$indent$offset += 2;');
case TypeIds.bfloat16:
output
..writeln(
- '$indent$view.setUint16($offset, $valueExpression.toBits(),
generatedLittleEndian);',
+ '$indent$view.setUint16($offset, toBfloat16Bits($valueExpression),
generatedLittleEndian);',
)
..writeln('$indent$offset += 2;');
case TypeIds.float32:
@@ -1662,13 +1662,13 @@ GeneratedFieldType(
case TypeIds.float16:
output
..writeln(
- '$indent$target = Float16.fromBits($view.getUint16($offset,
generatedLittleEndian));',
+ '$indent$target = fromFloat16Bits($view.getUint16($offset,
generatedLittleEndian));',
)
..writeln('$indent$offset += 2;');
case TypeIds.bfloat16:
output
..writeln(
- '$indent$target = Bfloat16.fromBits($view.getUint16($offset,
generatedLittleEndian));',
+ '$indent$target = fromBfloat16Bits($view.getUint16($offset,
generatedLittleEndian));',
)
..writeln('$indent$offset += 2;');
case TypeIds.float32:
@@ -2772,12 +2772,13 @@ GeneratedFieldType(
final valid = switch (_typeLiteral(nonNullable)) {
'bool' => typeId == TypeIds.boolType,
'int' => _isSupportedIntTypeId(typeId),
- 'double' => typeId == TypeIds.float32 || typeId == TypeIds.float64,
+ 'double' => typeId == TypeIds.float16 ||
+ typeId == TypeIds.bfloat16 ||
+ typeId == TypeIds.float32 ||
+ typeId == TypeIds.float64,
'String' => typeId == TypeIds.string,
'Int64' => _isSigned64TypeId(typeId),
'Uint64' => _isUnsigned64TypeId(typeId),
- 'Float16' => typeId == TypeIds.float16,
- 'Bfloat16' => typeId == TypeIds.bfloat16,
'Float32' => typeId == TypeIds.float32,
'Decimal' => typeId == TypeIds.decimal,
'Timestamp' || 'DateTime' => typeId == TypeIds.timestamp,
@@ -2996,10 +2997,6 @@ GeneratedFieldType(
return TypeIds.varUint64;
case 'Int64':
return TypeIds.varInt64;
- case 'Float16':
- return TypeIds.float16;
- case 'Bfloat16':
- return TypeIds.bfloat16;
case 'Float32':
return TypeIds.float32;
case 'Decimal':
diff --git a/dart/packages/fory/lib/src/context/read_context.dart
b/dart/packages/fory/lib/src/context/read_context.dart
index 6d17c6867..1ed9dbed9 100644
--- a/dart/packages/fory/lib/src/context/read_context.dart
+++ b/dart/packages/fory/lib/src/context/read_context.dart
@@ -35,8 +35,6 @@ import 'package:fory/src/serializer/serializer.dart';
import 'package:fory/src/serializer/serializer_support.dart';
import 'package:fory/src/serializer/time_serializers.dart';
import 'package:fory/src/serializer/typed_array_serializers.dart';
-import 'package:fory/src/types/bfloat16.dart';
-import 'package:fory/src/types/float16.dart';
import 'package:fory/src/types/int64.dart';
import 'package:fory/src/types/timestamp.dart';
import 'package:fory/src/types/uint64.dart';
@@ -143,10 +141,10 @@ final class ReadContext {
Int64 readInt64() => _buffer.readInt64();
/// Reads a half-precision floating-point value.
- Float16 readFloat16() => _buffer.readFloat16();
+ double readFloat16() => _buffer.readFloat16();
/// Reads a bfloat16 floating-point value.
- Bfloat16 readBfloat16() => _buffer.readBfloat16();
+ double readBfloat16() => _buffer.readBfloat16();
/// Reads a single-precision floating-point value.
double readFloat32() => _buffer.readFloat32();
diff --git a/dart/packages/fory/lib/src/context/write_context.dart
b/dart/packages/fory/lib/src/context/write_context.dart
index 35b04a0a4..4748995eb 100644
--- a/dart/packages/fory/lib/src/context/write_context.dart
+++ b/dart/packages/fory/lib/src/context/write_context.dart
@@ -132,10 +132,10 @@ final class WriteContext {
void writeInt64(Int64 value) => _buffer.writeInt64(value);
/// Writes a half-precision floating-point value.
- void writeFloat16(Float16 value) => _buffer.writeFloat16(value);
+ void writeFloat16(double value) => _buffer.writeFloat16(value);
/// Writes a bfloat16 floating-point value.
- void writeBfloat16(Bfloat16 value) => _buffer.writeBfloat16(value);
+ void writeBfloat16(double value) => _buffer.writeBfloat16(value);
/// Writes a single-precision floating-point value.
void writeFloat32(double value) => _buffer.writeFloat32(value);
diff --git a/dart/packages/fory/lib/src/memory/buffer_mixin.dart
b/dart/packages/fory/lib/src/memory/buffer_mixin.dart
index e8fcf415a..200ca3831 100644
--- a/dart/packages/fory/lib/src/memory/buffer_mixin.dart
+++ b/dart/packages/fory/lib/src/memory/buffer_mixin.dart
@@ -198,16 +198,16 @@ mixin _BufferMixin {
}
/// Writes a half-precision floating-point value.
- void writeFloat16(Float16 value) => writeUint16(value.toBits());
+ void writeFloat16(double value) => writeUint16(toFloat16Bits(value));
/// Reads a half-precision floating-point value.
- Float16 readFloat16() => Float16.fromBits(readUint16());
+ double readFloat16() => fromFloat16Bits(readUint16());
/// Writes a bfloat16 floating-point value.
- void writeBfloat16(Bfloat16 value) => writeUint16(value.toBits());
+ void writeBfloat16(double value) => writeUint16(toBfloat16Bits(value));
/// Reads a bfloat16 floating-point value.
- Bfloat16 readBfloat16() => Bfloat16.fromBits(readUint16());
+ double readBfloat16() => fromBfloat16Bits(readUint16());
/// Writes [value] verbatim.
void writeBytes(List<int> value) {
diff --git a/dart/packages/fory/lib/src/resolver/type_resolver.dart
b/dart/packages/fory/lib/src/resolver/type_resolver.dart
index adecdca05..f9e4b0ca5 100644
--- a/dart/packages/fory/lib/src/resolver/type_resolver.dart
+++ b/dart/packages/fory/lib/src/resolver/type_resolver.dart
@@ -427,12 +427,6 @@ final class TypeResolver {
if (value is Uint64) {
return _builtin(Uint64, TypeIds.varUint64);
}
- if (value is Float16) {
- return _builtin(Float16, TypeIds.float16);
- }
- if (value is Bfloat16) {
- return _builtin(Bfloat16, TypeIds.bfloat16);
- }
if (value is Float32) {
return _builtin(Float32, TypeIds.float32);
}
@@ -1297,9 +1291,9 @@ final class TypeResolver {
case TypeIds.taggedUint64:
return _builtin(Uint64, TypeIds.taggedUint64);
case TypeIds.float16:
- return _builtin(Float16, TypeIds.float16);
+ return _builtin(double, TypeIds.float16);
case TypeIds.bfloat16:
- return _builtin(Bfloat16, TypeIds.bfloat16);
+ return _builtin(double, TypeIds.bfloat16);
case TypeIds.float32:
return _builtin(Float32, TypeIds.float32);
case TypeIds.float64:
@@ -1512,12 +1506,6 @@ final class TypeResolver {
if (type == Uint64List) {
return TypeIds.uint64Array;
}
- if (type == Float16) {
- return TypeIds.float16;
- }
- if (type == Bfloat16) {
- return TypeIds.bfloat16;
- }
if (type == BoolList) {
return TypeIds.list;
}
diff --git a/dart/packages/fory/lib/src/serializer/collection_serializers.dart
b/dart/packages/fory/lib/src/serializer/collection_serializers.dart
index e6d23674d..125292cc7 100644
--- a/dart/packages/fory/lib/src/serializer/collection_serializers.dart
+++ b/dart/packages/fory/lib/src/serializer/collection_serializers.dart
@@ -609,9 +609,9 @@ void _setArrayValue(Object target, int arrayTypeId, int
index, Object? value) {
(target as Uint64List)[index] =
value is int ? Uint64(value) : value as Uint64;
case TypeIds.float16Array:
- (target as Float16List)[index] = value as Float16;
+ (target as Float16List)[index] = value as double;
case TypeIds.bfloat16Array:
- (target as Bfloat16List)[index] = value as Bfloat16;
+ (target as Bfloat16List)[index] = value as double;
case TypeIds.float32Array:
(target as Float32List)[index] = (value as num).toDouble();
case TypeIds.float64Array:
diff --git a/dart/packages/fory/lib/src/serializer/primitive_serializers.dart
b/dart/packages/fory/lib/src/serializer/primitive_serializers.dart
index 31e1c1384..947964632 100644
--- a/dart/packages/fory/lib/src/serializer/primitive_serializers.dart
+++ b/dart/packages/fory/lib/src/serializer/primitive_serializers.dart
@@ -21,8 +21,6 @@ import 'package:fory/src/context/read_context.dart';
import 'package:fory/src/context/write_context.dart';
import 'package:fory/src/meta/type_ids.dart';
import 'package:fory/src/serializer/serializer.dart';
-import 'package:fory/src/types/bfloat16.dart';
-import 'package:fory/src/types/float16.dart';
import 'package:fory/src/types/float32.dart';
import 'package:fory/src/types/int64.dart';
import 'package:fory/src/types/uint64.dart';
@@ -118,10 +116,10 @@ final class PrimitiveSerializer<T> extends Serializer<T> {
buffer.writeTaggedUint64(_uint64Value(value));
return;
case TypeIds.float16:
- buffer.writeFloat16(value as Float16);
+ buffer.writeFloat16(value as double);
return;
case TypeIds.bfloat16:
- buffer.writeBfloat16(value as Bfloat16);
+ buffer.writeBfloat16(value as double);
return;
case TypeIds.float32:
buffer.writeFloat32((value as Float32).value);
@@ -264,13 +262,13 @@ const PrimitiveSerializer<Uint64> taggedUint64Serializer =
TypeIds.taggedUint64,
supportsRef: false,
);
-const PrimitiveSerializer<Float16> float16Serializer =
- PrimitiveSerializer<Float16>(
+const PrimitiveSerializer<double> float16Serializer =
+ PrimitiveSerializer<double>(
TypeIds.float16,
supportsRef: false,
);
-const PrimitiveSerializer<Bfloat16> bfloat16Serializer =
- PrimitiveSerializer<Bfloat16>(
+const PrimitiveSerializer<double> bfloat16Serializer =
+ PrimitiveSerializer<double>(
TypeIds.bfloat16,
supportsRef: false,
);
diff --git a/dart/packages/fory/lib/src/types/bfloat16.dart
b/dart/packages/fory/lib/src/types/bfloat16.dart
index c1267c7d4..cd4c315ab 100644
--- a/dart/packages/fory/lib/src/types/bfloat16.dart
+++ b/dart/packages/fory/lib/src/types/bfloat16.dart
@@ -24,181 +24,63 @@ const int _bfloat16ImplicitMantissaBit =
0x0010000000000000;
const int _bfloat16RoundIncrement = 0x0000100000000000;
const int _bfloat16MantissaDivisor = 0x0000200000000000;
-/// Brain floating-point wrapper used by the xlang type system.
-///
-/// [Bfloat16] stores an IEEE 754 bfloat16 payload exactly. Constructing from a
-/// Dart number rounds directly from the incoming IEEE 754 binary64 value to
the
-/// closest representable bfloat16 value using round-to-nearest-even semantics.
-final class Bfloat16 implements Comparable<Bfloat16> {
- final int _bits;
-
- /// Creates a value directly from IEEE 754 bfloat16 bits.
- const Bfloat16.fromBits(int bits) : _bits = bits & 0xffff;
-
- /// Converts [value] to the closest representable bfloat16 value.
- factory Bfloat16(num value) => Bfloat16.fromDouble(value.toDouble());
-
- /// Converts [value] to the closest representable bfloat16 value.
- factory Bfloat16.fromDouble(double value) {
- final data = ByteData(8)..setFloat64(0, value, Endian.little);
- final low32 = data.getUint32(0, Endian.little);
- final high32 = data.getUint32(4, Endian.little);
- final sign = (high32 >>> 31) & 0x1;
- final exponent = (high32 >>> 20) & 0x7ff;
- final mantissa = ((high32 & 0x000fffff) * 0x100000000) + low32;
-
- if (exponent == 0x7ff) {
- if (mantissa == 0) {
- return Bfloat16.fromBits((sign << 15) | 0x7f80);
- }
- var payload = (mantissa ~/ _bfloat16MantissaDivisor) & 0x7f;
- if (payload == 0) {
- payload = 0x40;
- } else {
- payload |= 0x40;
- }
- return Bfloat16.fromBits((sign << 15) | 0x7f80 | payload);
- }
-
- final adjustedExponent = exponent - 1023 + 127;
- if (adjustedExponent >= 0xff) {
- return Bfloat16.fromBits((sign << 15) | 0x7f80);
+final ByteData _bfloat16Float64Data = ByteData(8);
+final ByteData _bfloat16Float32Data = ByteData(4);
+
+/// Converts [value] to IEEE 754 bfloat16 bits.
+int toBfloat16Bits(double value) {
+ _bfloat16Float64Data.setFloat64(0, value, Endian.little);
+ final low32 = _bfloat16Float64Data.getUint32(0, Endian.little);
+ final high32 = _bfloat16Float64Data.getUint32(4, Endian.little);
+ final sign = (high32 >>> 31) & 0x1;
+ final exponent = (high32 >>> 20) & 0x7ff;
+ final mantissa = ((high32 & 0x000fffff) * 0x100000000) + low32;
+
+ if (exponent == 0x7ff) {
+ if (mantissa == 0) {
+ return (sign << 15) | 0x7f80;
}
- if (adjustedExponent <= 0) {
- if (adjustedExponent < -7) {
- return Bfloat16.fromBits(sign << 15);
- }
- final shifted = (mantissa + _bfloat16ImplicitMantissaBit) ~/
- _pow2Int(46 - adjustedExponent);
- final rounded = (shifted + 1) ~/ 2;
- return Bfloat16.fromBits((sign << 15) | rounded);
+ var payload = (mantissa ~/ _bfloat16MantissaDivisor) & 0x7f;
+ if (payload == 0) {
+ payload = 0x40;
+ } else {
+ payload |= 0x40;
}
+ return (sign << 15) | 0x7f80 | payload;
+ }
- var roundedMantissa = mantissa + _bfloat16RoundIncrement;
- var roundedExponent = adjustedExponent;
- if (roundedMantissa >= _bfloat16ImplicitMantissaBit) {
- roundedMantissa = 0;
- roundedExponent += 1;
- if (roundedExponent >= 0xff) {
- return Bfloat16.fromBits((sign << 15) | 0x7f80);
- }
+ final adjustedExponent = exponent - 1023 + 127;
+ if (adjustedExponent >= 0xff) {
+ return (sign << 15) | 0x7f80;
+ }
+ if (adjustedExponent <= 0) {
+ if (adjustedExponent < -7) {
+ return sign << 15;
}
- return Bfloat16.fromBits(
- (sign << 15) |
- (roundedExponent << 7) |
- (roundedMantissa ~/ _bfloat16MantissaDivisor),
- );
+ final shifted = (mantissa + _bfloat16ImplicitMantissaBit) ~/
+ _pow2Int(46 - adjustedExponent);
+ final rounded = (shifted + 1) ~/ 2;
+ return (sign << 15) | rounded;
}
- /// Returns the raw IEEE 754 bfloat16 bits for this value.
- int toBits() => _bits;
-
- /// Expands this bfloat16 value to a Dart [double].
- double toDouble() {
- final data = ByteData(4)..setUint32(0, _bits << 16, Endian.little);
- return data.getFloat32(0, Endian.little);
+ var roundedMantissa = mantissa + _bfloat16RoundIncrement;
+ var roundedExponent = adjustedExponent;
+ if (roundedMantissa >= _bfloat16ImplicitMantissaBit) {
+ roundedMantissa = 0;
+ roundedExponent += 1;
+ if (roundedExponent >= 0xff) {
+ return (sign << 15) | 0x7f80;
+ }
}
+ return (sign << 15) |
+ (roundedExponent << 7) |
+ (roundedMantissa ~/ _bfloat16MantissaDivisor);
+}
- /// Returns the rounded bfloat16 value as a Dart [double].
- double get value => toDouble();
-
- /// Returns a bfloat16-rounded sum.
- Bfloat16 operator +(Object other) => switch (other) {
- Bfloat16 otherValue => Bfloat16(value + otherValue.value),
- num otherValue => Bfloat16(value + otherValue.toDouble()),
- _ => throw ArgumentError.value(
- other, 'other', 'Expected a num or Bfloat16.'),
- };
-
- /// Returns a bfloat16-rounded difference.
- Bfloat16 operator -(Object other) => switch (other) {
- Bfloat16 otherValue => Bfloat16(value - otherValue.value),
- num otherValue => Bfloat16(value - otherValue.toDouble()),
- _ => throw ArgumentError.value(
- other, 'other', 'Expected a num or Bfloat16.'),
- };
-
- /// Returns a bfloat16-rounded product.
- Bfloat16 operator *(Object other) => switch (other) {
- Bfloat16 otherValue => Bfloat16(value * otherValue.value),
- num otherValue => Bfloat16(value * otherValue.toDouble()),
- _ => throw ArgumentError.value(
- other, 'other', 'Expected a num or Bfloat16.'),
- };
-
- /// Returns a bfloat16-rounded quotient.
- Bfloat16 operator /(Object other) => switch (other) {
- Bfloat16 otherValue => Bfloat16(value / otherValue.value),
- num otherValue => Bfloat16(value / otherValue.toDouble()),
- _ => throw ArgumentError.value(
- other, 'other', 'Expected a num or Bfloat16.'),
- };
-
- /// Returns a bfloat16-rounded remainder.
- Bfloat16 operator %(Object other) => switch (other) {
- Bfloat16 otherValue => Bfloat16(value % otherValue.value),
- num otherValue => Bfloat16(value % otherValue.toDouble()),
- _ => throw ArgumentError.value(
- other, 'other', 'Expected a num or Bfloat16.'),
- };
-
- /// Returns the truncated integer quotient, matching Dart `num` semantics.
- int operator ~/(Object other) => switch (other) {
- Bfloat16 otherValue => value ~/ otherValue.value,
- num otherValue => value ~/ otherValue.toDouble(),
- _ => throw ArgumentError.value(
- other, 'other', 'Expected a num or Bfloat16.'),
- };
-
- /// Returns the negated bfloat16-rounded value.
- Bfloat16 operator -() => Bfloat16(-value);
-
- /// Returns whether this value is strictly less than [other].
- bool operator <(Object other) => switch (other) {
- Bfloat16 otherValue => value < otherValue.value,
- num otherValue => value < otherValue.toDouble(),
- _ => throw ArgumentError.value(
- other, 'other', 'Expected a num or Bfloat16.'),
- };
-
- /// Returns whether this value is less than or equal to [other].
- bool operator <=(Object other) => switch (other) {
- Bfloat16 otherValue => value <= otherValue.value,
- num otherValue => value <= otherValue.toDouble(),
- _ => throw ArgumentError.value(
- other, 'other', 'Expected a num or Bfloat16.'),
- };
-
- /// Returns whether this value is strictly greater than [other].
- bool operator >(Object other) => switch (other) {
- Bfloat16 otherValue => value > otherValue.value,
- num otherValue => value > otherValue.toDouble(),
- _ => throw ArgumentError.value(
- other, 'other', 'Expected a num or Bfloat16.'),
- };
-
- /// Returns whether this value is greater than or equal to [other].
- bool operator >=(Object other) => switch (other) {
- Bfloat16 otherValue => value >= otherValue.value,
- num otherValue => value >= otherValue.toDouble(),
- _ => throw ArgumentError.value(
- other, 'other', 'Expected a num or Bfloat16.'),
- };
-
- @override
- bool operator ==(Object other) =>
- identical(this, other) || other is Bfloat16 && other._bits == _bits;
-
- @override
- int get hashCode => _bits.hashCode;
-
- /// Compares this value with [other] after expanding both to Dart [double]s.
- @override
- int compareTo(Bfloat16 other) => value.compareTo(other.value);
-
- /// Returns the expanded Dart [double] string form of this value.
- @override
- String toString() => value.toString();
+/// Expands IEEE 754 bfloat16 [bits] to a Dart [double].
+double fromBfloat16Bits(int bits) {
+ _bfloat16Float32Data.setUint32(0, (bits & 0xffff) << 16, Endian.little);
+ return _bfloat16Float32Data.getFloat32(0, Endian.little);
}
int _pow2Int(int exponent) {
@@ -209,14 +91,14 @@ int _pow2Int(int exponent) {
return result;
}
-/// Fixed-length contiguous storage for [Bfloat16] values.
+/// Fixed-length contiguous storage for bfloat16 values.
///
-/// [Bfloat16List] behaves like a typed-data-style list whose elements are
-/// [Bfloat16] wrappers instead of Dart [double]s. Each element occupies
-/// exactly two bytes, backed by a contiguous [ByteBuffer], so serializers can
-/// process the list as a single dense binary payload.
-final class Bfloat16List extends ListBase<Bfloat16> {
- /// The number of bytes used by one [Bfloat16] element.
+/// [Bfloat16List] stores raw bfloat16 bits but exposes elements as Dart
+/// [double] values. Each element occupies exactly two bytes, backed by a
+/// contiguous [ByteBuffer], so serializers can process the list as a single
+/// dense binary payload.
+final class Bfloat16List extends ListBase<double> {
+ /// The number of bytes used by one bfloat16 element.
static const int bytesPerElement = Uint16List.bytesPerElement;
final Uint16List _storage;
@@ -227,7 +109,7 @@ final class Bfloat16List extends ListBase<Bfloat16> {
Bfloat16List._(this._storage);
/// Copies [values] into a new contiguous bfloat16 list.
- factory Bfloat16List.fromList(Iterable<Bfloat16> values) {
+ factory Bfloat16List.fromList(Iterable<double> values) {
final copied = values.toList(growable: false);
final result = Bfloat16List(copied.length);
for (var index = 0; index < copied.length; index += 1) {
@@ -250,7 +132,7 @@ final class Bfloat16List extends ListBase<Bfloat16> {
/// Creates a zero-copy element-range view of [data].
///
- /// [start] and [end] are measured in [Bfloat16] elements, not bytes.
+ /// [start] and [end] are measured in bfloat16 elements, not bytes.
factory Bfloat16List.sublistView(TypedData data, [int start = 0, int? end]) {
if (data.lengthInBytes % bytesPerElement != 0) {
throw ArgumentError.value(
@@ -271,7 +153,7 @@ final class Bfloat16List extends ListBase<Bfloat16> {
/// Returns the shared backing buffer for this list.
ByteBuffer get buffer => _storage.buffer;
- /// Returns the size in bytes of each [Bfloat16] element.
+ /// Returns the size in bytes of each bfloat16 element.
int get elementSizeInBytes => bytesPerElement;
/// Returns the byte length of this list view.
@@ -280,7 +162,7 @@ final class Bfloat16List extends ListBase<Bfloat16> {
/// Returns the byte offset of this view in [buffer].
int get offsetInBytes => _storage.offsetInBytes;
- /// Returns the number of [Bfloat16] elements in this fixed-length list.
+ /// Returns the number of bfloat16 elements in this fixed-length list.
@override
int get length => _storage.length;
@@ -292,11 +174,11 @@ final class Bfloat16List extends ListBase<Bfloat16> {
/// Reads the element at [index].
@override
- Bfloat16 operator [](int index) => Bfloat16.fromBits(_storage[index]);
+ double operator [](int index) => fromBfloat16Bits(_storage[index]);
/// Stores [value] at [index].
@override
- void operator []=(int index, Bfloat16 value) {
- _storage[index] = value.toBits();
+ void operator []=(int index, double value) {
+ _storage[index] = toBfloat16Bits(value);
}
}
diff --git a/dart/packages/fory/lib/src/types/float16.dart
b/dart/packages/fory/lib/src/types/float16.dart
index dcb514e76..f21c95d9a 100644
--- a/dart/packages/fory/lib/src/types/float16.dart
+++ b/dart/packages/fory/lib/src/types/float16.dart
@@ -24,195 +24,75 @@ const int _float16ImplicitMantissaBit = 0x0010000000000000;
const int _float16RoundIncrement = 0x0000020000000000;
const int _float16MantissaDivisor = 0x0000040000000000;
-/// Half-precision floating-point wrapper used by the xlang type system.
-///
-/// [Float16] stores an IEEE 754 binary16 payload exactly. Constructing from a
-/// Dart number rounds to the closest representable binary16 value, and the
-/// arithmetic operators round every result back to binary16 precision before
-/// returning a new wrapper.
-final class Float16 implements Comparable<Float16> {
- final int _bits;
-
- /// Creates a value directly from IEEE 754 binary16 bits.
- const Float16.fromBits(int bits) : _bits = bits & 0xffff;
-
- /// Converts [value] to the closest representable binary16 value.
- factory Float16(num value) => Float16.fromDouble(value.toDouble());
-
- /// Converts [value] to the closest representable binary16 value.
- factory Float16.fromDouble(double value) {
- if (value.isNaN) {
- return const Float16.fromBits(0x7e00);
- }
- final data = ByteData(8)..setFloat64(0, value, Endian.little);
- final low32 = data.getUint32(0, Endian.little);
- final high32 = data.getUint32(4, Endian.little);
- final sign = (high32 >>> 31) & 0x1;
- final exponent = (high32 >>> 20) & 0x7ff;
- final mantissa = ((high32 & 0x000fffff) * 0x100000000) + low32;
+final ByteData _float16Float64Data = ByteData(8);
- if (exponent == 0x7ff) {
- return Float16.fromBits((sign << 15) | 0x7c00);
- }
+/// Converts [value] to IEEE 754 binary16 bits.
+int toFloat16Bits(double value) {
+ if (value.isNaN) {
+ return 0x7e00;
+ }
+ _float16Float64Data.setFloat64(0, value, Endian.little);
+ final low32 = _float16Float64Data.getUint32(0, Endian.little);
+ final high32 = _float16Float64Data.getUint32(4, Endian.little);
+ final sign = (high32 >>> 31) & 0x1;
+ final exponent = (high32 >>> 20) & 0x7ff;
+ final mantissa = ((high32 & 0x000fffff) * 0x100000000) + low32;
+
+ if (exponent == 0x7ff) {
+ return (sign << 15) | 0x7c00;
+ }
- final adjustedExponent = exponent - 1023 + 15;
- if (adjustedExponent >= 0x1f) {
- return Float16.fromBits((sign << 15) | 0x7c00);
- }
- if (adjustedExponent <= 0) {
- if (adjustedExponent < -10) {
- return Float16.fromBits(sign << 15);
- }
- final shifted = (mantissa + _float16ImplicitMantissaBit) ~/
- _pow2Int(43 - adjustedExponent);
- final rounded = (shifted + 1) ~/ 2;
- return Float16.fromBits((sign << 15) | rounded);
+ final adjustedExponent = exponent - 1023 + 15;
+ if (adjustedExponent >= 0x1f) {
+ return (sign << 15) | 0x7c00;
+ }
+ if (adjustedExponent <= 0) {
+ if (adjustedExponent < -10) {
+ return sign << 15;
}
+ final shifted = (mantissa + _float16ImplicitMantissaBit) ~/
+ _pow2Int(43 - adjustedExponent);
+ final rounded = (shifted + 1) ~/ 2;
+ return (sign << 15) | rounded;
+ }
- var roundedMantissa = mantissa + _float16RoundIncrement;
- var roundedExponent = adjustedExponent;
- if (roundedMantissa >= _float16ImplicitMantissaBit) {
- roundedMantissa = 0;
- roundedExponent += 1;
- if (roundedExponent >= 0x1f) {
- return Float16.fromBits((sign << 15) | 0x7c00);
- }
+ var roundedMantissa = mantissa + _float16RoundIncrement;
+ var roundedExponent = adjustedExponent;
+ if (roundedMantissa >= _float16ImplicitMantissaBit) {
+ roundedMantissa = 0;
+ roundedExponent += 1;
+ if (roundedExponent >= 0x1f) {
+ return (sign << 15) | 0x7c00;
}
- return Float16.fromBits(
- (sign << 15) |
- (roundedExponent << 10) |
- (roundedMantissa ~/ _float16MantissaDivisor),
- );
}
+ return (sign << 15) |
+ (roundedExponent << 10) |
+ (roundedMantissa ~/ _float16MantissaDivisor);
+}
- /// Returns the raw IEEE 754 binary16 bits for this value.
- int toBits() => _bits;
-
- /// Expands this binary16 value to a Dart [double].
- double toDouble() {
- final sign = (_bits >> 15) & 0x1;
- final exponent = (_bits >> 10) & 0x1f;
- final mantissa = _bits & 0x03ff;
- if (exponent == 0) {
- if (mantissa == 0) {
- return sign == 0 ? 0.0 : -0.0;
- }
- final value = mantissa / 1024.0 * 0.00006103515625;
- return sign == 0 ? value : -value;
+/// Expands IEEE 754 binary16 [bits] to a Dart [double].
+double fromFloat16Bits(int bits) {
+ final sign = (bits >> 15) & 0x1;
+ final exponent = (bits >> 10) & 0x1f;
+ final mantissa = bits & 0x03ff;
+ if (exponent == 0) {
+ if (mantissa == 0) {
+ return sign == 0 ? 0.0 : -0.0;
}
- if (exponent == 0x1f) {
- return mantissa == 0
- ? (sign == 0 ? double.infinity : double.negativeInfinity)
- : double.nan;
- }
- final exponentValue = exponent - 15;
- final scale = exponentValue >= 0
- ? (1 << exponentValue).toDouble()
- : 1.0 / (1 << -exponentValue).toDouble();
- final value = (1.0 + mantissa / 1024.0) * scale;
+ final value = mantissa / 1024.0 * 0.00006103515625;
return sign == 0 ? value : -value;
}
-
- /// Returns the rounded binary16 value as a Dart [double].
- double get value => toDouble();
-
- /// Returns a binary16-rounded sum.
- Float16 operator +(Object other) => switch (other) {
- Float16 otherValue => Float16(value + otherValue.value),
- num otherValue => Float16(value + otherValue.toDouble()),
- _ => throw ArgumentError.value(
- other, 'other', 'Expected a num or Float16.'),
- };
-
- /// Returns a binary16-rounded difference.
- Float16 operator -(Object other) => switch (other) {
- Float16 otherValue => Float16(value - otherValue.value),
- num otherValue => Float16(value - otherValue.toDouble()),
- _ => throw ArgumentError.value(
- other, 'other', 'Expected a num or Float16.'),
- };
-
- /// Returns a binary16-rounded product.
- Float16 operator *(Object other) => switch (other) {
- Float16 otherValue => Float16(value * otherValue.value),
- num otherValue => Float16(value * otherValue.toDouble()),
- _ => throw ArgumentError.value(
- other, 'other', 'Expected a num or Float16.'),
- };
-
- /// Returns a binary16-rounded quotient.
- Float16 operator /(Object other) => switch (other) {
- Float16 otherValue => Float16(value / otherValue.value),
- num otherValue => Float16(value / otherValue.toDouble()),
- _ => throw ArgumentError.value(
- other, 'other', 'Expected a num or Float16.'),
- };
-
- /// Returns a binary16-rounded remainder.
- Float16 operator %(Object other) => switch (other) {
- Float16 otherValue => Float16(value % otherValue.value),
- num otherValue => Float16(value % otherValue.toDouble()),
- _ => throw ArgumentError.value(
- other, 'other', 'Expected a num or Float16.'),
- };
-
- /// Returns the truncated integer quotient, matching Dart `num` semantics.
- int operator ~/(Object other) => switch (other) {
- Float16 otherValue => value ~/ otherValue.value,
- num otherValue => value ~/ otherValue.toDouble(),
- _ => throw ArgumentError.value(
- other, 'other', 'Expected a num or Float16.'),
- };
-
- /// Returns the negated binary16-rounded value.
- Float16 operator -() => Float16(-value);
-
- /// Returns whether this value is strictly less than [other].
- bool operator <(Object other) => switch (other) {
- Float16 otherValue => value < otherValue.value,
- num otherValue => value < otherValue.toDouble(),
- _ => throw ArgumentError.value(
- other, 'other', 'Expected a num or Float16.'),
- };
-
- /// Returns whether this value is less than or equal to [other].
- bool operator <=(Object other) => switch (other) {
- Float16 otherValue => value <= otherValue.value,
- num otherValue => value <= otherValue.toDouble(),
- _ => throw ArgumentError.value(
- other, 'other', 'Expected a num or Float16.'),
- };
-
- /// Returns whether this value is strictly greater than [other].
- bool operator >(Object other) => switch (other) {
- Float16 otherValue => value > otherValue.value,
- num otherValue => value > otherValue.toDouble(),
- _ => throw ArgumentError.value(
- other, 'other', 'Expected a num or Float16.'),
- };
-
- /// Returns whether this value is greater than or equal to [other].
- bool operator >=(Object other) => switch (other) {
- Float16 otherValue => value >= otherValue.value,
- num otherValue => value >= otherValue.toDouble(),
- _ => throw ArgumentError.value(
- other, 'other', 'Expected a num or Float16.'),
- };
-
- @override
- bool operator ==(Object other) =>
- identical(this, other) || other is Float16 && other._bits == _bits;
-
- @override
- int get hashCode => _bits.hashCode;
-
- /// Compares this value with [other] after expanding both to Dart [double]s.
- @override
- int compareTo(Float16 other) => value.compareTo(other.value);
-
- /// Returns the expanded Dart [double] string form of this value.
- @override
- String toString() => value.toString();
+ if (exponent == 0x1f) {
+ return mantissa == 0
+ ? (sign == 0 ? double.infinity : double.negativeInfinity)
+ : double.nan;
+ }
+ final exponentValue = exponent - 15;
+ final scale = exponentValue >= 0
+ ? (1 << exponentValue).toDouble()
+ : 1.0 / (1 << -exponentValue).toDouble();
+ final value = (1.0 + mantissa / 1024.0) * scale;
+ return sign == 0 ? value : -value;
}
int _pow2Int(int exponent) {
@@ -223,14 +103,14 @@ int _pow2Int(int exponent) {
return result;
}
-/// Fixed-length contiguous storage for [Float16] values.
+/// Fixed-length contiguous storage for binary16 values.
///
-/// [Float16List] behaves like a typed-data-style list whose elements are
-/// [Float16] wrappers instead of Dart [double]s. Each element occupies exactly
-/// two bytes, backed by a contiguous [ByteBuffer], so serializers can write or
-/// read the list without repacking each element.
-final class Float16List extends ListBase<Float16> {
- /// The number of bytes used by one [Float16] element.
+/// [Float16List] stores raw binary16 bits but exposes elements as Dart
+/// [double] values. Each element occupies exactly two bytes, backed by a
+/// contiguous [ByteBuffer], so serializers can write or read the list without
+/// repacking each element.
+final class Float16List extends ListBase<double> {
+ /// The number of bytes used by one binary16 element.
static const int bytesPerElement = Uint16List.bytesPerElement;
final Uint16List _storage;
@@ -241,7 +121,7 @@ final class Float16List extends ListBase<Float16> {
Float16List._(this._storage);
/// Copies [values] into a new contiguous binary16 list.
- factory Float16List.fromList(Iterable<Float16> values) {
+ factory Float16List.fromList(Iterable<double> values) {
final copied = values.toList(growable: false);
final result = Float16List(copied.length);
for (var index = 0; index < copied.length; index += 1) {
@@ -264,7 +144,7 @@ final class Float16List extends ListBase<Float16> {
/// Creates a zero-copy element-range view of [data].
///
- /// [start] and [end] are measured in [Float16] elements, not bytes.
+ /// [start] and [end] are measured in binary16 elements, not bytes.
factory Float16List.sublistView(TypedData data, [int start = 0, int? end]) {
if (data.lengthInBytes % bytesPerElement != 0) {
throw ArgumentError.value(
@@ -285,7 +165,7 @@ final class Float16List extends ListBase<Float16> {
/// Returns the shared backing buffer for this list.
ByteBuffer get buffer => _storage.buffer;
- /// Returns the size in bytes of each [Float16] element.
+ /// Returns the size in bytes of each binary16 element.
int get elementSizeInBytes => bytesPerElement;
/// Returns the byte length of this list view.
@@ -294,7 +174,7 @@ final class Float16List extends ListBase<Float16> {
/// Returns the byte offset of this view in [buffer].
int get offsetInBytes => _storage.offsetInBytes;
- /// Returns the number of [Float16] elements in this fixed-length list.
+ /// Returns the number of binary16 elements in this fixed-length list.
@override
int get length => _storage.length;
@@ -306,11 +186,11 @@ final class Float16List extends ListBase<Float16> {
/// Reads the element at [index].
@override
- Float16 operator [](int index) => Float16.fromBits(_storage[index]);
+ double operator [](int index) => fromFloat16Bits(_storage[index]);
/// Stores [value] at [index].
@override
- void operator []=(int index, Float16 value) {
- _storage[index] = value.toBits();
+ void operator []=(int index, double value) {
+ _storage[index] = toFloat16Bits(value);
}
}
diff --git a/dart/packages/fory/test/buffer_test.dart
b/dart/packages/fory/test/buffer_test.dart
index 2da7443c1..3d672f7ab 100644
--- a/dart/packages/fory/test/buffer_test.dart
+++ b/dart/packages/fory/test/buffer_test.dart
@@ -38,8 +38,8 @@ void main() {
group('Buffer', () {
test('round-trips fixed-width primitives, 16-bit floats, and bytes', () {
final buffer = Buffer();
- final half = Float16(-2.5);
- final brain = Bfloat16(-3.5);
+ const half = -2.5;
+ const brain = -3.5;
buffer.writeBool(false);
buffer.writeBool(true);
diff --git
a/dart/packages/fory/test/scalar_and_typed_array_serializer_test.dart
b/dart/packages/fory/test/scalar_and_typed_array_serializer_test.dart
index f5374a187..990de5870 100644
--- a/dart/packages/fory/test/scalar_and_typed_array_serializer_test.dart
+++ b/dart/packages/fory/test/scalar_and_typed_array_serializer_test.dart
@@ -49,8 +49,11 @@ class ScalarAndArrayEnvelope {
Float32List float32s = Float32List(0);
Float64List float64s = Float64List(0);
List<bool> flags = <bool>[];
- Float16 half = Float16(0);
- Bfloat16 brain = Bfloat16(0);
+ @ForyField(type: Float16Type())
+ double half = 0.0;
+
+ @ForyField(type: Bfloat16Type())
+ double brain = 0.0;
Float32 single = Float32(0);
LocalDate date = const LocalDate(1970, 1, 1);
Timestamp timestamp = _timestamp(0, 0);
@@ -152,21 +155,21 @@ ScalarAndArrayEnvelope _sampleEnvelope() {
..uint64s = Uint64List.fromList(
<Object>[0, 1, 1 << 40, _uint64HighBit, _uint64Max],
)
- ..float16s = Float16List.fromList(<Float16>[
- Float16.fromBits(0x8000),
- Float16.fromBits(0x3555),
- Float16.fromBits(0x7c00),
+ ..float16s = Float16List.fromList(<double>[
+ fromFloat16Bits(0x8000),
+ fromFloat16Bits(0x3555),
+ fromFloat16Bits(0x7c00),
])
- ..bfloat16s = Bfloat16List.fromList(<Bfloat16>[
- Bfloat16.fromBits(0x8000),
- Bfloat16.fromBits(0x3eab),
- Bfloat16.fromBits(0x7f80),
+ ..bfloat16s = Bfloat16List.fromList(<double>[
+ fromBfloat16Bits(0x8000),
+ fromBfloat16Bits(0x3eab),
+ fromBfloat16Bits(0x7f80),
])
..float32s = Float32List.fromList(<double>[-1.5, 0.0, 3.25])
..float64s = Float64List.fromList(<double>[-2.5, 0.0, 4.5])
..flags = <bool>[true, false, true, true]
- ..half = const Float16.fromBits(0x8000)
- ..brain = const Bfloat16.fromBits(0x7fc0)
+ ..half = fromFloat16Bits(0x8000)
+ ..brain = fromBfloat16Bits(0x3fc0)
..single = Float32(3.5)
..date = LocalDate.fromEpochDay(Int64(-1))
..timestamp = _timestamp(-123, 456789123);
@@ -206,15 +209,29 @@ void _expectUint64ListEquals(Uint64List actual,
Uint64List expected) {
void _expectFloat16ListEquals(Float16List actual, Float16List expected) {
expect(
- actual.map((value) => value.toBits()).toList(),
- orderedEquals(expected.map((value) => value.toBits()).toList()),
+ Uint16List.view(actual.buffer, actual.offsetInBytes, actual.length)
+ .toList(),
+ orderedEquals(
+ Uint16List.view(
+ expected.buffer,
+ expected.offsetInBytes,
+ expected.length,
+ ).toList(),
+ ),
);
}
void _expectBfloat16ListEquals(Bfloat16List actual, Bfloat16List expected) {
expect(
- actual.map((value) => value.toBits()).toList(),
- orderedEquals(expected.map((value) => value.toBits()).toList()),
+ Uint16List.view(actual.buffer, actual.offsetInBytes, actual.length)
+ .toList(),
+ orderedEquals(
+ Uint16List.view(
+ expected.buffer,
+ expected.offsetInBytes,
+ expected.length,
+ ).toList(),
+ ),
);
}
@@ -228,18 +245,20 @@ void _expectFloat64ListEquals(Float64List actual,
Float64List expected) {
void main() {
group('scalar and typed array serializers', () {
- test('round-trips Float16 edge cases', () {
+ test('round-trips float16 edge cases', () {
final fory = Fory();
- final cases = <Float16>[
- const Float16.fromBits(0x8000),
- const Float16.fromBits(0x7e00),
- Float16(double.infinity),
- Float16(-1.5),
+ final cases = <double>[
+ fromFloat16Bits(0x8000),
+ fromFloat16Bits(0x7e00),
+ double.infinity,
+ -1.5,
];
for (final value in cases) {
- final roundTrip = _roundTripRoot<Float16>(fory, value);
- expect(roundTrip.toBits(), equals(value.toBits()));
+ final roundTrip = fory.deserialize<double>(
+ fory.serializeBuiltin(value, wireTypeId: TypeIds.float16),
+ );
+ expect(toFloat16Bits(roundTrip), equals(toFloat16Bits(value)));
}
});
@@ -258,18 +277,20 @@ void main() {
expect(ordinary, equals(Float32(-1.5)));
});
- test('round-trips Bfloat16 edge cases', () {
+ test('round-trips bfloat16 edge cases', () {
final fory = Fory();
- final cases = <Bfloat16>[
- const Bfloat16.fromBits(0x8000),
- const Bfloat16.fromBits(0x7fc0),
- Bfloat16(double.infinity),
- Bfloat16(-1.5),
+ final cases = <double>[
+ fromBfloat16Bits(0x8000),
+ fromBfloat16Bits(0x7fc0),
+ double.infinity,
+ -1.5,
];
for (final value in cases) {
- final roundTrip = _roundTripRoot<Bfloat16>(fory, value);
- expect(roundTrip.toBits(), equals(value.toBits()));
+ final roundTrip = fory.deserialize<double>(
+ fory.serializeBuiltin(value, wireTypeId: TypeIds.bfloat16),
+ );
+ expect(toBfloat16Bits(roundTrip), equals(toBfloat16Bits(value)));
}
});
@@ -390,31 +411,31 @@ void main() {
_expectFloat16ListEquals(
_roundTripRoot<Float16List>(
fory,
- Float16List.fromList(<Float16>[
- Float16.fromBits(0x8000),
- Float16.fromBits(0x3555),
- Float16.fromBits(0x7c00),
+ Float16List.fromList(<double>[
+ fromFloat16Bits(0x8000),
+ fromFloat16Bits(0x3555),
+ fromFloat16Bits(0x7c00),
]),
),
- Float16List.fromList(<Float16>[
- Float16.fromBits(0x8000),
- Float16.fromBits(0x3555),
- Float16.fromBits(0x7c00),
+ Float16List.fromList(<double>[
+ fromFloat16Bits(0x8000),
+ fromFloat16Bits(0x3555),
+ fromFloat16Bits(0x7c00),
]),
);
_expectBfloat16ListEquals(
_roundTripRoot<Bfloat16List>(
fory,
- Bfloat16List.fromList(<Bfloat16>[
- Bfloat16.fromBits(0x8000),
- Bfloat16.fromBits(0x3eab),
- Bfloat16.fromBits(0x7f80),
+ Bfloat16List.fromList(<double>[
+ fromBfloat16Bits(0x8000),
+ fromBfloat16Bits(0x3eab),
+ fromBfloat16Bits(0x7f80),
]),
),
- Bfloat16List.fromList(<Bfloat16>[
- Bfloat16.fromBits(0x8000),
- Bfloat16.fromBits(0x3eab),
- Bfloat16.fromBits(0x7f80),
+ Bfloat16List.fromList(<double>[
+ fromBfloat16Bits(0x8000),
+ fromBfloat16Bits(0x3eab),
+ fromBfloat16Bits(0x7f80),
]),
);
_expectFloat32ListEquals(
@@ -472,17 +493,17 @@ void main() {
expect(float16s.offsetInBytes, equals(0));
expect(float16s.lengthInBytes, equals(4));
- expect(float16s[0].toBits(), equals(0x3c00));
- expect(float16s[1].toBits(), equals(0x3555));
+ expect(toFloat16Bits(float16s[0]), equals(0x3c00));
+ expect(toFloat16Bits(float16s[1]), equals(0x3555));
- float16s[1] = Float16.fromBits(0x4200);
+ float16s[1] = fromFloat16Bits(0x4200);
expect(storage[1], equals(0x4200));
expect(bfloat16s.offsetInBytes, equals(4));
- expect(bfloat16s[0].toBits(), equals(0x3f80));
- expect(bfloat16s[1].toBits(), equals(0x7fc0));
+ expect(toBfloat16Bits(bfloat16s[0]), equals(0x3f80));
+ expect(toBfloat16Bits(bfloat16s[1]), equals(0x7fc0));
- bfloat16s[0] = Bfloat16.fromBits(0xbf80);
+ bfloat16s[0] = fromBfloat16Bits(0xbf80);
expect(storage[2], equals(0xbf80));
});
@@ -508,8 +529,11 @@ void main() {
_expectFloat32ListEquals(roundTrip.float32s, value.float32s);
_expectFloat64ListEquals(roundTrip.float64s, value.float64s);
expect(roundTrip.flags, orderedEquals(value.flags));
- expect(roundTrip.half.toBits(), equals(value.half.toBits()));
- expect(roundTrip.brain.toBits(), equals(value.brain.toBits()));
+ expect(toFloat16Bits(roundTrip.half), equals(toFloat16Bits(value.half)));
+ expect(
+ toBfloat16Bits(roundTrip.brain),
+ equals(toBfloat16Bits(value.brain)),
+ );
expect(roundTrip.single, equals(value.single));
expect(roundTrip.date, equals(value.date));
expect(roundTrip.timestamp, equals(value.timestamp));
diff --git a/dart/packages/fory/test/xlang_protocol_test.dart
b/dart/packages/fory/test/xlang_protocol_test.dart
index 355ef4252..99a2d63a0 100644
--- a/dart/packages/fory/test/xlang_protocol_test.dart
+++ b/dart/packages/fory/test/xlang_protocol_test.dart
@@ -20,12 +20,8 @@
import 'dart:typed_data';
import 'package:fory/fory.dart';
-import 'package:fory/src/context/read_context.dart';
-import 'package:fory/src/context/write_context.dart';
import 'package:fory/src/meta/type_meta.dart';
import 'package:fory/src/resolver/type_resolver.dart';
-import 'package:fory/src/serializer/serializer.dart';
-import 'package:fory/src/types/int64.dart';
import 'package:fory/src/util/hash_util.dart';
import 'package:test/test.dart';
@@ -64,31 +60,36 @@ void main() {
final values = fory.deserialize<Float16List>(bytes);
expect(
- values.map((value) => value.toBits()).toList(),
+ Uint16List.view(values.buffer, values.offsetInBytes, values.length)
+ .toList(),
orderedEquals(<int>[0x3c00, 0xc000, 0x7e00]),
);
});
test('deserializes BFLOAT16 and BFLOAT16_ARRAY wire values', () {
final fory = Fory();
- final scalarBytes =
- Uint8List.fromList(fory.serialize(Bfloat16.fromBits(0xbf60)));
- final arrayBytes = Uint8List.fromList(
- fory.serialize(
- Bfloat16List.fromList(<Bfloat16>[
- Bfloat16.fromBits(0x3f80),
- Bfloat16.fromBits(0xbf80),
- Bfloat16.fromBits(0x7fc1),
- ]),
+ final scalarBytes = Uint8List.fromList(
+ fory.serializeBuiltin(
+ fromBfloat16Bits(0xbf60),
+ wireTypeId: TypeIds.bfloat16,
),
);
+ final rawArray = Uint16List.fromList(<int>[0x3f80, 0xbf80, 0x7fc1]);
+ final arrayBytes = Uint8List.fromList(
+ fory.serialize(Bfloat16List.view(rawArray.buffer)),
+ );
- expect(fory.deserialize<Bfloat16>(scalarBytes).toBits(), equals(0xbf60));
expect(
- fory
- .deserialize<Bfloat16List>(arrayBytes)
- .map((value) => value.toBits())
- .toList(),
+ toBfloat16Bits(fory.deserialize<double>(scalarBytes)),
+ equals(0xbf60),
+ );
+ final arrayValues = fory.deserialize<Bfloat16List>(arrayBytes);
+ expect(
+ Uint16List.view(
+ arrayValues.buffer,
+ arrayValues.offsetInBytes,
+ arrayValues.length,
+ ).toList(),
orderedEquals(<int>[0x3f80, 0xbf80, 0x7fc1]),
);
});
diff --git a/docs/compiler/schema-idl.md b/docs/compiler/schema-idl.md
index 63a6e3ef3..85249596d 100644
--- a/docs/compiler/schema-idl.md
+++ b/docs/compiler/schema-idl.md
@@ -1113,12 +1113,12 @@ Underscore spellings for integer encoding are not FDL
type names.
**Language Mapping:**
-| Fory IDL | Java | Python annotation/value | Go
| Rust | C++ | JavaScript | Dart |
-| ---------- | ---------- | --------------------------- | -------------------
| ---------- | ------------------ | ---------- | ---------- |
-| `float16` | `Float16` | `pyfory.Float16` / `float` | `float16.Float16`
| `Float16` | `fory::float16_t` | `number` | `Float16` |
-| `bfloat16` | `BFloat16` | `pyfory.BFloat16` / `float` | `bfloat16.BFloat16`
| `BFloat16` | `fory::bfloat16_t` | `BFloat16` | `BFloat16` |
-| `float32` | `float` | `pyfory.Float32` | `float32`
| `f32` | `float` | `number` | `Float32` |
-| `float64` | `double` | `pyfory.Float64` | `float64`
| `f64` | `double` | `number` | `double` |
+| Fory IDL | Java | Python annotation/value | Go
| Rust | C++ | JavaScript | Dart |
+| ---------- | ---------- | --------------------------- | -------------------
| ---------- | ------------------ | ---------- | --------- |
+| `float16` | `Float16` | `pyfory.Float16` / `float` | `float16.Float16`
| `Float16` | `fory::float16_t` | `number` | `double` |
+| `bfloat16` | `BFloat16` | `pyfory.BFloat16` / `float` | `bfloat16.BFloat16`
| `BFloat16` | `fory::bfloat16_t` | `number` | `double` |
+| `float32` | `float` | `pyfory.Float32` | `float32`
| `f32` | `float` | `number` | `Float32` |
+| `float64` | `double` | `pyfory.Float64` | `float64`
| `f64` | `double` | `number` | `double` |
#### String Type
diff --git a/docs/guide/dart/cross-language.md
b/docs/guide/dart/cross-language.md
index 077a771db..1918d9468 100644
--- a/docs/guide/dart/cross-language.md
+++ b/docs/guide/dart/cross-language.md
@@ -161,7 +161,7 @@ Fory matches fields by name or by stable field ID. For
robust cross-language int
1. Use the same type identity on every side (same numeric ID or same
`namespace + typeName`).
2. Assign stable `@ForyField(id: ...)` values to all fields before shipping
the first payload.
3. Keep field names consistent or rely on IDs, since Dart typically uses
`lowerCamelCase` while Go uses `PascalCase` for exported fields and C# often
uses `PascalCase` properties.
-4. Use explicit numeric field metadata: `@ForyField(type: Int32Type())` in
Dart for Java `int`, Go `int32`, and C# `int`; `double` in Dart for 64-bit
floats; `Float32` for 32-bit; `Int64` / `Uint64` for full-range 64-bit values.
+4. Use explicit numeric field metadata: `@ForyField(type: Int32Type())` in
Dart for Java `int`, Go `int32`, and C# `int`; `double` in Dart for 64-bit
floats; `double` plus `Float16Type` or `Bfloat16Type` for 16-bit floats;
`Float32` for 32-bit; `Int64` / `Uint64` for full-range 64-bit values.
5. Use `Timestamp`, `LocalDate`, and `Duration` for temporal fields rather
than raw `DateTime`.
6. Validate real round trips across all languages before shipping.
@@ -173,7 +173,8 @@ Because Dart `int` is not itself a promise about the exact
xlang wire width, pre
- `@ForyField(type: Uint32Type())` for xlang `uint32`
- `@ForyField(type: Int8Type())` / `@ForyField(type: Int16Type())` /
`@ForyField(type: Uint8Type())` / `@ForyField(type: Uint16Type())` for narrower
integer widths
- `Int64` and `Uint64` for full-range 64-bit values on web
-- `Float16`, `Bfloat16`, and `Float32` for reduced-width floating point
+- `double` fields annotated with `Float16Type` or `Bfloat16Type` for 16-bit
+ floating-point scalars, and `Float32` for single-precision values
- `Float16List` and `Bfloat16List` for 16-bit floating-point array payloads
- `Timestamp`, `LocalDate`, and `Duration` for explicit temporal semantics
diff --git a/docs/guide/dart/index.md b/docs/guide/dart/index.md
index 34e1da64e..c7458389c 100644
--- a/docs/guide/dart/index.md
+++ b/docs/guide/dart/index.md
@@ -118,8 +118,8 @@ dart run build_runner build --delete-conflicting-outputs
- `@ForyStruct()` — marks a class for code generation
- `@ForyField(...)` — per-field options and canonical `type:` overrides
- `@ListField(...)`, `@SetField(...)`, `@MapField(...)` — container sugar for
nested `type:` trees
-- Exact-value wrappers: `Int64`, `Uint64`, `Float16`, `Bfloat16`, `Float32`
-- Float wrappers: `Float16`, `Bfloat16`, `Float32`
+- Exact-value wrappers: `Int64`, `Uint64`, `Float32`
+- Reduced-precision scalar fields: `double` with `Float16Type` or
`Bfloat16Type`
- 16-bit float arrays: `Float16List`, `Bfloat16List`
- Time types: `LocalDate`, `Timestamp`, `Duration`
diff --git a/docs/guide/dart/supported-types.md
b/docs/guide/dart/supported-types.md
index 186de6938..12f2e3098 100644
--- a/docs/guide/dart/supported-types.md
+++ b/docs/guide/dart/supported-types.md
@@ -76,14 +76,15 @@ field metadata or explicit `Buffer` APIs when native VM
payloads must preserve
unsigned 64-bit identity across dynamic boundaries. Dart web uses wrapper
classes, so web root `Uint64` values keep `varuint64` metadata.
-## Floating-Point Wrappers
+## Floating-Point Types
-Dart `double` maps to 64-bit float. If the peer uses reduced-precision
-floating-point values, use an explicit wrapper:
+Dart `double` maps to 64-bit float by default. If the peer uses
+reduced-precision floating-point values, keep the Dart field as `double` and
+mark the exact wire type with field metadata:
- `Float32` — 32-bit float (matches Java `float`, C# `float`, Go `float32`)
-- `Float16` — half-precision, for specialized numeric payloads
-- `Bfloat16` — brain floating point, useful when interoperating with
ML-oriented payloads
+- `@ForyField(type: Float16Type()) double value` — half-precision scalar
+- `@ForyField(type: Bfloat16Type()) double value` — bfloat16 scalar
For contiguous 16-bit floating-point arrays, use `Float16List` and
`Bfloat16List` rather than `Uint16List` when the schema is `array<float16>`
diff --git a/docs/guide/java/advanced-features.md
b/docs/guide/java/advanced-features.md
index 8661f8755..99b57b562 100644
--- a/docs/guide/java/advanced-features.md
+++ b/docs/guide/java/advanced-features.md
@@ -93,7 +93,7 @@ public interface MemoryAllocator {
* The implementation must grow the buffer in-place by modifying
* the existing buffer instance.
*/
- MemoryBuffer grow(MemoryBuffer buffer, int newCapacity);
+ void grow(MemoryBuffer buffer, int newCapacity);
}
```
@@ -111,9 +111,9 @@ MemoryAllocator customAllocator = new MemoryAllocator() {
}
@Override
- public MemoryBuffer grow(MemoryBuffer buffer, int newCapacity) {
+ public void grow(MemoryBuffer buffer, int newCapacity) {
if (newCapacity <= buffer.size()) {
- return buffer;
+ return;
}
// Custom growth strategy - add 100% extra capacity
@@ -121,7 +121,6 @@ MemoryAllocator customAllocator = new MemoryAllocator() {
byte[] data = new byte[newSize];
buffer.copyToUnsafe(0, data, Platform.BYTE_ARRAY_OFFSET, buffer.size());
buffer.initHeapBuffer(data, 0, data.length);
- return buffer;
}
};
diff --git a/docs/guide/javascript/supported-types.md
b/docs/guide/javascript/supported-types.md
index a932a35b3..4c1d1564b 100644
--- a/docs/guide/javascript/supported-types.md
+++ b/docs/guide/javascript/supported-types.md
@@ -23,18 +23,18 @@ This page lists the JavaScript and TypeScript types
supported by Fory, and expla
## Primitive and Scalar Types
-| JavaScript value | Fory schema
| Notes
|
-| --------------------- |
-------------------------------------------------------------------------------------
| ---------------------------------------------------- |
-| `boolean` | `Type.bool()`
|
|
-| `number` | `Type.int8()` / `Type.int16()` / `Type.int32()` /
`Type.float32()` / `Type.float64()` | Pick the width that matches the peer
language |
-| `bigint` | `Type.int64()` / `Type.uint64()`
| Use `bigint` for 64-bit integers
|
-| `string` | `Type.string()`
|
|
-| `Uint8Array` | `Type.binary()`
| Binary blob
|
-| `Date` | `Type.timestamp()`
| Serializes/deserializes as `Date`
|
-| `Date` | `Type.date()`
| Date without time; deserializes as `Date`
|
-| duration (ms) | `Type.duration()`
| Exposed as a numeric millisecond value in
JavaScript |
-| `number` | `Type.float16()`
| Half-precision float
|
-| `BFloat16` / `number` | `Type.bfloat16()`
| Deserializes to `BFloat16`
|
+| JavaScript value | Fory schema
| Notes
|
+| ---------------- |
-------------------------------------------------------------------------------------
| ---------------------------------------------------- |
+| `boolean` | `Type.bool()`
|
|
+| `number` | `Type.int8()` / `Type.int16()` / `Type.int32()` /
`Type.float32()` / `Type.float64()` | Pick the width that matches the peer
language |
+| `bigint` | `Type.int64()` / `Type.uint64()`
| Use `bigint` for 64-bit integers
|
+| `string` | `Type.string()`
|
|
+| `Uint8Array` | `Type.binary()`
| Binary blob
|
+| `Date` | `Type.timestamp()`
| Serializes/deserializes as `Date`
|
+| `Date` | `Type.date()`
| Date without time; deserializes as `Date`
|
+| duration (ms) | `Type.duration()`
| Exposed as a numeric millisecond value in
JavaScript |
+| `number` | `Type.float16()`
| Half-precision float
|
+| `number` | `Type.bfloat16()`
| Brain floating point
|
## Integer Types
@@ -97,7 +97,7 @@ Type.int64Array(); // BigInt64Array
Type.float32Array(); // Float32Array
Type.float64Array(); // Float64Array
Type.float16Array(); // number[]
-Type.bfloat16Array(); // BFloat16[]
+Type.bfloat16Array(); // BFloat16Array
```
Use `Type.list(elementType)` for non-numeric, struct, nullable-element, or
ref-tracked ordered collections.
diff --git a/docs/guide/xlang/serialization.md
b/docs/guide/xlang/serialization.md
index bee478369..aca6d3c25 100644
--- a/docs/guide/xlang/serialization.md
+++ b/docs/guide/xlang/serialization.md
@@ -30,7 +30,7 @@ Reduced-precision floating-point values are also part of the
built-in xlang type
- `float16` and `array<float16>`
- `bfloat16` and `array<bfloat16>`
-Use the language-specific carrier types documented in the type mapping
reference. Python uses `pyfory.Float16` and `pyfory.BFloat16` as annotation
markers only; scalar values are native Python `float`, and dense
reduced-precision arrays use `pyfory.Float16Array` and `pyfory.BFloat16Array`.
Go uses the `float16` and `bfloat16` packages for scalar, slice, and array
carriers; JavaScript uses `number` for scalar `float16`, `BFloat16` / `number`
for scalar `bfloat16`, and dense array carriers [...]
+Use the language-specific carrier types documented in the type mapping
reference. Python uses `pyfory.Float16` and `pyfory.BFloat16` as annotation
markers only; scalar values are native Python `float`, and dense
reduced-precision arrays use `pyfory.Float16Array` and `pyfory.BFloat16Array`.
Go uses the `float16` and `bfloat16` packages for scalar, slice, and array
carriers; JavaScript uses `number` for scalar `float16` and `bfloat16`, and
dense array carriers `BoolArray`, `Float16Array`, [...]
When `compatible=true`, a direct struct/class field can evolve between
`list<T>` and `array<T>` for dense bool/numeric `T`. Integer list element
encodings in the same signedness and width domain match the corresponding dense
array element domain. This applies only to the immediate matched field schema.
It does not apply to nested collection, map, array, union, or generic
positions. If a peer `list<T>` payload declares nullable or ref-tracked
elements, reading it into a local `array<T>` f [...]
diff --git a/docs/specification/xlang_type_mapping.md
b/docs/specification/xlang_type_mapping.md
index a05a045bb..5cd7adc96 100644
--- a/docs/specification/xlang_type_mapping.md
+++ b/docs/specification/xlang_type_mapping.md
@@ -71,7 +71,7 @@ FDL spells them as an encoding modifier plus a semantic
integer type.
| tagged uint64 | 15 | long/Long
| int/pyfory.TaggedUInt64 | `Type.uint64({
encoding: "tagged" })` | uint64_t |
uint64 | u64
|
| float8 | 16 | /
| / | /
| / | /
| /
|
| float16 | 17 | Float16
| native float / pyfory.Float16 annotation | `number`
| `fory::float16_t` |
`float16.Float16` | `Float16`
|
-| bfloat16 | 18 | BFloat16
| native float / pyfory.BFloat16 annotation | `BFloat16` /
`number` | `fory::bfloat16_t`
| `bfloat16.BFloat16` | `BFloat16`
|
+| bfloat16 | 18 | BFloat16
| native float / pyfory.BFloat16 annotation | `number`
| `fory::bfloat16_t` |
`bfloat16.BFloat16` | `BFloat16`
|
| float32 | 19 | float/Float
| float/pyfory.Float32 | Type.float32()
| float |
float32 | f32
|
| float64 | 20 | double/Double
| float/pyfory.Float64 | Type.float64()
| double |
float64 | f64
|
| string | 21 | String
| str | String
| string |
string | String/str
|
@@ -112,11 +112,12 @@ Notes:
- Python `pyfory.Float16` and `pyfory.BFloat16` are reserved annotation
markers; scalar values deserialize as native Python `float`.
- Python `BoolArray`, `Int8Array`, `Int16Array`, `Int32Array`, `Int64Array`,
`UInt8Array`, `UInt16Array`, `UInt32Array`, `UInt64Array`, `Float16Array`,
`BFloat16Array`, `Float32Array`, and `Float64Array` are public dense-array
wrappers with list-like sequence behavior.
-- JavaScript `BoolArray`, fallback `Float16Array`, and `BFloat16Array` are
public dense-array wrappers backed by `Uint8Array` or `Uint16Array`. A
JavaScript runtime with native `Float16Array` may return that native carrier
for `array<float16>`.
+- JavaScript `BoolArray`, fallback `Float16Array`, and `BFloat16Array` are
public dense-array wrappers backed by `Uint8Array` or `Uint16Array`. Scalar
`float16` and `bfloat16` values use `number`. A JavaScript runtime with native
`Float16Array` may return that native carrier for `array<float16>`.
- Java plain `byte[]` maps to `binary`. Numeric byte arrays use type-use
annotations:
`@Int8Type byte[]` for `array<int8>` and `@UInt8Type byte[]` for
`array<uint8>`.
-- Dart uses `BoolList` for `array<bool>`, typed-data lists for
integer/float32/float64 arrays, and
- `Float16List` / `BFloat16List` for `array<float16>` / `array<bfloat16>`.
Plain Dart `List<bool>`
+- Dart uses `double` plus `Float16Type` or `Bfloat16Type` metadata for scalar
+ `float16` and `bfloat16`, `BoolList` for `array<bool>`, typed-data lists for
integer/float32/float64 arrays, and
+ `Float16List` / `Bfloat16List` for `array<float16>` / `array<bfloat16>`.
Plain Dart `List<bool>`
maps to `list<bool>` unless a field uses `@ArrayField(element: BoolType())`
or
`@ForyField(type: ArrayType(element: BoolType()))` with a `BoolList` carrier.
- `Float16[]` and `BFloat16[]` remain object arrays in xlang mode and
serialize with the `list` wire type.
diff --git a/integration_tests/idl_tests/dart/test/idl_roundtrip_test.dart
b/integration_tests/idl_tests/dart/test/idl_roundtrip_test.dart
index c58660362..6bbc28203 100644
--- a/integration_tests/idl_tests/dart/test/idl_roundtrip_test.dart
+++ b/integration_tests/idl_tests/dart/test/idl_roundtrip_test.dart
@@ -297,8 +297,8 @@ example.ExampleMessage buildExampleMessage() {
..fixedU64Value = Uint64(9876543210)
..varintU64Value = Uint64(12345678901)
..taggedU64Value = Uint64(2222222222)
- ..float16Value = Float16(1.5)
- ..bfloat16Value = Bfloat16(2.5)
+ ..float16Value = 1.5
+ ..bfloat16Value = 2.5
..float32Value = Float32(3.5)
..float64Value = 4.5
..stringValue = 'example'
@@ -325,10 +325,10 @@ example.ExampleMessage buildExampleMessage() {
..fixedU64List = <Uint64>[Uint64(9000000000)]
..varintU64List = <Uint64>[Uint64(12000000000)]
..taggedU64List = <Uint64>[Uint64(13000000000)]
- ..float16List = <Float16>[Float16(1.0), Float16(2.0)]
- ..bfloat16List = <Bfloat16>[Bfloat16(1.0), Bfloat16(2.0)]
- ..maybeFloat16List = <Float16?>[Float16(1.0), null, Float16(2.0)]
- ..maybeBfloat16List = <Bfloat16?>[Bfloat16(1.0), null, Bfloat16(3.0)]
+ ..float16List = <double>[1.0, 2.0]
+ ..bfloat16List = <double>[1.0, 2.0]
+ ..maybeFloat16List = <double?>[1.0, null, 2.0]
+ ..maybeBfloat16List = <double?>[1.0, null, 3.0]
..float32List = <Float32>[Float32(1.5), Float32(2.5)]
..float64List = <double>[3.5, 4.5]
..stringList = <String>['alpha', 'beta']
@@ -372,11 +372,8 @@ example.ExampleMessage buildExampleMessage() {
..uint16Array = Uint16List.fromList(<int>[50000, 60000])
..uint32Array = Uint32List.fromList(<int>[2000000000, 2100000000])
..uint64Array = Uint64List.fromList(<int>[9000000000, 12000000000])
- ..float16Array = Float16List.fromList(<Float16>[Float16(1.0),
Float16(2.0)])
- ..bfloat16Array = Bfloat16List.fromList(<Bfloat16>[
- Bfloat16(1.0),
- Bfloat16(2.0),
- ])
+ ..float16Array = Float16List.fromList(<double>[1.0, 2.0])
+ ..bfloat16Array = Bfloat16List.fromList(<double>[1.0, 2.0])
..float32Array = Float32List.fromList(<double>[1.5, 2.5])
..float64Array = Float64List.fromList(<double>[3.5, 4.5])
..int32ArrayList = <Int32List>[
@@ -416,12 +413,10 @@ example.ExampleMessage buildExampleMessage() {
..stringValuesByEnum = <example.ExampleState, String>{
example.ExampleState.ready: 'ready',
}
- ..float16ValuesByName = <String, Float16>{'f16': Float16(1.25)}
- ..maybeFloat16ValuesByName = <String, Float16?>{'maybe-f16': Float16(1.5)}
- ..bfloat16ValuesByName = <String, Bfloat16>{'bf16': Bfloat16(1.75)}
- ..maybeBfloat16ValuesByName = <String, Bfloat16?>{
- 'maybe-bf16': Bfloat16(2.25),
- }
+ ..float16ValuesByName = <String, double>{'f16': 1.25}
+ ..maybeFloat16ValuesByName = <String, double?>{'maybe-f16': 1.5}
+ ..bfloat16ValuesByName = <String, double>{'bf16': 1.75}
+ ..maybeBfloat16ValuesByName = <String, double?>{'maybe-bf16': 2.25}
..bytesValuesByName = <String, Uint8List>{
'bytes': Uint8List.fromList(<int>[8, 9]),
}
diff --git a/integration_tests/idl_tests/javascript/roundtrip.ts
b/integration_tests/idl_tests/javascript/roundtrip.ts
index e832c17b6..8198b76a9 100644
--- a/integration_tests/idl_tests/javascript/roundtrip.ts
+++ b/integration_tests/idl_tests/javascript/roundtrip.ts
@@ -30,7 +30,6 @@ import * as assert from "assert/strict";
import * as fs from "fs";
import Fory, {
- BFloat16,
BFloat16Array,
BoolArray,
Decimal,
@@ -187,9 +186,6 @@ function normalizeAcyclic(value: unknown): unknown {
if (value instanceof Decimal) {
return { __decimal: value.toString() };
}
- if (value instanceof BFloat16) {
- return value.toFloat32();
- }
if (
value instanceof BoolArray ||
value instanceof ForyFloat16Array ||
diff --git a/integration_tests/idl_tests/javascript/test/roundtrip.test.ts
b/integration_tests/idl_tests/javascript/test/roundtrip.test.ts
index e4fde5357..c141b4577 100644
--- a/integration_tests/idl_tests/javascript/test/roundtrip.test.ts
+++ b/integration_tests/idl_tests/javascript/test/roundtrip.test.ts
@@ -18,7 +18,6 @@
*/
import Fory, {
- BFloat16,
BFloat16Array,
BoolArray,
Decimal,
@@ -132,9 +131,6 @@ function normalize(value: unknown): unknown {
if (value instanceof Decimal) {
return { __decimal: value.toString() };
}
- if (value instanceof BFloat16) {
- return value.toFloat32();
- }
if (
value instanceof BoolArray ||
value instanceof ForyFloat16Array ||
diff --git
a/java/fory-core/src/main/java/org/apache/fory/memory/MemoryAllocator.java
b/java/fory-core/src/main/java/org/apache/fory/memory/MemoryAllocator.java
index ebbc6098c..185b444d7 100644
--- a/java/fory-core/src/main/java/org/apache/fory/memory/MemoryAllocator.java
+++ b/java/fory-core/src/main/java/org/apache/fory/memory/MemoryAllocator.java
@@ -35,7 +35,6 @@ public interface MemoryAllocator {
*
* @param buffer the existing buffer to grow
* @param newCapacity the required new capacity
- * @return the same MemoryBuffer instance with at least the new capacity
*/
- MemoryBuffer grow(MemoryBuffer buffer, int newCapacity);
+ void grow(MemoryBuffer buffer, int newCapacity);
}
diff --git
a/java/fory-core/src/main/java/org/apache/fory/memory/MemoryBuffer.java
b/java/fory-core/src/main/java/org/apache/fory/memory/MemoryBuffer.java
index 89a0c96f8..612ad7b03 100644
--- a/java/fory-core/src/main/java/org/apache/fory/memory/MemoryBuffer.java
+++ b/java/fory-core/src/main/java/org/apache/fory/memory/MemoryBuffer.java
@@ -2826,9 +2826,9 @@ public final class MemoryBuffer {
}
@Override
- public MemoryBuffer grow(MemoryBuffer buffer, int newCapacity) {
+ public void grow(MemoryBuffer buffer, int newCapacity) {
if (newCapacity <= buffer.size()) {
- return buffer;
+ return;
}
int newSize =
@@ -2839,8 +2839,6 @@ public final class MemoryBuffer {
byte[] data = new byte[newSize];
buffer.copyToUnsafe(0, data, Platform.BYTE_ARRAY_OFFSET, buffer.size());
buffer.initHeapBuffer(data, 0, data.length);
-
- return buffer;
}
}
diff --git
a/java/fory-core/src/test/java/org/apache/fory/memory/MemoryAllocatorTest.java
b/java/fory-core/src/test/java/org/apache/fory/memory/MemoryAllocatorTest.java
index 68c3e613d..008aad6f2 100644
---
a/java/fory-core/src/test/java/org/apache/fory/memory/MemoryAllocatorTest.java
+++
b/java/fory-core/src/test/java/org/apache/fory/memory/MemoryAllocatorTest.java
@@ -98,9 +98,8 @@ public class MemoryAllocatorTest {
MemoryAllocator defaultAllocator = MemoryBuffer.getGlobalAllocator();
MemoryBuffer buffer = defaultAllocator.allocate(100);
- // Growth should return the same instance
- MemoryBuffer grownBuffer = defaultAllocator.grow(buffer, 200);
- assertSame(buffer, grownBuffer);
+ defaultAllocator.grow(buffer, 200);
+ assertEquals(buffer.size(), 200 << 1);
}
@Test
@@ -115,9 +114,9 @@ public class MemoryAllocatorTest {
}
@Override
- public MemoryBuffer grow(MemoryBuffer buffer, int newCapacity) {
+ public void grow(MemoryBuffer buffer, int newCapacity) {
if (newCapacity <= buffer.size()) {
- return buffer;
+ return;
}
// Use default grow logic but with custom marker
@@ -125,7 +124,6 @@ public class MemoryAllocatorTest {
byte[] data = new byte[newSize];
buffer.copyToUnsafe(0, data, Platform.BYTE_ARRAY_OFFSET,
buffer.size());
buffer.initHeapBuffer(data, 0, data.length);
- return buffer;
}
};
diff --git a/javascript/packages/core/index.ts
b/javascript/packages/core/index.ts
index 4af7a47ac..a0c99e25c 100644
--- a/javascript/packages/core/index.ts
+++ b/javascript/packages/core/index.ts
@@ -26,7 +26,7 @@ import { Serializer, Mode } from "./lib/type";
import Fory from "./lib/fory";
import { BinaryReader } from "./lib/reader";
import { BinaryWriter } from "./lib/writer";
-import { BFloat16, BFloat16Array } from "./lib/types/bfloat16";
+import { BFloat16Array } from "./lib/types/bfloat16";
import { BoolArray } from "./lib/types/boolArray";
import { Float16Array, ForyFloat16Array } from "./lib/types/float16";
import { ReadContext, WriteContext } from "./lib/context";
@@ -41,7 +41,6 @@ export {
Dynamic,
BinaryReader,
BoolArray,
- BFloat16,
BFloat16Array,
Decimal,
Float16Array,
diff --git a/javascript/packages/core/lib/reader/index.ts
b/javascript/packages/core/lib/reader/index.ts
index b4d654f21..38562948a 100644
--- a/javascript/packages/core/lib/reader/index.ts
+++ b/javascript/packages/core/lib/reader/index.ts
@@ -21,7 +21,7 @@ import { LATIN1, UTF16, UTF8 } from "../type";
import { isNodeEnv } from "../util";
import { PlatformBuffer, alloc, fromUint8Array } from "../platformBuffer";
import { readLatin1String } from "./string";
-import { BFloat16 } from "../types/bfloat16";
+import { fromBFloat16Bits } from "../types/bfloat16";
import { fromFloat16Bits } from "../types/float16";
export class BinaryReader {
@@ -569,8 +569,8 @@ export class BinaryReader {
return fromFloat16Bits(this.readUint16());
}
- readBfloat16(): BFloat16 {
- return BFloat16.fromBits(this.readUint16());
+ readBfloat16() {
+ return fromBFloat16Bits(this.readUint16());
}
readGetCursor() {
diff --git a/javascript/packages/core/lib/typeInfo.ts
b/javascript/packages/core/lib/typeInfo.ts
index 9d09b8527..0dc4f9731 100644
--- a/javascript/packages/core/lib/typeInfo.ts
+++ b/javascript/packages/core/lib/typeInfo.ts
@@ -18,7 +18,7 @@
*/
import { ForyTypeInfoSymbol, TypeId } from "./type";
-import { BFloat16, BFloat16Array } from "./types/bfloat16";
+import { BFloat16Array } from "./types/bfloat16";
import { BoolArray } from "./types/boolArray";
import { Float16Array } from "./types/float16";
import { Decimal } from "./types/decimal";
@@ -491,8 +491,6 @@ export type HintInput<T> = T extends {
type: typeof TypeId.STRING;
}
? string
- : T extends { type: typeof TypeId.BFLOAT16 }
- ? BFloat16 | number
: T extends {
type:
| typeof TypeId["INT8"]
@@ -507,6 +505,7 @@ export type HintInput<T> = T extends {
| typeof TypeId.VAR_UINT32
| typeof TypeId.FLOAT8
| typeof TypeId.FLOAT16
+ | typeof TypeId.BFLOAT16
| typeof TypeId.FLOAT32
| typeof TypeId.FLOAT64;
}
@@ -596,7 +595,7 @@ export type HintInput<T> = T extends {
: T extends {
type: typeof TypeId.BFLOAT16_ARRAY;
}
- ? BFloat16Array | BFloat16[] | number[]
+ ? BFloat16Array | number[]
: T extends {
type: typeof TypeId.FLOAT32_ARRAY;
}
@@ -620,8 +619,6 @@ export type HintResult<T> = T extends never ? any : T
extends {
type: typeof TypeId.STRING;
}
? string
- : T extends { type: typeof TypeId.BFLOAT16 }
- ? BFloat16
: T extends {
type:
| typeof TypeId.INT8
@@ -634,6 +631,7 @@ export type HintResult<T> = T extends never ? any : T
extends {
| typeof TypeId.VAR_UINT32
| typeof TypeId.FLOAT8
| typeof TypeId.FLOAT16
+ | typeof TypeId.BFLOAT16
| typeof TypeId.FLOAT32
| typeof TypeId.FLOAT64;
}
diff --git a/javascript/packages/core/lib/types/bfloat16.ts
b/javascript/packages/core/lib/types/bfloat16.ts
index 5806de158..953366987 100644
--- a/javascript/packages/core/lib/types/bfloat16.ts
+++ b/javascript/packages/core/lib/types/bfloat16.ts
@@ -20,45 +20,19 @@
const float32View = new Float32Array(1);
const uint32View = new Uint32Array(float32View.buffer);
-export class BFloat16 {
- private readonly _bits: number;
-
- constructor(bits: number) {
- this._bits = bits & 0xffff;
- }
-
- toBits(): number {
- return this._bits;
- }
-
- static fromBits(bits: number): BFloat16 {
- return new BFloat16(bits & 0xffff);
- }
-
- static fromFloat32(f32: number): BFloat16 {
- float32View[0] = f32;
- const bits = uint32View[0];
- const exponent = (bits >> 23) & 0xff;
- if (exponent === 255) {
- return BFloat16.fromBits((bits >> 16) & 0xffff);
- }
- const remainder = bits & 0x1ffff;
- let u = (bits + 0x8000) >> 16;
- if (remainder === 0x8000 && (u & 1) !== 0) {
- u--;
- }
- return BFloat16.fromBits(u & 0xffff);
- }
-
- toFloat32(): number {
- float32View[0] = 0;
- uint32View[0] = this._bits << 16;
- return float32View[0];
- }
-}
-
-export function toBFloat16Bits(value: BFloat16 | number): number {
- return value instanceof BFloat16 ? value.toBits() :
BFloat16.fromFloat32(value).toBits();
+export function toBFloat16Bits(value: number): number {
+ float32View[0] = value;
+ const bits = uint32View[0];
+ const exponent = (bits >> 23) & 0xff;
+ if (exponent === 255) {
+ return (bits >> 16) & 0xffff;
+ }
+ const remainder = bits & 0x1ffff;
+ let u = (bits + 0x8000) >> 16;
+ if (remainder === 0x8000 && (u & 1) !== 0) {
+ u--;
+ }
+ return u & 0xffff;
}
export function fromBFloat16Bits(bits: number): number {
@@ -73,8 +47,8 @@ export class BFloat16Array {
private _data: Uint16Array;
constructor(length: number);
- constructor(source: BFloat16Array | Uint16Array | ArrayLike<BFloat16 |
number>);
- constructor(lengthOrSource: number | BFloat16Array | Uint16Array |
ArrayLike<BFloat16 | number>) {
+ constructor(source: BFloat16Array | Uint16Array | ArrayLike<number>);
+ constructor(lengthOrSource: number | BFloat16Array | Uint16Array |
ArrayLike<number>) {
if (typeof lengthOrSource === "number") {
this._data = new Uint16Array(lengthOrSource);
} else if (lengthOrSource instanceof BFloat16Array) {
@@ -118,7 +92,7 @@ export class BFloat16Array {
return this.get(normalized);
}
- set(values: BFloat16Array | ArrayLike<BFloat16 | number>, offset = 0): void {
+ set(values: BFloat16Array | ArrayLike<number>, offset = 0): void {
if (values instanceof BFloat16Array) {
this._data.set(values.raw, offset);
return;
@@ -128,11 +102,11 @@ export class BFloat16Array {
}
}
- setValue(index: number, value: BFloat16 | number): void {
+ setValue(index: number, value: number): void {
this._data[index] = toBFloat16Bits(value);
}
- fill(value: BFloat16 | number, start?: number, end?: number): this {
+ fill(value: number, start?: number, end?: number): this {
this._data.fill(toBFloat16Bits(value), start, end);
return this;
}
diff --git a/javascript/packages/core/lib/writer/index.ts
b/javascript/packages/core/lib/writer/index.ts
index 4413dd9ca..6f6eed717 100644
--- a/javascript/packages/core/lib/writer/index.ts
+++ b/javascript/packages/core/lib/writer/index.ts
@@ -21,7 +21,7 @@ import { HalfMaxInt32, HalfMinInt32, Hps, LATIN1, UTF16, UTF8
} from "../type";
import { PlatformBuffer, alloc, strByteLength } from "../platformBuffer";
import { OwnershipError } from "../error";
import { toFloat16Bits } from "../types/float16";
-import { BFloat16, toBFloat16Bits } from "../types/bfloat16";
+import { toBFloat16Bits } from "../types/bfloat16";
const MAX_POOL_SIZE = 1024 * 1024 * 3; // 3MB
const MAX_SAFE_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);
@@ -506,7 +506,7 @@ export class BinaryWriter {
this.writeUint16(toFloat16Bits(value));
}
- writeBfloat16(value: BFloat16 | number) {
+ writeBfloat16(value: number) {
this.writeUint16(toBFloat16Bits(value));
}
diff --git a/javascript/test/number.test.ts b/javascript/test/number.test.ts
index 14cdff38b..354696425 100644
--- a/javascript/test/number.test.ts
+++ b/javascript/test/number.test.ts
@@ -17,7 +17,7 @@
* under the License.
*/
-import Fory, { Type, BFloat16 } from '../packages/core/index';
+import Fory, { Type } from '../packages/core/index';
import { describe, expect, test } from '@jest/globals';
describe('number', () => {
@@ -160,10 +160,9 @@ describe('number', () => {
}, {
a: Type.bfloat16()
})).serializer;
- const input = fory.serialize({ a: BFloat16.fromFloat32(1.5) }, serializer);
+ const input = fory.serialize({ a: 1.5 }, serializer);
const result = fory.deserialize(input);
- expect(result.a).toBeInstanceOf(BFloat16);
- expect(result.a.toFloat32()).toBeCloseTo(1.5, 2);
+ expect(result.a).toBeCloseTo(1.5, 2);
});
test('should bfloat16 accept number', () => {
@@ -175,8 +174,7 @@ describe('number', () => {
})).serializer;
const input = fory.serialize({ a: 1.5 }, serializer);
const result = fory.deserialize(input);
- expect(result.a).toBeInstanceOf(BFloat16);
- expect(result.a.toFloat32()).toBeCloseTo(1.5, 2);
+ expect(result.a).toBeCloseTo(1.5, 2);
});
test('should bfloat16 NaN work', () => {
@@ -188,8 +186,7 @@ describe('number', () => {
})).serializer;
const input = fory.serialize({ a: NaN }, serializer);
const result = fory.deserialize(input);
- expect(result.a).toBeInstanceOf(BFloat16);
- expect(Number.isNaN(result.a.toFloat32())).toBe(true);
+ expect(Number.isNaN(result.a)).toBe(true);
});
test('should bfloat16 Infinity work', () => {
@@ -201,8 +198,7 @@ describe('number', () => {
})).serializer;
const input = fory.serialize({ a: Infinity }, serializer);
const result = fory.deserialize(input);
- expect(result.a).toBeInstanceOf(BFloat16);
- expect(result.a.toFloat32()).toBe(Infinity);
+ expect(result.a).toBe(Infinity);
});
test('should bfloat16 zero and neg zero round-trip', () => {
@@ -215,10 +211,10 @@ describe('number', () => {
})).serializer;
const input = fory.serialize({ a: 0, b: -0 }, serializer);
const result = fory.deserialize(input);
- expect(result.a.toFloat32()).toBe(0);
- expect(result.b.toFloat32()).toBe(-0);
- expect(1 / result.a.toFloat32()).toBe(Infinity);
- expect(1 / result.b.toFloat32()).toBe(-Infinity);
+ expect(result.a).toBe(0);
+ expect(result.b).toBe(-0);
+ expect(1 / result.a).toBe(Infinity);
+ expect(1 / result.b).toBe(-Infinity);
});
test('should uint8 work', () => {
@@ -305,4 +301,3 @@ describe('number', () => {
expect(result).toEqual({ a: 1n });
});
});
-
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]