uint32_t Hash64Low(const char* s, size_t len) {
  return static_cast<uint32_t>(Hash64(s, len));
}

uint32_t Hash64High(const char* s, size_t len) {
  return static_cast<uint32_t>(Hash64(s, len) >> 32);
}

// Hash the concatenation of the given string with itself.
uint64_t Hash64D(const char* s, size_t len) {
  char buf[8000];
  char* ss = len*2 > sizeof(buf) ? (char*)malloc(len*2) : buf;
  memcpy(ss, s, len);
  memcpy(ss + len, s, len);
  uint64_t h = Hash64(ss, len*2);
  if (ss != buf) free(ss);
  return h;
}

// Hash the concatenation of the given string with itself.
uint32_t Hash64DLow(const char* s, size_t len) {
  return static_cast<uint32_t>(Hash64D(s, len));
}

// Hash the concatenation of the given string with itself.
uint32_t Hash64DHigh(const char* s, size_t len) {
  return static_cast<uint32_t>(Hash64D(s, len) >> 32);
}

// Hash the concatenation of the given string with 3 copies of itself.
uint64_t Hash64Q(const char* s, size_t len) {
  char buf[8000];
  char* ss = len*4 > sizeof(buf) ? (char*)malloc(len*4) : buf;
  memcpy(ss, s, len);
  memcpy(ss + len, s, len);
  memcpy(ss + len*2, ss, len*2);
  uint64_t h = Hash64(ss, len*4);
  if (ss != buf) free(ss);
  return h;
}

// Hash the concatenation of the given string with 3 copies of itself.
uint32_t Hash64QLow(const char* s, size_t len) {
  return static_cast<uint32_t>(Hash64Q(s, len));
}

// Hash the concatenation of the given string with 3 copies of itself.
uint32_t Hash64QHigh(const char* s, size_t len) {
  return static_cast<uint32_t>(Hash64Q(s, len) >> 32);
}
