diff --git a/avif.odin b/avif.odin index 46f658d..a4e7419 100644 --- a/avif.odin +++ b/avif.odin @@ -7,7 +7,7 @@ import "core:encoding/endian" import "core:io" import "core:strings" -Error :: image.Error +//Error :: image.Error //Image :: image.Image Options :: image.Options @@ -130,14 +130,14 @@ read_box :: proc(img: ^Image, reader: ^Reader) -> (err: io.Error) { } // if the Box has a size 0 then it's the last Box, parse it and return EOF - if reader.size == 0 { + if reader.box.size == 0 { err = .EOF } - fmt.println("box size:", reader.size) - fmt.println("type:", reader.type) + fmt.println("box size:", reader.box.size) + fmt.println("type:", reader.box.type) - #partial switch reader.type { + #partial switch reader.box.type { case .FTYP: read_ftyp(img, reader) case .META: @@ -164,6 +164,8 @@ read_box :: proc(img: ^Image, reader: ^Reader) -> (err: io.Error) { read_colr(reader) case .IPMA: read_ipma(reader) + case .MDAT: + read_mdat(reader) case: // Skip unknown boxes skip_box(reader) @@ -172,6 +174,15 @@ read_box :: proc(img: ^Image, reader: ^Reader) -> (err: io.Error) { return err } +@(private) +read_mdat :: proc(reader: ^Reader) { + // TODO: + read_obu(reader) + read_obu(reader) + read_obu(reader) + read_obu(reader) +} + @(private) read_ipma :: proc(reader: ^Reader) { vaf, _ := read_bitfield(reader, VersionAndFlags) diff --git a/box.odin b/box.odin index 4da6315..8cf0e4e 100644 --- a/box.odin +++ b/box.odin @@ -3,12 +3,14 @@ package avif import "core:encoding/endian" import "core:fmt" import "core:io" +import "core:math" +import "core:image" import "core:strings" import "core:unicode/utf8" BOX_HEADER_SIZE :: 8 // 4 for box size, 4 for box type -_BoxError :: enum { +BoxError :: enum { ReadExceedsBox, } @@ -33,125 +35,151 @@ BoxType :: enum u32 { CLLI = 'c' << 24 | 'l' << 16 | 'l' << 8 | 'i', // Content Light Level Info } -BoxError :: union { +Error :: union { io.Error, - _BoxError, + BoxError, + OBUError, + image.General_Image_Error, } Box :: struct { size: u32, type: BoxType, + pos: i64, } Reader :: struct { - using current_box: Box, + box: Box, s: []byte, // read-only buffer i: i64, // current reading index - box_pos: i64, // Byte index for the Box + bits_read_in_byte: u8, } reader_init :: proc(r: ^Reader, s: []byte) { r.s = s r.i = 0 - r.box_pos = 0 + r.box.pos = 0 } -read_header :: proc(r: ^Reader) -> (err: BoxError) { - r.box_pos = 0 - r.size = read_u32be(r) or_return +read_header :: proc(r: ^Reader) -> (err: Error) { + r.box.pos = 0 + r.box.size = read_u32be(r) or_return type := read_u32be(r) or_return - r.type = transmute(BoxType)type + r.box.type = transmute(BoxType)type return err } -read_byte :: proc(r: ^Reader) -> (byte, BoxError) { +read_bit :: proc(r: ^Reader) -> (bit: byte, err: Error) { if r.i >= i64(len(r.s)) { return 0, .EOF } - if r.box_pos >= i64(r.size) { + if r.box.size != 0 && r.box.pos >= i64(r.box.size) { + return 0, .ReadExceedsBox + } + byte := r.s[r.i] + + // Get the bit that's after however many bits read starting from the MSB in the byte + bits := 8 - (r.bits_read_in_byte + 1) + b := (r.s[r.i:r.i+1][0] & auto_cast math.pow2_f32(bits)) >> bits + r.bits_read_in_byte += 1 + + if r.bits_read_in_byte == 8 { + r.i += 1 + r.box.pos += 1 + r.bits_read_in_byte = 0 + } + + return b, nil +} + +read_byte :: proc(r: ^Reader) -> (byte, Error) { + if r.i >= i64(len(r.s)) { + return 0, .EOF + } + if r.box.size != 0 && r.box.pos >= i64(r.box.size) { return 0, .ReadExceedsBox } b := r.s[r.i] r.i += 1 - r.box_pos += 1 + r.box.pos += 1 return b, nil } -read_u16be :: proc(r: ^Reader) -> (u16, BoxError) { +read_u16be :: proc(r: ^Reader) -> (u16, Error) { if r.i >= i64(len(r.s)) { return 0, .EOF } - if r.box_pos + 2 > i64(r.size) { + if r.box.size != 0 && r.box.pos + 2 > i64(r.box.size) { return 0, .ReadExceedsBox } b := endian.unchecked_get_u16be(r.s[r.i:]) r.i += 2 - r.box_pos += 2 + r.box.pos += 2 return b, nil } -read_u32be :: proc(r: ^Reader) -> (u32, BoxError) { +read_u32be :: proc(r: ^Reader) -> (u32, Error) { if r.i >= i64(len(r.s)) { return 0, .EOF } - if r.size != 0 && r.box_pos + 4 > i64(r.size) { + if r.box.size != 0 && r.box.pos + 4 > i64(r.box.size) { return 0, .ReadExceedsBox } b := endian.unchecked_get_u32be(r.s[r.i:]) r.i += 4 - r.box_pos += 4 + r.box.pos += 4 return b, nil } -read_u64be :: proc(r: ^Reader) -> (u64, BoxError) { +read_u64be :: proc(r: ^Reader) -> (u64, Error) { if r.i >= i64(len(r.s)) { return 0, .EOF } - if r.size != 0 && r.box_pos + 8 > i64(r.size) { + if r.box.size != 0 && r.box.pos + 8 > i64(r.box.size) { return 0, .ReadExceedsBox } b := endian.unchecked_get_u64be(r.s[r.i:]) r.i += 8 - r.box_pos += 8 + r.box.pos += 8 return b, nil } -read_slice :: proc(r: ^Reader, s: []byte) -> (n: int, err: BoxError) { +read_slice :: proc(r: ^Reader, s: []byte) -> (n: int, err: Error) { if r.i >= i64(len(r.s)) { return 0, .EOF } n = copy(s, r.s[r.i:]) - if r.box_pos + i64(n) > i64(r.size) { + if r.box.pos + i64(n) > i64(r.box.size) { return 0, .ReadExceedsBox } r.i += i64(n) - r.box_pos += i64(n) + r.box.pos += i64(n) return } -read_rune :: proc(r: ^Reader) -> (ch: rune, size: int, err: BoxError) { +read_rune :: proc(r: ^Reader) -> (ch: rune, size: int, err: Error) { if r.i >= i64(len(r.s)) { return 0, 0, .EOF } if c := r.s[r.i]; c < utf8.RUNE_SELF { - if r.box_pos >= i64(r.size) { + if r.box.pos >= i64(r.box.size) { return 0, 0, .ReadExceedsBox } r.i += 1 - r.box_pos += 1 + r.box.pos += 1 return rune(c), 1, nil } ch, size = utf8.decode_rune(r.s[r.i:]) - if r.box_pos + i64(size) > i64(r.size) { + if r.box.pos + i64(size) > i64(r.box.size) { return 0, 0, .ReadExceedsBox } r.i += i64(size) - r.box_pos += i64(size) + r.box.pos += i64(size) return } -read_string :: proc(r: ^Reader) -> (str: string, err: BoxError) { +read_string :: proc(r: ^Reader) -> (str: string, err: Error) { if r.i >= i64(len(r.s)) { return "", .EOF } @@ -173,32 +201,39 @@ read_string :: proc(r: ^Reader) -> (str: string, err: BoxError) { } @(private = "file") -read_bitfield_u32 :: proc(r: ^Reader, $T: typeid) -> (T, BoxError) where size_of(T) == 4 { +read_bitfield_u32 :: proc(r: ^Reader, $T: typeid) -> (T, Error) where size_of(T) == 4 { b, err := read_u32be(r) return T(b), err } @(private = "file") -read_bitfield_u16 :: proc(r: ^Reader, $T: typeid) -> (T, BoxError) where size_of(T) == 2 { +read_bitfield_u16 :: proc(r: ^Reader, $T: typeid) -> (T, Error) where size_of(T) == 2 { b, err := read_u16be(r) return T(b), err } +@(private = "file") +read_bitfield_u8 :: proc(r: ^Reader, $T: typeid) -> (T, Error) where size_of(T) == 1 { + b, err := read_byte(r) + return T(b), err +} + read_bitfield :: proc { + read_bitfield_u8, read_bitfield_u16, read_bitfield_u32, } skip_box :: proc(r: ^Reader) { - fmt.printfln("SKIPPED! %v with size %d", r.type, r.size) - reader_seek(r, auto_cast r.size - BOX_HEADER_SIZE, .Current) + fmt.printfln("SKIPPED! %v with size %d", r.box.type, r.box.size) + reader_seek(r, auto_cast r.box.size - BOX_HEADER_SIZE, .Current) } remaining_box_size :: proc(r: ^Reader) -> i64 { - return i64(r.size) - r.box_pos + return i64(r.box.size) - r.box.pos } -reader_seek :: proc(r: ^Reader, offset: i64, whence: io.Seek_From) -> (i64, BoxError) { +reader_seek :: proc(r: ^Reader, offset: i64, whence: io.Seek_From) -> (i64, Error) { abs: i64 switch whence { case .Start: diff --git a/obu.odin b/obu.odin index dbddf43..92314c8 100644 --- a/obu.odin +++ b/obu.odin @@ -1,5 +1,6 @@ package avif +import "core:fmt" import "core:io" OBUType :: enum u8 { @@ -14,17 +15,76 @@ OBUType :: enum u8 { PADDING = 15, } -// TODO: write a nice bitstream reader -// ??? Still don't know how I want this to work -BitstreamReader :: struct { - data: []byte, - pos: i64, // Number of bits read from the data slice +OBUError :: enum { + ReservedOBU, +} + +ColorPrimaries :: enum u8 { + BT_709 = 1, + UNSPECIFIED = 2, + BT_470_M = 4, + BT_470_B_G = 5, + BT_601 = 6, + SMPTE_240 = 7, + GENERIC_FILM = 8, + BT_2020 = 9, + XYZ = 10, + SMPTE_431 = 11, + SMPTE_432 = 12, + EBU_3213 = 22, +} + +TransferCharacteristic :: enum u8 { + RESERVED_0 = 0, + BT_709 = 1, + UNSPECIFIED = 2, + RESERVED_3 = 3, + BT_470_M = 4, + BT_470_B_G = 5, + BT_601 = 6, + SMPTE_240 = 7, + LINEAR = 8, + LOG_100 = 9, + LOG_100_SQRT10 = 10, + IEC_61966 = 11, + BT_1361 = 12, + SRGB = 13, + BT_2020_10_BIT = 14, + BT_2020_12_BIT = 15, + SMPTE_2084 = 16, + SMPTE_428 = 17, + HLG = 18, +} + +MatrixCoefficient :: enum u8 { + IDENTITY = 0, + BT_709 = 1, + UNSPECIFIED = 2, + RESERVED_3 = 3, + FCC = 4, + BT_470_B_G = 5, + BT_601 = 6, + SMPTE_240 = 7, + SMPTE_YCGCO = 8, + BT_2020_NCL = 9, + BT_2020_CL = 10, + SMPTE_2085 = 11, + CHROMAT_NCL = 12, + CHROMAT_CL = 13, + ICTCP = 14, +} + +ChromeSamplePosition :: enum u8 { + UNKNOWN = 0, + VERTICAL = 1, + COLOCATED = 2, + RESERVED = 3, } OBUHeader :: bit_field u8 { obu_reserved: u8 | 1, - obu_has_size_field: u8 | 1, - obu_extension_flag: u8 | 1, + obu_has_size_field: b8 | 1, + obu_extension_flag: b8 | 1, obu_type: OBUType | 4, obu_forbidden_bit: u8 | 1, } @@ -35,29 +95,361 @@ OBUExtensionHeader :: bit_field u8 { temporal_id: u8 | 3, } -read_bit :: proc() -> b8 { - // TODO: idfk - // This should read a single bit from the bitstream and advance the bitstream position by 1 +read_obu :: proc(r: ^Reader) -> (err: Error) { + header := read_bitfield(r, OBUHeader) or_return + size: u64 - return false + fmt.println(header) + + if header.obu_extension_flag { + ext_header := read_bitfield(r, OBUExtensionHeader) or_return + + fmt.println(ext_header) + } + + if header.obu_has_size_field { + size = leb128(r) + } else { + // TODO: is this correct ??? + // The spec is NOT clear about wtf sz is, so I assume it's the box size without the header. + // It's also possibly the remaining box size, we'll have to check how other decoders do it. + size = u64(r.box.size - BOX_HEADER_SIZE - 1 - u32(header.obu_extension_flag)) + } + + // TODO: get bit position + //start_pos := get_position() + + //// TODO: + //if header.obu_type != .SEQUENCE_HEADER && header.obu_type != .TEMPORAL_DELIMITER && OperatingPointIdc != 0 && header.obu_extension_flag == 1 { + // in_temporal_layer := (OperatingPointIdc >> temporal_id) & 1 + // in_spatial_layer := (OperatingPointIdc >> (spatial_id + 8)) & 1 + + // if in_temporal_layer == 0 || in_spatial_layer == 0 { + // drop_obu() + // return + // } + //} + + fmt.println("OBU size:", size) + + if header.obu_type != .SEQUENCE_HEADER && + header.obu_type != .TEMPORAL_DELIMITER && + header.obu_type != .FRAME_HEADER && + header.obu_type != .TILE_GROUP && + header.obu_type != .METADATA && + header.obu_type != .FRAME && + header.obu_type != .REDUNDANT_FRAME_HEADER && + header.obu_type != .TILE_LIST && + header.obu_type != .PADDING { + return .ReservedOBU + } + + #partial switch header.obu_type { + case .TEMPORAL_DELIMITER: + // do nothing. the temporal OBU has an empty payload + case .SEQUENCE_HEADER: + parse_sequence_header_obu(r) + case .FRAME: + // TODO: + } + + // TODO: + //current_pos := get_position() + //payload_bits := current_pos - start_pos + + //if size > 0 && header.obu_type != .TILE_GROUP && header.obu_type != .TILE_LIST && header.obu_type != .FRAME { + // trailing_bits(size * 8 - payload_bits) + //} + + return nil } -f :: proc(n: int) -> u64 { +//timing_info :: proc(r: ^Reader) { +// num_units_in_display_tick = f(r, 32) +// time_scale = f(r, 32) +// equal_picture_interval = f(r, 32) +// if equal_picture_interval == 1 { +// num_ticks_per_picture_minus_1 = uvlc(r) +// } +//} +// +//decoder_model_info :: proc(r: ^Reader) { +// buffer_delay_length_minus_1 = f(r, 5) +// num_units_in_decoding_tick = f(r, 32) +// buffer_removal_time_length_minus_1 = f(r, 5) +// frame_presentation_time_length_minus_1 = f(r, 5) +//} +// +//operating_parameters_info :: proc(r: ^Reader, op: u8) { +// n = buffer_delay_length_minus_1 + 1 +// decoder_buffer_delay[op] = f(r, n) +// encoder_buffer_delay[op] = f(r, n) +// low_delay_mode_flag[op] = f(r, 1) +//} +// +//color_config :: proc(r: ^Reader) { +// high_bitdepth = f(r, 1) +// +// if seq_profile == 2 && high_bitdepth == 1 { +// twelve_bit = f(r, 1) +// BitDepth = twelve_bit == 1 ? 12 : 10 +// } else if seq_profile <= 2 { +// BitDepth = high_bitdepth == 1 ? 10 : 8 +// } +// +// if seq_profile == 1 { +// mono_chrome = 0 +// } else { +// mono_chrome = f(r, 1) +// } +// +// num_planes = mono_chrome == 1 ? 1 : 3 +// color_description_present_flag = f(r, 1) +// +// if color_description_present_flag == 1 { +// color_primaries = auto_cast f(r, 8) +// transfer_characteristic = auto_cast f(r, 8) +// matrix_coefficients = auto_cast f(r, 8) +// } else { +// color_primaries = .UNSPECIFIED +// transfer_characteristic = .UNSPECIFIED +// matrix_coefficients = .UNSPECIFIED +// } +// +// if mono_chrome == 1 { +// color_range = f(r, 1) +// subsampling_x = 1 +// subsampling_y = 1 +// chroma_sample_position = .UNKNOWN +// separate_uv_delta_q = 0 +// return +// } else if color_primaries == .BT_709 && transfer_characteristic == .SRGB && matrix_coefficients == .IDENTITY { +// color_range = 1 +// subsampling_x = 0 +// subsampling_y = 0 +// } else { +// color_range = f(r, 1) +// +// if seq_profile == 0 { +// subsampling_x = 1 +// subsampling_y = 1 +// } else if seq_profile == 1 { +// subsampling_x = 0 +// subsampling_y = 0 +// } else { +// if BitDepth == 12 { +// subsampling_x = f(r, 1) +// +// if subsampling_x == 1 { +// subsampling_y = f(r, 1) +// } else { +// subsampling_y = 0 +// } +// } else { +// subsampling_x = 1 +// subsampling_y = 0 +// } +// } +// +// if subsampling_x == 1 && subsampling_y == 1 { +// chroma_sample_position = auto_cast f(r, 2) +// } +// } +// +// separate_uv_delta_q = f(r, 1) +//} + +parse_sequence_header_obu :: proc(r: ^Reader) { + seq_profile := f(r, 3) + still_picture := f(r, 1) + reduced_still_picture_header := f(r, 1) + + timing_info_present_flag: u8 + decoder_model_info_present_flag: u8 + initial_display_delay_present_flag: u8 + operating_points_cnt_minus_1: u8 + + if reduced_still_picture_header == 1 { + // TODO: should these be saved as state ?? + timing_info_present_flag = 0 + decoder_model_info_present_flag = 0 + initial_display_delay_present_flag = 0 + operating_points_cnt_minus_1 = 0 + //operating_point_idc[ 0 ] = 0 + //seq_level_idx[ 0 ] + //seq_tier[ 0 ] = 0 + //decoder_model_present_for_this_op[ 0 ] = 0 + //initial_display_delay_present_for_this_op[ 0 ] = 0 + } else { + //timing_info_present_flag = auto_cast f(r, 1) + + //if timing_info_present_flag == 1 { + // timing_info(r) + + // decoder_model_info_present_flag = auto_cast f(r, 1) + // if decoder_model_info_present_flag == 1 { + // decoder_model_info(r) + // } + //} else { + // decoder_model_info_present_flag = 0 + //} + + //initial_display_delay_present_flag = auto_cast f(r, 1) + //operating_points_cnt_minus_1 = auto_cast f(r, 5) + + //for i in 0 ..=operating_points_cnt_minus_1 { + // operating_point_idc[i] = f(r, 12) + // seq_level_idx[i] = f(r, 5) + + // if seq_level_idx[i] > 7 { + // seq_tier[i] = f(r, 1) + // } else { + // seq_tier[i] = 0 + // } + + // if decoder_model_info_present_flag == 1 { + // decoder_model_present_for_this_op[i] = f(r, 1) + // if decoder_model_present_for_this_op[i] == 1 { + // operating_parameters_info(r, i) + // } + // } else { + // decoder_model_present_for_this_op[i] = 0 + // } + + // if initial_display_delay_present_flag == 1 { + // initial_display_delay_present_for_this_op[i] = f(r, 1) + // if initial_display_delay_present_for_this_op[i] == 1 { + // initial_display_delay_minus_1[i] = f(r, 4) + // } + // } + //} + } + + fmt.println("seq_profile:", seq_profile) + fmt.println("still_picture:", still_picture) + fmt.println("reduced_still_picture_header:", reduced_still_picture_header) + + fmt.println("timing_info_present_flag:", timing_info_present_flag) + fmt.println("decoder_model_info_present_flag:", decoder_model_info_present_flag) + fmt.println("initial_display_delay_present_flag:", initial_display_delay_present_flag) + fmt.println("operating_points_cnt_minus_1:", operating_points_cnt_minus_1) + + //operating_point := choose_operating_point() + //operating_point_idc_one := operating_point_idc[operating_point] + frame_width_bits_minus_1 := f(r, 4) + frame_height_bits_minus_1 := f(r, 4) + n := frame_width_bits_minus_1 + 1 + max_frame_width_minus_1 := f(r, auto_cast n) + n = frame_height_bits_minus_1 + 1 + max_frame_height_minus_1 := f(r, auto_cast n) + + frame_id_numbers_present_flag: u8 + delta_frame_id_length_minus_2: u8 + additional_frame_id_length_minus_1: u8 + + if reduced_still_picture_header == 1 { + frame_id_numbers_present_flag = 0 + } else { + frame_id_numbers_present_flag = auto_cast f(r, 1) + } + + if frame_id_numbers_present_flag == 1 { + delta_frame_id_length_minus_2 = auto_cast f(r, 4) + additional_frame_id_length_minus_1 = auto_cast f(r, 3) + } + + use_128x128_superblock := f(r, 1) + enable_filter_intra := f(r, 1) + enable_intra_edge_filter := f(r, 1) + + fmt.println("frame_width_bits_minus_1:", frame_width_bits_minus_1) + fmt.println("frame_height_bits_minus_1:", frame_height_bits_minus_1) + fmt.println("max_frame_width_minus_1:", max_frame_width_minus_1) + fmt.println("max_frame_height_minus_1:", max_frame_height_minus_1) + + fmt.println("frame_id_numbers_present_flag:", frame_id_numbers_present_flag) + fmt.println("delta_frame_id_length_minus_2:", delta_frame_id_length_minus_2) + fmt.println("additional_frame_id_length_minus_1:", additional_frame_id_length_minus_1) + + fmt.println("use_128x128_superblock:", use_128x128_superblock) + fmt.println("enable_filter_intra:", enable_filter_intra) + fmt.println("enable_intra_edge_filter:", enable_intra_edge_filter) + + //if reduced_still_picture_header == 1 { + // enable_interintra_compound = 0 + // enable_masked_compound = 0 + // enable_warped_motion = 0 + // enable_dual_filter = 0 + // enable_order_hint = 0 + // enable_jnt_comp = 0 + // enable_ref_frame_mvs = 0 + // seq_force_screen_content_tools = SELECT_SCREEN_CONTENT_TOOLS + // seq_force_integer_mv = SELECT_INTEGER_MV + // OrderHintBits = 0 + //} else { + // enable_interintra_compount = f(r, 1) + // enable_masked_compound = f(r, 1) + // enable_warped_motion = f(r, 1) + // enable_dual_filter = f(r, 1) + // enable_order_hint = f(r, 1) + // if enable_order_hint == 1 { + // enable_jnt_comp = f(r, 1) + // enable_ref_frame_mvs = f(r, 1) + // } else { + // enable_jnt_comp = 0 + // enable_ref_frame_mvs = 0 + // } + + // seq_choose_screen_content_tools = f(r, 1) + // if seq_choose_screen_content_tools == 1 { + // seq_force_screen_content_tools = SELECT_SCREEN_CONTENT_TOOLS + // } else { + // seq_force_screen_content_tools = f(r, 1) + // } + + // if seq_force_screen_content_tools > 0 { + // seq_choose_integer_mv = f(r, 1) + // if seq_choose_integer_mv == 1 { + // seq_force_integer_mv = SELECT_INTEGER_MV + // } else { + // seq_force_integer_mv = f(r, 1) + // } + // } else { + // seq_force_integer_mv = SELECT_INTEGER_MV + // } + + // if enable_order_hint == 1 { + // order_hint_bits_minus_1 = f(r, 3) + // OrderHintBits = order_hint_bits_minus_1 + 1 + // } else { + // OrderHintBits = 0 + // } + //} + + //enable_superres = f(r, 1) + //enable_cdef = f(r, 1) + //enable_restoration = f(r, 1) + //color_config() + //film_grain_params_present = f(r, 1) +} + +f :: proc(r: ^Reader, n: int) -> u64 { x: u64 = 0 for i in 0 ..< n { - x = 2 * x + auto_cast read_bit() + // TODO: maybe get rid of or_break and propagate the error?? + x = 2 * x + auto_cast read_bit(r) or_break } return x } -leb128 :: proc() -> u64 { +leb128 :: proc(r: ^Reader) -> u64 { value: u64 = 0 leb128_bytes := 0 for i: u64 = 0; i < 8; i += 1 { - leb128_byte := f(8) + leb128_byte := f(r, 8) value |= ((leb128_byte & 0x7f) << (i * 7)) leb128_bytes += 1 @@ -68,3 +460,22 @@ leb128 :: proc() -> u64 { return value } + +uvlc :: proc(r: ^Reader) -> u64 { + leading_zeros: u64 = 0 + + for { + done := f(r, 1) + if done == 1 { + break + } + leading_zeros += 1 + } + + if leading_zeros >= 32 { + return (1 << 32) - 1 + } + + value := f(r, auto_cast leading_zeros) + return value + (1 << leading_zeros) - 1 +}