Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. //===--- StringSwitch.h - Switch-on-literal-string Construct --------------===/
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //===----------------------------------------------------------------------===/
  7. ///
  8. /// \file
  9. ///  This file implements the StringSwitch template, which mimics a switch()
  10. ///  statement whose cases are string literals.
  11. ///
  12. //===----------------------------------------------------------------------===/
  13. #ifndef LLVM_ADT_STRINGSWITCH_H
  14. #define LLVM_ADT_STRINGSWITCH_H
  15.  
  16. #include "llvm/ADT/StringRef.h"
  17. #include "llvm/Support/Compiler.h"
  18. #include <cassert>
  19. #include <cstring>
  20. #include <optional>
  21.  
  22. namespace llvm {
  23.  
  24. /// A switch()-like statement whose cases are string literals.
  25. ///
  26. /// The StringSwitch class is a simple form of a switch() statement that
  27. /// determines whether the given string matches one of the given string
  28. /// literals. The template type parameter \p T is the type of the value that
  29. /// will be returned from the string-switch expression. For example,
  30. /// the following code switches on the name of a color in \c argv[i]:
  31. ///
  32. /// \code
  33. /// Color color = StringSwitch<Color>(argv[i])
  34. ///   .Case("red", Red)
  35. ///   .Case("orange", Orange)
  36. ///   .Case("yellow", Yellow)
  37. ///   .Case("green", Green)
  38. ///   .Case("blue", Blue)
  39. ///   .Case("indigo", Indigo)
  40. ///   .Cases("violet", "purple", Violet)
  41. ///   .Default(UnknownColor);
  42. /// \endcode
  43. template<typename T, typename R = T>
  44. class StringSwitch {
  45.   /// The string we are matching.
  46.   const StringRef Str;
  47.  
  48.   /// The pointer to the result of this switch statement, once known,
  49.   /// null before that.
  50.   std::optional<T> Result;
  51.  
  52. public:
  53.   explicit StringSwitch(StringRef S)
  54.   : Str(S), Result() { }
  55.  
  56.   // StringSwitch is not copyable.
  57.   StringSwitch(const StringSwitch &) = delete;
  58.  
  59.   // StringSwitch is not assignable due to 'Str' being 'const'.
  60.   void operator=(const StringSwitch &) = delete;
  61.   void operator=(StringSwitch &&other) = delete;
  62.  
  63.   StringSwitch(StringSwitch &&other)
  64.     : Str(other.Str), Result(std::move(other.Result)) { }
  65.  
  66.   ~StringSwitch() = default;
  67.  
  68.   // Case-sensitive case matchers
  69.   StringSwitch &Case(StringLiteral S, T Value) {
  70.     if (!Result && Str == S) {
  71.       Result = std::move(Value);
  72.     }
  73.     return *this;
  74.   }
  75.  
  76.   StringSwitch& EndsWith(StringLiteral S, T Value) {
  77.     if (!Result && Str.endswith(S)) {
  78.       Result = std::move(Value);
  79.     }
  80.     return *this;
  81.   }
  82.  
  83.   StringSwitch& StartsWith(StringLiteral S, T Value) {
  84.     if (!Result && Str.startswith(S)) {
  85.       Result = std::move(Value);
  86.     }
  87.     return *this;
  88.   }
  89.  
  90.   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, T Value) {
  91.     return Case(S0, Value).Case(S1, Value);
  92.   }
  93.  
  94.   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
  95.                       T Value) {
  96.     return Case(S0, Value).Cases(S1, S2, Value);
  97.   }
  98.  
  99.   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
  100.                       StringLiteral S3, T Value) {
  101.     return Case(S0, Value).Cases(S1, S2, S3, Value);
  102.   }
  103.  
  104.   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
  105.                       StringLiteral S3, StringLiteral S4, T Value) {
  106.     return Case(S0, Value).Cases(S1, S2, S3, S4, Value);
  107.   }
  108.  
  109.   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
  110.                       StringLiteral S3, StringLiteral S4, StringLiteral S5,
  111.                       T Value) {
  112.     return Case(S0, Value).Cases(S1, S2, S3, S4, S5, Value);
  113.   }
  114.  
  115.   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
  116.                       StringLiteral S3, StringLiteral S4, StringLiteral S5,
  117.                       StringLiteral S6, T Value) {
  118.     return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, Value);
  119.   }
  120.  
  121.   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
  122.                       StringLiteral S3, StringLiteral S4, StringLiteral S5,
  123.                       StringLiteral S6, StringLiteral S7, T Value) {
  124.     return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, Value);
  125.   }
  126.  
  127.   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
  128.                       StringLiteral S3, StringLiteral S4, StringLiteral S5,
  129.                       StringLiteral S6, StringLiteral S7, StringLiteral S8,
  130.                       T Value) {
  131.     return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, Value);
  132.   }
  133.  
  134.   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
  135.                       StringLiteral S3, StringLiteral S4, StringLiteral S5,
  136.                       StringLiteral S6, StringLiteral S7, StringLiteral S8,
  137.                       StringLiteral S9, T Value) {
  138.     return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, S9, Value);
  139.   }
  140.  
  141.   // Case-insensitive case matchers.
  142.   StringSwitch &CaseLower(StringLiteral S, T Value) {
  143.     if (!Result && Str.equals_insensitive(S))
  144.       Result = std::move(Value);
  145.  
  146.     return *this;
  147.   }
  148.  
  149.   StringSwitch &EndsWithLower(StringLiteral S, T Value) {
  150.     if (!Result && Str.endswith_insensitive(S))
  151.       Result = Value;
  152.  
  153.     return *this;
  154.   }
  155.  
  156.   StringSwitch &StartsWithLower(StringLiteral S, T Value) {
  157.     if (!Result && Str.startswith_insensitive(S))
  158.       Result = std::move(Value);
  159.  
  160.     return *this;
  161.   }
  162.  
  163.   StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, T Value) {
  164.     return CaseLower(S0, Value).CaseLower(S1, Value);
  165.   }
  166.  
  167.   StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
  168.                            T Value) {
  169.     return CaseLower(S0, Value).CasesLower(S1, S2, Value);
  170.   }
  171.  
  172.   StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
  173.                            StringLiteral S3, T Value) {
  174.     return CaseLower(S0, Value).CasesLower(S1, S2, S3, Value);
  175.   }
  176.  
  177.   StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
  178.                            StringLiteral S3, StringLiteral S4, T Value) {
  179.     return CaseLower(S0, Value).CasesLower(S1, S2, S3, S4, Value);
  180.   }
  181.  
  182.   [[nodiscard]] R Default(T Value) {
  183.     if (Result)
  184.       return std::move(*Result);
  185.     return Value;
  186.   }
  187.  
  188.   [[nodiscard]] operator R() {
  189.     assert(Result && "Fell off the end of a string-switch");
  190.     return std::move(*Result);
  191.   }
  192. };
  193.  
  194. } // end namespace llvm
  195.  
  196. #endif // LLVM_ADT_STRINGSWITCH_H
  197.