blob: b0b3097b61ee184ace43c13d06d9cbb1e6e6a6a5 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "extend_bits.h"
#include <zircon/assert.h>
uint64_t ExtendBits(uint64_t nearby_extended, uint64_t to_extend, uint32_t to_extend_low_order_bit_count) {
ZX_DEBUG_ASSERT(to_extend_low_order_bit_count == 64 ||
to_extend < (static_cast<uint64_t>(1) << to_extend_low_order_bit_count));
// Shift up to the top bits of the uint64_t, so we can exploit subtraction that underflows to
// compute distance regardless of recent overflow of a and/or b. We could probably also do this
// by chopping off some top order bits after subtraction, but somehow this makes more sense to me.
// This way, we're sorta just creating a and b which are each 64 bit counters with 64 bit natural
// overflow, so we can figure out the logical above/below relationship between nearby_extended and
// to_extend.
uint64_t a = nearby_extended << (64 - to_extend_low_order_bit_count);
uint64_t b = to_extend << (64 - to_extend_low_order_bit_count);
// Is the distance between a and b smaller if we assume b is logically above a, or if we assume
// a is logically above b. We want to assume the option which has a and b closer together in
// distance on a mod ring, as we don't generally know whether to_extend will be logically above or
// logically below nearby_extended.
//
// One of these will be relatively small, and the other will be huge (or both 0). Another way to
// do this is to check if b - a is < 0x8000000000000000.
uint64_t result;
if (b - a <= a - b) {
// offset is logically above (or equal to) last_inserted_offset
result = nearby_extended + ((b - a) >> (64 - to_extend_low_order_bit_count));
} else {
// offset is logically below last_inserted_offset
result = nearby_extended - ((a - b) >> (64 - to_extend_low_order_bit_count));
}
return result;
}