Program Listing for File hash.h

Return to documentation for file (liberate/cpp/hash.h)

/*
 * This file is part of liberate.
 *
 * Author(s): Jens Finkhaeuser <jens@finkhaeuser.de>
 *
 * Copyright (c) 2014-2015 Unwesen Ltd.
 * Copyright (c) 2016-2021 Jens Finkhaeuser.
 * Copyright (c) 2022 Interpeer gUG (haftungsbeschränkt)
 *
 * SPDX-License-Identifier: GPL-3.0-only
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef LIBERATE_CPP_HASH_H
#define LIBERATE_CPP_HASH_H

#ifndef __cplusplus
#error You are trying to include a C++ only header file
#endif

#include <liberate.h>

#include <functional>
#include <cstddef>

#define LIBERATE_MAKE_HASHABLE(type) \
  namespace std { \
    template <> struct hash<type> { \
      std::size_t operator()(type const & t) const noexcept { \
        return t.hash(); \
      } \
    }; \
  }


namespace liberate::cpp {

inline void
hash_combine(std::size_t & seed, std::size_t const & value)
{
  seed ^= value + 0x9e3779b9
    + (seed << 6) + (seed >> 2);
}


template <typename T>
inline std::size_t
multi_hash(T const & t)
{
  return std::hash<T>()(t);
}

template <typename T0, typename... Ts>
inline std::size_t
multi_hash(T0 const & t0, Ts && ... ts)
{
  std::size_t seed = multi_hash(t0);
  if constexpr (0 == sizeof...(ts)) {
    return seed;
  }

  std::size_t remainder = multi_hash(std::forward<Ts>(ts)...);

  hash_combine(seed, remainder);
  return seed;
}


template <typename iterT>
inline std::size_t
range_hash(iterT const & begin, iterT const & end)
{
  iterT cur = begin;
  std::size_t hash = 0;

  std::hash<typename std::iterator_traits<iterT>::value_type> hasher;
  for ( ; cur != end ; ++cur) {
    hash_combine(hash, hasher(*cur));
  }

  return hash;
}


} // namespace liberate::cpp

#endif // guard