2

頭をconstexpr悩ませた後、Jesteress ハッシュ アルゴリズムをなんとか 化することができました。cjesteress()ただし、コンパイラはin などの呼び出しから定数を生成することを拒否しますが、 と の両方をstd::cout << cjesteress("test) << std::endl;使用して呼び出しのコードを生成します。私は何を間違えましたか?clang-3.3gcc-4.8.1

#include <cstdint>

#include <cstring>

#include <string>

#define ROL(x, n) (((x) << (n)) | ((x) >> (32-(n))))

namespace detail
{

constexpr std::uint32_t const PRIME(709607u);

//////////////////////////////////////////////////////////////////////////////
inline constexpr std::size_t cstrlen(char const* const p,
  std::size_t const s = 0)
{
  return *p ? cstrlen(p + 1, s + 1) : s;
}

//////////////////////////////////////////////////////////////////////////////
inline constexpr std::uint32_t case4(char const*& p, std::size_t const wrdlen,
  std::uint32_t hash32)
{
  return wrdlen & sizeof(std::uint32_t)
    ? hash32 = (hash32 ^ *(std::uint32_t*)p) * PRIME,
      p += sizeof(std::uint32_t),
      hash32
    : hash32;
}

//////////////////////////////////////////////////////////////////////////////
inline constexpr std::uint32_t case2(char const*& p, std::size_t const wrdlen,
  std::uint32_t hash32)
{
  return wrdlen & sizeof(std::uint16_t)
    ? hash32 = (hash32 ^ *(std::uint16_t*)p) * PRIME,
      p += sizeof(std::uint16_t),
      hash32
    : hash32;
}

//////////////////////////////////////////////////////////////////////////////
inline constexpr std::uint32_t case1(char const* p, std::size_t const wrdlen,
  std::uint32_t hash32)
{
  return wrdlen & 1
    ? hash32 = (hash32 ^ *p) * PRIME
    : hash32;
}

//////////////////////////////////////////////////////////////////////////////
inline constexpr std::uint32_t cjesteress(char const* p, std::size_t wrdlen,
  std::uint32_t hash32)
{
  return wrdlen >= 2 * sizeof(std::uint32_t)
    ? cjesteress(p + 2 * sizeof(std::uint32_t),
        wrdlen - 2 * sizeof(std::uint32_t),
        (hash32 ^ (ROL(*(std::uint32_t *)p, 5) ^ *(std::uint32_t *)(p + 4)))
          * ::detail::PRIME)
    : (hash32 = ::detail::case4(p, wrdlen, hash32),
      hash32 = ::detail::case2(p, wrdlen, hash32),
      hash32 = ::detail::case1(p, wrdlen, hash32),
      hash32 ^ (hash32 >> 16));
}

}

//////////////////////////////////////////////////////////////////////////////
inline constexpr std::uint32_t cjesteress(char const* const p)
{
  return ::detail::cjesteress(p, ::detail::cstrlen(p), 2166136261u);
}

//////////////////////////////////////////////////////////////////////////////
inline constexpr std::uint32_t cjesteress(char const* const p,
  std::size_t const wrdlen)
{
  return ::detail::cjesteress(p, wrdlen, 2166136261u);
}

エラーは不可解です:

testjesteress.cpp:16:33:   in constexpr expansion of
'cjesteress(((const char*)"1234567890"))'
../resource/jesteress.hpp:78:67:   in constexpr expansion of
'detail::cjesteress(((const char*)p), detail::cstrlen(((const
char*)p), 0ul), 2166136261u)' testjesteress.cpp:16:33: error:
accessing value of '"1234567890"' through a 'uint32_t {aka unsigned
int}' glvalue in a constant expression
     case cjesteress("1234567890"):
                                 ^

編集:すべてのおかげで、これは実用的な実装です:

#include <cstdint>

#include <cstring>

#define ROL(x, n) (((x) << (n)) | ((x) >> (32-(n))))

namespace detail
{

static constexpr std::uint32_t const PRIME(709607u);

//////////////////////////////////////////////////////////////////////////////
inline constexpr std::size_t cstrlen(char const* const p,
  std::size_t const s = 0)
{
  return *p ? cstrlen(p + 1, s + 1) : s;
}

//////////////////////////////////////////////////////////////////////////////
inline constexpr std::uint32_t p2u32(char const* const p)
{
  return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
}

//////////////////////////////////////////////////////////////////////////////
inline constexpr std::uint16_t p2u16(char const* const p)
{
  return p[0] | p[1] << 8;
}

//////////////////////////////////////////////////////////////////////////////
inline constexpr std::uint32_t case0(std::uint32_t const hash32)
{
  return hash32 ^ (hash32 >> 16);
}

//////////////////////////////////////////////////////////////////////////////
inline constexpr std::uint32_t case1(char const* const p,
  std::size_t const wrdlen, std::uint32_t const hash32)
{
  return wrdlen & 1
    ? case0((hash32 ^ *p) * PRIME)
    : case0(hash32);
}

//////////////////////////////////////////////////////////////////////////////
inline constexpr std::uint32_t case2(char const* const p,
  std::size_t const wrdlen, std::uint32_t const hash32)
{
  return wrdlen & sizeof(std::uint16_t)
    ? case1(p + sizeof(std::uint16_t), wrdlen, (hash32 ^ p2u16(p)) * PRIME)
    : case1(p, wrdlen, hash32);
}

//////////////////////////////////////////////////////////////////////////////
inline constexpr std::uint32_t case4(char const* const p,
  std::size_t const wrdlen, std::uint32_t const hash32)
{
  return wrdlen & sizeof(std::uint32_t)
    ? case2(p + sizeof(std::uint32_t), wrdlen, (hash32 ^ p2u32(p)) * PRIME)
    : case2(p, wrdlen, hash32);
}

//////////////////////////////////////////////////////////////////////////////
inline constexpr std::uint32_t cjesteress(char const* const p,
  std::size_t const wrdlen, std::uint32_t const hash32)
{
  return wrdlen >= 2 * sizeof(std::uint32_t)
    ? cjesteress(p + 2 * sizeof(std::uint32_t),
        wrdlen - 2 * sizeof(std::uint32_t),
        (hash32 ^ (ROL(p2u32(p), 5) ^ p2u32(p + 4)))
          * ::detail::PRIME)
    : ::detail::case4(p, wrdlen, hash32);
}

}

//////////////////////////////////////////////////////////////////////////////
inline constexpr std::uint32_t cjesteress(char const* const p)
{
  return ::detail::cjesteress(p, ::detail::cstrlen(p), 2166136261u);
}

//////////////////////////////////////////////////////////////////////////////
inline constexpr std::uint32_t cjesteress(char const* const p,
  std::size_t const wrdlen)
{
  return ::detail::cjesteress(p, wrdlen, 2166136261u);
}
4

1 に答える 1