fork download
  1. #include <iostream>
  2. #include <utility>
  3. #include <map>
  4. #include <string>
  5. #include <initializer_list>
  6. #include <cstring>
  7. #include <stdexcept>
  8.  
  9. namespace LiteralSwitch {
  10.  
  11. // simple hash function
  12. constexpr unsigned int dbj2Hash(const char* str, size_t size, int index = 0)
  13. {
  14. return !str[index] ? 0x1505 : (dbj2Hash(str, size, index + 1) * 0x21) ^ str[index];
  15. }
  16.  
  17.  
  18. // Create a literal type for short-hand case strings
  19. constexpr unsigned int operator"" _C ( const char str[], size_t size)
  20. {
  21. return dbj2Hash(str, size - 1);
  22. }
  23.  
  24.  
  25. struct CaseLabel
  26. {
  27. typedef const char* label_type;
  28. typedef uint32_t value_type;
  29. typedef std::pair<const label_type, value_type> store_type;
  30.  
  31. constexpr CaseLabel(const char* str)
  32. : data_(std::make_pair(str, dbj2Hash(str, strlen(str))))
  33. {
  34. }
  35.  
  36. constexpr operator value_type() const { return data_.second; }
  37. constexpr operator label_type() const { return data_.first; }
  38. constexpr operator store_type() const { return data_; }
  39.  
  40. private:
  41.  
  42. const store_type data_;
  43. };
  44. struct compare {
  45. bool operator()(const char *left, const char *right) const
  46. {
  47. return strcmp(left, right) < 0;
  48. }
  49. };
  50.  
  51. struct CaseLabelSet
  52. : private std::map<CaseLabel::label_type, CaseLabel::value_type, compare>
  53. {
  54. CaseLabelSet(std::initializer_list<CaseLabel> values)
  55. {
  56. for(auto x : values) insert(x);
  57. }
  58.  
  59. CaseLabel::value_type operator()(const std::string& label) const
  60. {
  61. return operator()(label.c_str());
  62. }
  63. CaseLabel::value_type operator()(const char* label) const
  64. {
  65. auto it = find(label);
  66. if(it == end())
  67. {
  68. throw std::invalid_argument("Case label not found");
  69. }
  70.  
  71. return it->second;
  72. }
  73. };
  74.  
  75. }
  76.  
  77. using namespace LiteralSwitch;
  78.  
  79. void Test(const std::string& cond)
  80. {
  81. static const CaseLabelSet setValues = {"Hello", "World"};
  82.  
  83. try
  84. {
  85. switch(setValues(cond))
  86. {
  87. case "Hello"_C: std::cout << "Goodbye"; break;
  88. case "World"_C: std::cout << "Planet"; break;
  89. default: std::cout << "BOGUS!";
  90.  
  91. }
  92. std::cout << std::endl;
  93. }
  94. catch(std::invalid_argument)
  95. {
  96. std::cout << "exception on unknown switch/case value. should go to default" << std::endl;
  97. }
  98. }
  99.  
  100.  
  101. int main()
  102. {
  103. Test("Hello");
  104. Test("World");
  105. Test("hello");
  106. }
  107.  
Success #stdin #stdout 0s 2988KB
stdin
Standard input is empty
stdout
Goodbye
Planet
exception on unknown switch/case value. should go to default