diff options
Diffstat (limited to 'source/core/slang-command-options.h')
| -rw-r--r-- | source/core/slang-command-options.h | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/source/core/slang-command-options.h b/source/core/slang-command-options.h new file mode 100644 index 000000000..a92d4d8f8 --- /dev/null +++ b/source/core/slang-command-options.h @@ -0,0 +1,253 @@ +#ifndef SLANG_CORE_COMMAND_OPTIONS_H +#define SLANG_CORE_COMMAND_OPTIONS_H + +#include "slang-basic.h" +#include "slang-string-slice-pool.h" +#include "slang-name-value.h" + +namespace Slang +{ + +/* For convenience we encode within "names" flags. +"-D..." means that -D *must* be followed by the value +"-D?..." means that -D *can* be a prefix, or it might be followed with the arg +*/ + +struct CommandOptions +{ + typedef uint32_t Flags; + + typedef int32_t UserIndex; + enum class UserValue : UserIndex; + static const UserValue kInvalidUserValue = UserValue(0x80000000); + + enum class LookupKind : int32_t + { + Category = -2, ///< Lookup a category name + Option = -1, ///< Lookup an option name (all options use the same lookup index even if in different categories) + Base = 0, ///< Lookup via category index + }; + + enum class CategoryKind + { + Option, ///< Command line option (like "-D") + Value, ///< One of a set of values (such as an enum or some other kind of list of values) + }; + + struct ValuePair + { + const char* name; + const char* description; + }; + + struct Category + { + UserValue userValue = kInvalidUserValue; + + CategoryKind kind; + UnownedStringSlice name; + UnownedStringSlice description; + + // Holds the span that defines all of the options associated with the category + Index optionStartIndex = 0; + Index optionEndIndex = 0; + }; + + struct Flag + { + enum Enum : Flags + { + CanPrefix = 0x1, /// Allows -Dfsggf or -D fdsfsd + IsPrefix = 0x2, /// Is an option that can only be a prefix + }; + }; + + struct Option + { + UnownedStringSlice names; ///< Comma delimited list of names, first name is the default + UnownedStringSlice usage; ///< Describes usage, can be empty + UnownedStringSlice description; ///< A description of usage + + UserValue userValue = kInvalidUserValue; + + Index categoryIndex = -1; ///< Category this option belongs to + Flags flags = 0; ///< Flags about this option + }; + + /// Add a category + Index addCategory(CategoryKind kind, const char* name, const char* description, UserValue userValue = kInvalidUserValue); + /// Use an already known category. It's an error if the category isn't found + void setCategory(const char* name); + + void add(const char* name, const char* usage, const char* description, UserValue userValue = kInvalidUserValue); + void add(const UnownedStringSlice* names, Count namesCount, const char* usage, const char* description, UserValue userValue = kInvalidUserValue, Flags flags = 0); + + void addValue(const UnownedStringSlice& name, UserValue userValue = kInvalidUserValue); + void addValue(const UnownedStringSlice& name, const UnownedStringSlice& description, UserValue userValue = kInvalidUserValue); + void addValue(const char* name, const char* description, UserValue userValue = kInvalidUserValue); + void addValue(const char* name, UserValue userValue = kInvalidUserValue); + void addValue(const UnownedStringSlice* names, Count namesCount, UserValue userValue = kInvalidUserValue); + + /// Add values (without UserValue association) + void addValues(const ValuePair* pairs, Count pairsCount); + + /// Add values + void addValues(const ConstArrayView<NameValue>& values); + void addValues(const ConstArrayView<NamesValue>& values); + void addValues(const ConstArrayView<NamesDescriptionValue>& values); + + /// Sometimes values are listed with *names* per value. This method will take into account the aliases + void addValuesWithAliases(const ConstArrayView<NameValue>& values); + + /// Get the target index based off the name and the kind + Index findTargetIndexByName(LookupKind kind, const UnownedStringSlice& name) const; + /// Given a kind and a user value lookup the target index + Index findTargetIndexByUserValue(LookupKind kind, UserValue userValue) const; + + /// Finds the category by name or -1 if not found + Index findCategoryByName(const UnownedStringSlice& name) const { return findTargetIndexByName(LookupKind::Category, name); } + /// Finds the option index by name or -1 if not found + Index findOptionByName(const UnownedStringSlice& name) const; + /// Find the option index of a value, using it's category index and the name + Index findValueByName(Index categoryIndex, const UnownedStringSlice& name) const { return findTargetIndexByName(LookupKind(categoryIndex), name); } + + /// Get the category index from a user value + Index findCategoryByUserValue(UserValue userValue) const { return findTargetIndexByUserValue(LookupKind::Category, userValue); } + /// Can only get options + Index findOptionByUserValue(UserValue userValue) const { return findTargetIndexByUserValue(LookupKind::Option, userValue); } + /// Get a value associated with a category + Index findValueByUserValue(Index categoryIndex, UserValue userValue) const { return findTargetIndexByUserValue(LookupKind(categoryIndex), userValue); } + + /// Given a category user value, find the associated name + /// Returns -1 if not found + Index findOptionByCategoryUserValue(UserValue categoryUserValue, const UnownedStringSlice& name) const; + + /// Find a category by case insensitive name. Returns -1 if not found + Index findCategoryByCaseInsensitiveName(const UnownedStringSlice& slice) const; + + /// Given a category index returns all the options associated. + ConstArrayView<Option> getOptionsForCategory(Index categoryIndex) const; + + /// Get the categories + const List<Category>& getCategories() const { return m_categories; } + + /// Get all the options + const List<Option>& getOptions() const { return m_options; } + + /// Get the option at the specified index + const Option& getOptionAt(Index index) const { return m_options[index]; } + + /// Find all of the categories in the usage slice + void findCategoryIndicesFromUsage(const UnownedStringSlice& usageSlice, List<Index>& outCategories) const; + /// Get all the option names associated with a category index + void getCategoryOptionNames(Index categoryIndex, List<UnownedStringSlice>& outNames) const; + + /// Set up a lookup kind from a category index + static LookupKind makeLookupKind(Index categoryIndex) { return LookupKind(categoryIndex); } + + /// Returns true, if all values from [start, end) are found for the kind + bool hasContiguousUserValueRange(LookupKind kind, UserValue start, UserValue nonInclEnd) const; + + /// Returns the number of options in the range + Count getOptionCountInRange(Index categoryIndex, UserValue start, UserValue nonInclEnd) const; + Count getOptionCountInRange(LookupKind kind, UserValue start, UserValue nonInclEnd) const; + + + /// Ctor + CommandOptions() : + m_pool(StringSlicePool::Style::Default), + m_arena(1024 * 2) + { + } + + /// Returns name in the m_optionPool or -1 on error + SlangResult _addOptionName(const UnownedStringSlice& name, Flags flags, Index targetIndex); + SlangResult _addValueName(const UnownedStringSlice& name, Index categoryIndex, Index targetIndex); + SlangResult _addName(LookupKind kind, const UnownedStringSlice& name, Index targetIndex); + + SlangResult _addUserValue(LookupKind kind, UserValue userValue, Index targetIndex); + + Index _addOption(const UnownedStringSlice& name, const Option& inOption); + Index _addOption(const UnownedStringSlice* names, Count namesCount, const Option& option); + + Index _addValue(const UnownedStringSlice& name, const Option& inOption); + + UnownedStringSlice _addString(const char* text); + UnownedStringSlice _addString(const UnownedStringSlice& slice); + + /// A key type that uses the combination of the lookup kind and a name index. + /// Maps to a target index that could be a category or an option index. + struct NameKey + { + typedef NameKey ThisType; + + SLANG_FORCE_INLINE bool operator==(const ThisType& rhs) const { return kind == rhs.kind && nameIndex == rhs.nameIndex; } + SLANG_FORCE_INLINE bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } + HashCode getHashCode() const { return combineHash(Slang::getHashCode(kind), Slang::getHashCode(nameIndex)); } + + LookupKind kind; ///< The kind of lookup + Index nameIndex; ///< The name index in the pool + }; + + struct UserValueKey + { + typedef UserValueKey ThisType; + + SLANG_FORCE_INLINE bool operator==(const ThisType& rhs) const { return kind == rhs.kind && userValue == rhs.userValue; } + SLANG_FORCE_INLINE bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } + HashCode getHashCode() const { return combineHash(Slang::getHashCode(kind), Slang::getHashCode(userValue)); } + + LookupKind kind; ///< The kind of lookup + UserValue userValue; ///< The user value + }; + + Index m_currentCategoryIndex = -1; + + List<Category> m_categories; + + // Holds a bit for all valid prefix sizes. Max prefix size is therefore 32 chars + uint32_t m_prefixSizes = 0; + + List<Option> m_options; ///< All of the entries describing each of the options + StringSlicePool m_pool; ///< Only holds options, and handle therefore matches up to m_entries + Dictionary<NameKey, Index> m_nameMap; ///< Maps a name to an option index + Dictionary<UserValueKey, Index> m_userValueMap; ///< Maps a user value (for a kind) to an index + + MemoryArena m_arena; ///< For other misc storage +}; + +struct CommandOptionsWriter +{ + typedef CommandOptions::CategoryKind CategoryKind; + + /// Append descirption for a category + void appendDescriptionForCategory(const CommandOptions& options, Index categoryIndex); + /// Appends a description of all of the options + void appendDescription(const CommandOptions& options); + + /// Get the builder that string is being written to + StringBuilder& getBuilder() { return m_builder; } + + /// Ctor + CommandOptionsWriter(): + m_indentSlice(toSlice(" ")) + { + } + + Count _getCurrentLineLength(); + + void _appendWithWrap(Count indentCount, List<UnownedStringSlice>& slices, const UnownedStringSlice& delimit); + void _appendWithWrap(Count indentCount, List<UnownedStringSlice>& lines); + void _requireIndent(Count indentCount); + void _appendText(Count indentCount, const UnownedStringSlice& text); + + + UnownedStringSlice m_indentSlice; + Count m_lineLength = 80; + + StringBuilder m_builder; +}; + +} // namespace Slang + +#endif |
