संकलन समय स्ट्रिंग हैशिंग


100

मैंने कुछ अलग-अलग जगहों पर पढ़ा है कि C ++ 11 के नए स्ट्रिंग साहित्यिकों का उपयोग करने से संभवत: एक स्ट्रिंग के हैश की गणना संभव समय पर की जा सकती है। हालांकि, कोई भी बाहर आने के लिए तैयार नहीं लगता है और कहता है कि यह संभव होगा या यह कैसे किया जाएगा।

  • क्या यह संभव है?
  • ऑपरेटर कैसा दिखेगा?

मैं इस तरह के मामलों में विशेष रूप से रुचि रखता हूं।

void foo( const std::string& value )
{
   switch( std::hash(value) )
   {
      case "one"_hash: one(); break;
      case "two"_hash: two(); break;
      /*many more cases*/
      default: other(); break;
   }
}

नोट: संकलन समय हैश फ़ंक्शन को ठीक वैसा नहीं दिखना है जैसा मैंने लिखा है। मैंने यह अनुमान लगाने की पूरी कोशिश की कि अंतिम समाधान कैसा दिखेगा, लेकिन meta_hash<"string"_meta>::valueएक व्यवहार्य समाधान भी हो सकता है।


मैं कुछ भी खोजने के लिए प्रतीत नहीं कर सकते, लेकिन मैं अपने हैशिंग फ़ंक्शन को विवश करने के लिए देख सकता था।
ल्यूक

4
क्या कोई कंपाइलर है जो पहले से ही उपयोगकर्ता द्वारा परिभाषित शाब्दिक समर्थन करता है? Gcc नहीं करता है ( gcc.gnu.org/projects/cxx0x.html ) और मैंने उन्हें VC10 के लिए उल्लेख नहीं किया है। कंपाइलर समर्थन के बिना यह केवल काम का अनुमान लगा सकता है, लेकिन टेम्प्लेट किए गए उपयोगकर्ता-परिभाषित शाब्दिक रूप से यह संभव होना चाहिए।
जॉर्ज फ्रिट्ज़शे

1
यह प्यारा है लेकिन उपयोगी नहीं है? यदि स्विच मान रनटाइम स्ट्रिंग है, तो आपको टकरावों के लिए भी जांचना होगा। शायद पैकिंग बेहतर है (मेरे जवाब में 9 बिट्स को 64 बिट्स में भरने के लिए एक पैक फ़ंक्शन है)।
u0b34a0f6ae 10

@ u0b34a0f6ae टक्करों की जांच क्यों करें?
क्यूबस्प्ल42

यदि दो मामले मान समान हैं, तो कंपाइलर को एक त्रुटि जारी करनी चाहिए।
मार्क स्टॉरर

जवाबों:


88

यह थोड़ा देर से है, लेकिन मैं एक संकलन-समय CRC32 फ़ंक्शन के उपयोग के साथ लागू करने में सफल रहा constexpr। इसके साथ समस्या यह है कि लेखन के समय, यह केवल जीसीसी के साथ काम करता है और न ही एमएसवीसी और न ही इंटेल कंपाइलर।

यहाँ कोड स्निपेट है:

// CRC32 Table (zlib polynomial)
static constexpr uint32_t crc_table[256] = {
    0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
    0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
    0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
...
};
template<size_t idx>
constexpr uint32_t crc32(const char * str)
{
    return (crc32<idx-1>(str) >> 8) ^ crc_table[(crc32<idx-1>(str) ^ str[idx]) & 0x000000FF];
}

// This is the stop-recursion function
template<>
constexpr uint32_t crc32<size_t(-1)>(const char * str)
{
    return 0xFFFFFFFF;
}

// This doesn't take into account the nul char
#define COMPILE_TIME_CRC32_STR(x) (crc32<sizeof(x) - 2>(x) ^ 0xFFFFFFFF)

enum TestEnum
{
    CrcVal01 = COMPILE_TIME_CRC32_STR("stack-overflow"),
};

CrcVal01 0x335CC04A के बराबर है

आशा है कि यह आपकी मदद करेगा!


4
हाँ बिल्कुल। मैंने इसे पायथन CRC32 रनटाइम एल्गोरिथ्म (zlib से आने वाले) के खिलाफ परीक्षण किया और परिणाम समान हैं। वास्तव में, आप जो हासिल करने की कोशिश कर रहे हैं वह वास्तव में मैं इस तकनीक का उपयोग क्यों कर रहा हूं!
क्लेमेंट JACOB

2
इसे पोस्ट करने के लिए धन्यवाद, यह बहुत उपयोगी है!
तामसे सजेलेई

2
आपको एक संकलित ध्वज याद आ रहा था। इसके अलावा मुझे recursion टेम्पलेट फ़ंक्शन को रोकने में value -1 को size_t में डालना था। अपडेट किया गया संस्करण यहां उपलब्ध है ( क्लैंग
क्लेमेंट JACOB

1
constexprVS2013 में उपलब्ध नहीं है, नवंबर 2013 को छोड़कर CTP blogs.msdn.com/b/vcblog/archive/2013/11/18/…

2
आप दो बार भर्ती कर रहे हैं। इस समाधान में स्ट्रिंग की लंबाई के संबंध में एक घातीय जटिलता है, और कंपाइलर दूसरे कॉल को खत्म करने के लिए पर्याप्त चतुर नहीं है। इस समस्या के संभावित समाधान के लिए अन्य उत्तरों की जाँच करें।
CygnusX1

30

कम से कम and7.1.5 / 3 और 95.19 के मेरे पढ़ने से, निम्नलिखित वैध हो सकता है:

unsigned constexpr const_hash(char const *input) {
    return *input ?
        static_cast<unsigned int>(*input) + 33 * const_hash(input + 1) :
        5381;
}

ऐसा लगता है कि मूल नियमों का पालन does7.1.5 / 3 में किया गया है:

  1. फ़ॉर्म है: "वापसी अभिव्यक्ति;"
  2. इसका एकमात्र पैरामीटर एक सूचक है, जो एक स्केलर प्रकार है, और इसलिए एक शाब्दिक प्रकार है।
  3. इसकी वापसी अहस्ताक्षरित int है, जो स्केलर (और इसलिए शाब्दिक) भी है।
  4. रिटर्न प्रकार में कोई अंतर्निहित रूपांतरण नहीं है।

वहाँ कुछ सवाल है कि क्या *inputधर्मांतरण को रोकने के लिए कोई गैरकानूनी देनदारी है, और मुझे यकीन नहीं है कि मैं /5.19 / 2/6/2 1 और §4.1 में नियमों को अच्छी तरह से समझता हूं।

व्यावहारिक दृष्टिकोण से, इस कोड को (एक उदाहरण के लिए) जी ++ द्वारा स्वीकार किया जाता है, कम से कम जी ++ 4.7.1 के रूप में वापस।

उपयोग कुछ इस तरह होगा:

switch(std::hash(value)) {
    case const_hash("one"): one(); break;
    case const_hash("two"): two(); break;
    // ...
    default: other(); break;
}

§5.19 / 2/6/2 की आवश्यकताओं का अनुपालन करने के लिए आपको कुछ इस तरह से करना पड़ सकता है:

// one of the `constexpr`s is probably redundant, but I haven't figure out which.
char constexpr * constexpr v_one = "one"; 

// ....

case const_hash(v_one): one(); break;
  1. मैं अप्राकृतिक बुलेट बिंदुओं को संदर्भित करने के लिए अतिरिक्त 'स्लैश' संख्याओं का उपयोग कर रहा हूं, इसलिए यह दूसरा बुलेट बिंदु है यदि bullet5.19 / 2 के तहत छठा बुलेट बिंदु। मुझे लगता है कि मुझे पीट बेकर से बात करनी पड़ सकती है कि क्या इस तरह के टुकड़ों की पहचान करने के लिए पदानुक्रम के नीचे कुछ प्रकार की संख्या / अक्षर / रोमन अंक जोड़ना संभव है ...

3
इसमें दो बातें गलत हैं। 1: पुनरावर्ती कॉल की अनुमति नहीं है constexpr, 2: आपके पास कोई रुकने की स्थिति नहीं है (जहां *input == nullptr) और जैसा कि मैं समझता हूं कि constexprआपके पास एक नहीं हो सकता है।
मत्ती

9
यह कहाँ कहता है कि एक बाधा में पुनरावृत्ति की अनुमति नहीं है? जहां तक ​​मैं देख सकता हूं, यह केवल यह कहता है कि आपके द्वारा कॉल किए जाने वाले किसी भी फ़ंक्शन को स्वयं कॉन्स्ट्रेक्ट (.15.19 / 2/2) होना चाहिए। मैंने समाप्ति की स्थिति में गलती की थी, जिसे मैंने अब ठीक कर दिया है (मैंने गलती से इस्तेमाल किया था) जहां यह होना चाहिए था &&)।
जेरी कॉफ़िन

3
पुनरावर्ती बाधा। मैंने 2008 के कुछ मीटिंग मिनटों को पढ़ा। पुनरावर्ती कॉन्स्ट्रेक्स फ़ंक्शन को अनुमति देने या अस्वीकार करने के बारे में चर्चा हुई। गिस्ट वर्तमान शब्द था इसे मना नहीं किया, और इसे थोड़ा निहित किया। समिति ने महसूस किया कि इस तरह की एक शक्तिशाली विशेषता को स्पष्ट रूप से स्पष्ट किया जाना चाहिए। 2008 में वापस आ गया था, मुझे नहीं पता कि तब से क्या हुआ है।
deft_code

3
सही - मुझे शायद ध्यान देना चाहिए कि मैं N3000 से जा रहा था, जो (मेरा मानना ​​है) इस समय सबसे हालिया मसौदा है। मुझे पूरा यकीन है कि यह एक समय में निषिद्ध था, लेकिन कम से कम अब इसके लिए अनुमति दी जा रही है।
जेरी कॉफिन

2
उम, && ऑपरेटर एक बूल लौटा रहा है, इसलिए यह फ़ंक्शन संभवतः वह नहीं कर रहा है जो आप चाहते हैं। विशेष रूप से यह किसी भी रिक्त स्ट्रिंग के लिए 0 देता है और संभवतया एक तार के साथ शुरू होने वाले कुछ अन्य तार जो (unsigned)-1अगर कोई है तो परिवर्तित करता है; और अन्य सभी तारों के लिए 1 लौटाता है। टर्नरी सशर्त ऑपरेटर के साथ फिर से लिखना?
ndkrempel

13

यह ओपी की समस्या को यथासंभव हल करने का प्रयास है।

namespace my_hash {
  template<class>struct hasher;
  template<>
  struct hasher<std::string> {
    std::size_t constexpr operator()(char const *input)const {
      return *input ?
        static_cast<unsigned int>(*input) + 33 * (*this)(input + 1) :
        5381;
    }
    std::size_t operator()( const std::string& str ) const {
      return (*this)(str.c_str());
    }
  };
  template<typename T>
  std::size_t constexpr hash(T&& t) {
    return hasher< typename std::decay<T>::type >()(std::forward<T>(t));
  }
  inline namespace literals {
    std::size_t constexpr operator "" _hash(const char* s,size_t) {
      return hasher<std::string>()(s);
    }
  }
}
using namespace my_hash::literals;
void one() {} void two() {} void other() {}

void foo( const std::string& value )
{
  switch( my_hash::hash(value) )
  {
    case "one"_hash: one(); break;
    case "two"_hash: two(); break;
    /*many more cases*/
    default: other(); break;
  }
}

जीवंत उदाहरण

मुख्य अंतर पर ध्यान दें - std::hashइसका उपयोग नहीं किया जा सकता है, क्योंकि हमारे पास std::hashएल्गोरिथ्म पर नियंत्रण नहीं है , और हमें इसे संकलन समय पर मूल्यांकन करने के लिए इसे पुन: लागू करना चाहिएconstexpr । इसके अलावा, कोई "पारदर्शी" हैश नहीं है std, इसलिए आप (बिना std::stringबनाए) हैश को कच्चे वर्ण बफर के रूप में नहीं बना सकते हैं std::string

मैंने std::stringकस्टम हैशर (पारदर्शी const char*समर्थन के साथ ) को एक my_hashनाम स्थान में अटका दिया है , इसलिए आप इसे std::unordered_mapसंगति में रख सकते हैं ।

@ जैरीकॉफिन के उत्कृष्ट उत्तर और उसके नीचे टिप्पणी सूत्र के आधार पर, लेकिन इसे वर्तमान C ++ 11 सर्वोत्तम प्रथाओं (जैसा कि उनका अनुमान लगाने का विरोध किया गया है!) के साथ इसे लिखने के प्रयास के साथ।

ध्यान दें कि एक switchबयान के लिए "कच्चे हैश" का उपयोग caseकरना खतरनाक है। आप ==यह काम करने की पुष्टि करने के लिए बाद में तुलना करना चाहते हैं ।


2
लाइव उदाहरण लिंक गलत / पुराना लगता है?
फेनफंडाचटजिग

@fuenfundachtzig क्या आपको विश्वास होगा कि मैंने इसे ठीक किया है?
यक्क - एडम नेवरामोंट

13

क्लेमेंट JACOB के एक पर आधारित यह स्निपेट। लेकिन क्लैंग के साथ भी काम करता है। और यह संकलन पर तेज होना चाहिए (इसमें केवल एक पुनरावर्ती कॉल है, मूल पोस्ट में दो की तरह नहीं)।

#include <iostream>
#include <string>
#include <vector>

static constexpr unsigned int crc_table[256] = {
    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
    0xe963a535, 0x9e6495a3,    0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
    0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
    0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
    0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
    0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
    0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
    0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
    0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
    0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
    0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
    0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
    0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
    0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
    0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
    0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
    0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
    0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};


template<int size, int idx = 0, class dummy = void>
struct MM{
  static constexpr unsigned int crc32(const char * str, unsigned int prev_crc = 0xFFFFFFFF)
  {
      return MM<size, idx+1>::crc32(str, (prev_crc >> 8) ^ crc_table[(prev_crc ^ str[idx]) & 0xFF] );
  }
};

// This is the stop-recursion function
template<int size, class dummy>
struct MM<size, size, dummy>{
  static constexpr unsigned int crc32(const char * str, unsigned int prev_crc = 0xFFFFFFFF)
  {
      return prev_crc^ 0xFFFFFFFF;
  }
};

// This don't take into account the nul char
#define COMPILE_TIME_CRC32_STR(x) (MM<sizeof(x)-1>::crc32(x))


template<unsigned int crc>
void PrintCrc()
{
    std::cout << crc << std::endl;
}


int main()
{

    PrintCrc<COMPILE_TIME_CRC32_STR("HAH")>();
}

अवधारणा का प्रमाण यहाँ देखें


1
धन्यवाद, याकूब का जवाब ठीक है जो मैं जीसीसी पर चाहता था, लेकिन मिक्सी पीवीसी बड़ी त्रुटियों के साथ त्रुटियों को फेंक रहा था। आपका जवाब msvc पर काम करता है कि मुझे बड़े तार के साथ हैश की जरूरत है।
डैनियल मूडी

8

ध्यान दें कि यहाँ दिखाया गया प्रपत्र मानक में स्वीकार नहीं किया गया था, जैसा कि नीचे दिया गया है।

संकलित समय स्ट्रिंग प्रसंस्करण N2765 में प्रस्तावित उपयोगकर्ता-परिभाषित शाब्दिक के माध्यम से संभव हो गया है । जैसा कि मैंने पहले ही उल्लेख किया है, मैं किसी भी संकलक के बारे में नहीं जानता जो वर्तमान में इसे लागू करता है और संकलक समर्थन के बिना केवल अनुमान कार्य हो सकता है।

In2.13.7.3 और ड्राफ्ट के 4 में हमारे पास निम्नलिखित हैं:

अन्यथा (एस में शाब्दिक ऑपरेटर टेम्पलेट शामिल है), एल को फॉर्म
ऑपरेटर "" एक्स <'c1', 'c2', ..., 'ck'> () के रूप में माना जाता है, जहां n स्रोत वर्ण अनुक्रम c1c2 है ... सी.के.। [नोट: अनुक्रम c1c2 ... ck में केवल मूल स्रोत वर्ण सेट से वर्ण हो सकते हैं। ध्यान दें]

उस के साथ संयोजन करें constexprऔर हमें समय स्ट्रिंग प्रसंस्करण संकलित करना चाहिए।

अद्यतन: मैंने अनदेखी की है कि मैं गलत पैराग्राफ पढ़ रहा था, इस फॉर्म को उपयोगकर्ता-परिभाषित-पूर्णांक-शाब्दिक और -फ्लोटिंग-शाब्दिक के लिए अनुमति दी गई है, लेकिन स्पष्ट रूप से -स्ट्रिंग-शाब्दिक (§2.13.7.5) के लिए नहीं।
प्रस्ताव के इस भाग को स्वीकार नहीं किया गया है।

कहा जा रहा है कि, C ++ 0x में मेरी सीमित झलक के साथ, यह कुछ इस तरह दिख सकता है (मुझे सबसे अधिक संभावना कुछ गलत लगी):

template<char c, char... str>
struct hash {
    static const unsigned result = c + hash<str...>::result;
};

template<char c>
struct hash {
    static const unsigned result = c;
};

template<char... str> 
constexpr unsigned
operator "" _hash() {
    return hash<str>::result;
}

// update: probably wrong, because the above 
// form is not allowed for string-literals:    
const unsigned h = "abcd"_hash;

यदि जैरी काम करता है, तो निम्नलिखित को काम करना चाहिए:

constexpr unsigned operator "" _hash(const char* s, size_t) {
    return const_hash(s);
}

Var लंबाई टेम्पलेट और constexprउपयोगकर्ता परिभाषित शाब्दिक का अच्छा (और आवश्यक) संयोजन । मुझे यकीन नहीं है कि आप स्ट्रिंग पैरामीटर को टेम्पलेट पैरामीटर के रूप में उपयोग कर सकते हैं, क्या उनके पास स्थैतिक संबंध नहीं है? (वे C ++ 98 में कम से कम करते हैं और इसलिए टेम्पलेट मापदंडों के रूप में वर्बोटेन हैं)।
मत्ती

मैंने पैराग्राफ को मिलाया है और सोचा है कि यह मामला एक अपवाद था - दुख की बात है कि ऐसा प्रतीत नहीं होता है।
जॉर्ज फ्रिट्ज़शे

1
@Motti: स्ट्रिंग शाब्दिक का उपयोग टेम्पलेट पैरामीटर के रूप में gf कहाँ है? क्या आप स्ट्रिंग के शाब्दिक टेम्पलेट को स्ट्रिंग शाब्दिक के रूप में पारित करने में भ्रमित कर रहे हैं?
deft_code

यह मूल प्रस्ताव से लगता है, स्ट्रिंग शाब्दिकों के लिए टेम्प्लेट संस्करण स्वीकार नहीं किया गया था (समसामयिक मुद्दों के कारण; stackoverflow.com/questions/1108008/any-ideas-for-c1y/… - comments) - बहुत बुरा।
जॉर्ज फ्रिट्ज़चे

1
operator ""_hashXcode 5.0.2 में मेरे लिए अंतिम संस्करण काम करता है।
क्यूबसप्ले 42

8

क्लेमेंट JACOB के एक पर आधारित एक अन्य समाधान, C ++ 11 कॉन्स्टैक्स (विस्तारित C ​​++ 14 नहीं) का उपयोग करके, लेकिन केवल एक पुनरावृत्ति होने पर।

namespace detail {
// CRC32 Table (zlib polynomial)
static constexpr uint32_t crc_table[256] = { 0x00000000L, 0x77073096L, ... }

template<size_t idx>
constexpr uint32_t combine_crc32(const char * str, uint32_t part) {
  return (part >> 8) ^ crc_table[(part ^ str[idx]) & 0x000000FF];
}

template<size_t idx>
constexpr uint32_t crc32(const char * str) {
  return combine_crc32<idx>(str, crc32<idx - 1>(str));
}

// This is the stop-recursion function
template<>
constexpr uint32_t crc32<size_t(-1)>(const char * str) {
  return 0xFFFFFFFF;
}

} //namespace detail

template <size_t len>
constexpr uint32_t ctcrc32(const char (&str)[len]) {
  return detail::crc32<len - 2>(str) ^ 0xFFFFFFFF;
}

कुछ स्पष्टीकरण

  • हम एक एकल पुनरावृत्ति का उपयोग कर रहे हैं, ताकि फ़ंक्शन लंबे समय तक तार के लिए भी अच्छी तरह से काम करे।
  • अतिरिक्त समारोह combine_crc32 हमें एक चर के तहत एक पुनरावृत्ति के परिणाम को स्टोर करने partऔर दो बार उपयोग करने की अनुमति देता है । यह फ़ंक्शन स्थानीय वैरिएबल घोषणाओं को रोकने के लिए C ++ 11 लिमिटेटन के लिए एक चलना है।
  • ctcrc32समारोह एक स्ट्रिंग शाब्दिक है, जो एक के रूप में पारित हो जाता है की उम्मीद है const char (&)[len]। इस तरह हम एक स्ट्रिंग पैरामीटर को एक टेम्प्लेट पैरामीटर के रूप में प्राप्त कर सकते हैं और मैक्रोज़ पर निर्भर होने की आवश्यकता नहीं है।

2
यह मेरा पसंदीदा कार्यान्वयन था, धन्यवाद।
डैनियल मूडी

6

निम्नलिखित GCC 4.6.1 में काम करता है, और आप hashया तो या packस्विच ब्लॉक में उपयोग कर सकते हैं ।

/* Fast simple string hash (Bernstein?) */                                       
constexpr unsigned int hash(const char *s, int off = 0) {                        
    return !s[off] ? 5381 : (hash(s, off+1)*33) ^ s[off];                           
}                                                                                

/* Pack the string into an unsigned int                                          
 * Using 7 bits (ascii) it packs 9 chars into a uint64_t                         
 */                                                                              
template <class T = uint64_t, unsigned int Bits = 7>                             
constexpr T pack(const char *s, unsigned int off = 0) {                          
    return (Bits*off >= CHAR_BIT*sizeof(T) || !s[off]) ? 0 :                     
        (((T)s[off] << (Bits*off)) | pack(s,off+1));                             
}  

जीसीसी प्रतीत होता है () पुनरावर्ती कॉल की अनुमति नहीं देता है जहां हम एक सूचक के s+1साथ गुजरते हैं s, यही कारण है कि मैं offचर का उपयोग करता हूं ।


5

यदि आपके पास c ++ 17 संकलक और string_view है, तो यह तुच्छ हो जाता है, बस सामान्य संस्करण लिखें:

constexpr uint32_t crc32(std::string_view str)
{
    uint32_t crc = 0xffffffff;
    for (auto c : str)
        crc = (crc >> 8) ^ crc_table[(crc ^ c) & 0xff];
    return crc ^ 0xffffffff;
}

ध्यान दें कि कंपाइलर इसे संकलित समय पर संसाधित नहीं करने का निर्णय ले सकता है यदि आप बस लिखते हैं crc32("mystring")(आमतौर पर वीएस ऐसा करने के लिए जाता है)। उस मुद्दे को दरकिनार करने की चाल एक कॉन्स्ट्रेक्स चर बनाने के लिए है जो आपके crc32 के संकलन समय मूल्यांकन पर निर्भर करती है। आमतौर परconstexpr uint32_t val = crc32("mystring");
गिलियूम ग्रिस

3

यहां एक और C ++ 11 कार्यान्वयन (@ CygnusX1 उत्तर पर आधारित) है, जो कॉन्स्ट्रेप चार सरणियों और रनटाइम स्ट्रिंग्स के साथ काम करता है:

namespace detail {

    // CRC32 Table (zlib polynomial)
    static constexpr uint32_t crc_table[256] = { 0x00000000L, 0x77073096L, ... };

    constexpr uint32_t combine_crc32(size_t idx, const char * str, uint32_t part) {
        return (part >> 8) ^ crc_table[(part ^ str[idx]) & 0x000000FF];
    }

    constexpr uint32_t crc32(size_t idx, const char * str) {
        return idx == size_t(-1) ? 
            0xFFFFFFFF : combine_crc32(idx, str, crc32(idx - 1, str));
    }
}

uint32_t ctcrc32(std::string const& str) {
    size_t len = str.size() + 1;
    return detail::crc32(len - 2, str.c_str()) ^ 0xFFFFFFFF;
}

template <size_t len>
constexpr uint32_t ctcrc32(const char (&str)[len]) {
    return detail::crc32(len - 2, str) ^ 0xFFFFFFFF;
}

आपको आवश्यकता है str.size() + 1क्योंकि lenदूसरे अधिभार strlen(str) + 1के अंत में नल-चरित्र के कारण है।

मैंने इसके लिए एक अधिभार नहीं जोड़ा const char *क्योंकि यह दूसरे अधिभार के साथ खिलवाड़ करता है - आप आसानी से const char *, size_tया इसके लिए अधिभार जोड़ सकते हैं std::string_view


2

यह एक अच्छा सवाल है।

जेरी कॉफ़िन के जवाब के आधार पर, मैंने एक और बनाया है जो विज़ुअल स्टूडियो 2017 के std :: hash के साथ संगत है।

#include <functional>
#include <cassert>
using namespace std;


constexpr size_t cx_hash(const char* input) {
    size_t hash = sizeof(size_t) == 8 ? 0xcbf29ce484222325 : 0x811c9dc5;
    const size_t prime = sizeof(size_t) == 8 ? 0x00000100000001b3 : 0x01000193;

    while (*input) {
        hash ^= static_cast<size_t>(*input);
        hash *= prime;
        ++input;
    }

    return hash;
}


int main() {
    /* Enter your code here. Read input from STDIN. Print output to STDOUT */

    auto a = cx_hash("test");
    hash<string> func;
    auto b = func("test");
    assert(a == b);

    return 0;
}

https://github.com/manuelgustavo/cx_hash


0

मुझे अभी भी crc32- शाब्दिक संस्करण याद आ रहा था (जो टेम्प्लेट के साथ संभव नहीं है), इसलिए यहाँ मेरा सुझाव CygnusX1 पर आधारित है । कुछ परीक्षण किया, प्रतिक्रिया देने के लिए स्वतंत्र महसूस करें।

MSVC पर टेस्टेट।

पुनश्च: मुझे कहीं और अतिरिक्त सामान खोजने से नफरत है, इसलिए मैंने अपने जवाब के तल पर सीआरसी तालिका की प्रतिलिपि बनाई।

#include <inttypes.h>

namespace detail
{
    // CRC32 Table (zlib polynomial)
    static constexpr uint32_t crc_table[256] =
    {
        0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
        ...
    };

    constexpr uint32_t combine_crc32( const char c, uint32_t part )
    {
        return (part >> 8) ^ crc_table[(part ^ c) & 0x000000FF];
    }

    constexpr uint32_t crc32( const char * str, size_t idx )
    {
        return combine_crc32( str[idx], idx ? crc32( str, idx - 1 ) : 0xFFFFFFFF );
    }
} //namespace detail

constexpr uint32_t ctcrc32( const char* str, size_t len )
{
    return detail::crc32( str, len ) ^ 0xFFFFFFFF;
}

size_t constexpr operator "" _hash( const char* str, size_t len )
{
    return ctcrc32( str, len );
}

दान बर्नस्टीन (djb2) से एल्गोरिदम के साथ वैकल्पिक ( जेरी कॉफ़िन + जॉर्ज फ्रिट्ज़ से संयुक्त उत्तर )

unsigned constexpr const_hash( char const *input )
{
    return *input ?
        static_cast<unsigned int>(*input) + 33 * const_hash( input + 1 ) :
        5381;
}
size_t constexpr operator "" _hash( const char* str, size_t len )
{
    return const_hash( str );
}

Crc32 तालिका:

static constexpr uint32_t crc_table[256] =
    {
        0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
        0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
        0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
        0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
        0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
        0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
        0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
        0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
        0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
        0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
        0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
        0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
        0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
        0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
        0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
        0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
        0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
        0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
        0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
        0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
        0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
        0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
        0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
        0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
        0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
        0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
        0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
        0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
        0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
        0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
        0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
        0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
        0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
        0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
        0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
        0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
        0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
        0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
        0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
        0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
        0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
        0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
        0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
        0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
        0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
        0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
        0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
        0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
        0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
        0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
        0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
        0x2d02ef8dL
    };
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.