* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* We modify this part of the code based on Apache Flink to implement native execution of Flink operators.
* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
*/
#ifndef MATHUTILS_H
#define MATHUTILS_H
#include <stdexcept>
#include <limits>
#include <cstdint>
#include <cassert>
#ifdef DEBUG
#define MYASSERT(f) assert(f)
#else
#define MYASSERT(f) ((void)0)
#endif
class MathUtils {
public:
static int log2floor(int value)
{
if (value == 0) {
throw std::runtime_error("Logarithm of zero is undefined.");
}
return 31 - __builtin_clz(value);
}
static int log2strict(int value)
{
if (value == 0) {
throw std::runtime_error("Logarithm of zero is undefined.");
}
unsigned int uValue = static_cast<unsigned int>(value);
if ((uValue & (uValue - 1)) != 0) {
throw std::invalid_argument("The given value is not a power of two.");
}
return 31 - __builtin_clz(uValue);
}
static int roundDownToPowerOf2(int value)
{
if (value <= 0) {
throw std::invalid_argument("Value must be positive.");
}
return 1 << (31 - __builtin_clz(value));
}
static int checkedDownCast(int64_t value)
{
int downCast = static_cast<int>(value);
if (downCast != value) {
throw std::invalid_argument("Cannot downcast long value to integer.");
}
return downCast;
}
static bool isPowerOf2(int64_t value)
{
uint64_t unsignedValue = static_cast<uint64_t>(value);
return (unsignedValue & (unsignedValue - 1)) == 0;
}
static int jenkinsHash(int code)
{
unsigned int uCode = static_cast<unsigned int>(code);
uCode = (uCode + 0x7ed55d16) + (uCode << 12);
uCode = (uCode ^ 0xc761c23c) ^ (uCode >> 19);
uCode = (uCode + 0x165667b1) + (uCode << 5);
uCode = (uCode + 0xd3a2646c) ^ (uCode << 9);
uCode = (uCode + 0xfd7046c5) + (uCode << 3);
uCode = (uCode ^ 0xb55a4f09) ^ (uCode >> 16);
int hashed = static_cast<int>(uCode);
return hashed >= 0 ? hashed : -(hashed + 1);
}
static int murmurHash(int code)
{
unsigned int uCode = static_cast<unsigned int>(code);
uCode *= 0xcc9e2d51;
uCode = (uCode << 15) | (uCode >> (32 - 15));
uCode *= 0x1b873593;
uCode = (uCode << 13) | (uCode >> (32 - 13));
uCode = uCode * 5 + 0xe6546b64;
uCode ^= 4;
int hashed = bitMix(uCode);
if (hashed >= 0) {
return hashed;
} else if (hashed != std::numeric_limits<int>::min()) {
return -hashed;
} else {
return 0;
}
}
static int roundUpToPowerOfTwo(int x)
{
unsigned int ux = static_cast<unsigned int>(x);
ux = ux - 1;
ux |= ux >> 1;
ux |= ux >> 2;
ux |= ux >> 4;
ux |= ux >> 8;
ux |= ux >> 16;
return static_cast<int>(ux + 1);
}
static int longToIntWithBitMixing(int64_t in)
{
uint64_t unsignedIn = static_cast<uint64_t>(in);
unsignedIn = (unsignedIn ^ (unsignedIn >> 30)) * 0xbf58476d1ce4e5b9L;
unsignedIn = (unsignedIn ^ (unsignedIn >> 27)) * 0x94d049bb133111ebL;
unsignedIn = unsignedIn ^ (unsignedIn >> 31);
return static_cast<int>(unsignedIn);
}
static int bitMix(int in)
{
unsigned int unsignedIn = static_cast<unsigned int>(in);
unsignedIn ^= unsignedIn >> 16;
unsignedIn *= 0x85ebca6b;
unsignedIn ^= unsignedIn >> 13;
unsignedIn *= 0xc2b2ae35;
unsignedIn ^= unsignedIn >> 16;
return static_cast<unsigned int>(unsignedIn);
}
static int64_t flipSignBit(int64_t in)
{
uint64_t unsignedIn = static_cast<uint64_t>(in);
return unsignedIn ^ static_cast<uint64_t>(std::numeric_limits<int64_t>::min());
}
static int divideRoundUp(int dividend, int divisor)
{
MYASSERT(dividend >= 0 && "Negative dividend is not supported.");
MYASSERT(divisor > 0 && "Negative or zero divisor is not supported.");
return dividend == 0 ? 0 : (dividend - 1) / divisor + 1;
}
private:
MathUtils() = delete;
};
#endif