// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#ifndef VM_UTILS_H_
#define VM_UTILS_H_

#include "vm/assert.h"

namespace dart {

class Utils {
 public:
  template<typename T>
  static inline T Minimum(T x, T y) {
    return x < y ? x : y;
  }

  template<typename T>
  static inline T Maximum(T x, T y) {
    return x > y ? x : y;
  }

  template<typename T>
  static inline T Abs(T x) {
    if (x < 0) return -x;
    return x;
  }

  template<typename T>
  static inline bool IsPowerOfTwo(T x) {
    return (x & (x - 1)) == 0;
  }

  template<typename T>
  static inline int ShiftForPowerOfTwo(T x) {
    ASSERT(IsPowerOfTwo(x));
    int num_shifts = 0;
    while (x > 1) {
      num_shifts++;
      x = x >> 1;
    }
    return num_shifts;
  }

  template<typename T>
  static inline bool IsAligned(T x, int n) {
    ASSERT(IsPowerOfTwo(n));
    return (x & (n - 1)) == 0;
  }

  template<typename T>
  static inline bool IsAligned(T* x, int n) {
    return IsAligned(reinterpret_cast<uword>(x), n);
  }

  template<typename T>
  static inline T RoundDown(T x, int n) {
    ASSERT(IsPowerOfTwo(n));
    return (x & -n);
  }

  template<typename T>
  static inline T* RoundDown(T* x, int n) {
    return reinterpret_cast<T*>(RoundDown(reinterpret_cast<uword>(x), n));
  }

  template<typename T>
  static inline T RoundUp(T x, int n) {
    return RoundDown(x + n - 1, n);
  }

  template<typename T>
  static inline T* RoundUp(T* x, int n) {
    return reinterpret_cast<T*>(RoundUp(reinterpret_cast<uword>(x), n));
  }

  static uint32_t RoundUpToPowerOfTwo(uint32_t x);
  static int CountOneBits(uint32_t x);

  // Computes a hash value for the given string.
  static uint32_t StringHash(const char* data, int length);

  // Computes a hash value for the given word.
  static uint32_t WordHash(word key);

  // Check whether an N-bit two's-complement representation can hold value.
  static inline bool IsInt(int N, word value) {
    ASSERT((0 < N) && (N < kBitsPerWord));
    word limit = static_cast<word>(1) << (N - 1);
    return (-limit <= value) && (value < limit);
  }

  static inline bool IsUint(int N, word value) {
    ASSERT((0 < N) && (N < kBitsPerWord));
    word limit = static_cast<word>(1) << N;
    return (0 <= value) && (value < limit);
  }

  // Check whether the magnitude of value fits in N bits, i.e., whether an
  // (N+1)-bit sign-magnitude representation can hold value.
  static inline bool IsAbsoluteUint(int N, word value) {
    ASSERT((0 < N) && (N < kBitsPerWord));
    if (value < 0) value = -value;
    return IsUint(N, value);
  }

  static inline int32_t Low16Bits(int32_t value) {
    return static_cast<int32_t>(value & 0xffff);
  }

  static inline int32_t High16Bits(int32_t value) {
    return static_cast<int32_t>(value >> 16);
  }

  static inline int32_t Low32Bits(int64_t value) {
    return static_cast<int32_t>(value);
  }

  static inline int32_t High32Bits(int64_t value) {
    return static_cast<int32_t>(value >> 32);
  }

  static inline int64_t LowHighTo64Bits(uint32_t low, int32_t high) {
    return (static_cast<int64_t>(high) << 32) | (low & 0x0ffffffffLL);
  }

  static bool IsDecimalDigit(char c) {
    return ('0' <= c) && (c <= '9');
  }

  static bool IsHexDigit(char c) {
    return IsDecimalDigit(c)
          || (('A' <= c) && (c <= 'F'))
          || (('a' <= c) && (c <= 'f'));
  }

  static int HexDigitToInt(char c) {
    ASSERT(IsHexDigit(c));
    if (IsDecimalDigit(c)) return c - '0';
    if (('A' <= c) && (c <= 'F')) return 10 + (c - 'A');
    return 10 + (c - 'a');
  }

  static char IntToHexDigit(int i) {
    ASSERT(0 <= i && i < 16);
    if (i < 10) return static_cast<char>('0' + i);
    return static_cast<char>('A' + (i - 10));
  }
};

}  // namespace dart

#endif  // VM_UTILS_H_
