mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	Merge branch 'integration' into memory_api
This commit is contained in:
		| @@ -108,13 +108,9 @@ constexpr ColorModeHelper operator|(ColorModeHelper lhs, ColorMode rhs) { | |||||||
| // Type alias for raw color mode bitmask values | // Type alias for raw color mode bitmask values | ||||||
| using color_mode_bitmask_t = uint16_t; | using color_mode_bitmask_t = uint16_t; | ||||||
|  |  | ||||||
| // Number of ColorMode enum values | // Lookup table for ColorMode bit mapping | ||||||
| constexpr int COLOR_MODE_BITMASK_SIZE = 10; |  | ||||||
|  |  | ||||||
| // Shared lookup table for ColorMode bit mapping |  | ||||||
| // This array defines the canonical order of color modes (bit 0-9) | // This array defines the canonical order of color modes (bit 0-9) | ||||||
| // Declared early so it can be used by constexpr functions | constexpr ColorMode COLOR_MODE_LOOKUP[] = { | ||||||
| constexpr ColorMode COLOR_MODE_LOOKUP[COLOR_MODE_BITMASK_SIZE] = { |  | ||||||
|     ColorMode::UNKNOWN,                // bit 0 |     ColorMode::UNKNOWN,                // bit 0 | ||||||
|     ColorMode::ON_OFF,                 // bit 1 |     ColorMode::ON_OFF,                 // bit 1 | ||||||
|     ColorMode::BRIGHTNESS,             // bit 2 |     ColorMode::BRIGHTNESS,             // bit 2 | ||||||
| @@ -127,8 +123,29 @@ constexpr ColorMode COLOR_MODE_LOOKUP[COLOR_MODE_BITMASK_SIZE] = { | |||||||
|     ColorMode::RGB_COLD_WARM_WHITE,    // bit 9 |     ColorMode::RGB_COLD_WARM_WHITE,    // bit 9 | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // Type alias for ColorMode bitmask using generic FiniteSetMask template | /// Bit mapping policy for ColorMode | ||||||
| using ColorModeMask = FiniteSetMask<ColorMode, COLOR_MODE_BITMASK_SIZE>; | /// Uses lookup table for non-contiguous enum values | ||||||
|  | struct ColorModeBitPolicy { | ||||||
|  |   using mask_t = uint16_t;  // 10 bits requires uint16_t | ||||||
|  |   static constexpr int max_bits = sizeof(COLOR_MODE_LOOKUP) / sizeof(COLOR_MODE_LOOKUP[0]); | ||||||
|  |  | ||||||
|  |   static constexpr unsigned to_bit(ColorMode mode) { | ||||||
|  |     // Linear search through lookup table | ||||||
|  |     // Compiler optimizes this to efficient code since array is constexpr | ||||||
|  |     for (int i = 0; i < max_bits; ++i) { | ||||||
|  |       if (COLOR_MODE_LOOKUP[i] == mode) | ||||||
|  |         return i; | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static constexpr ColorMode from_bit(unsigned bit) { | ||||||
|  |     return (bit < max_bits) ? COLOR_MODE_LOOKUP[bit] : ColorMode::UNKNOWN; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // Type alias for ColorMode bitmask using policy-based design | ||||||
|  | using ColorModeMask = FiniteSetMask<ColorMode, ColorModeBitPolicy>; | ||||||
|  |  | ||||||
| // Number of ColorCapability enum values | // Number of ColorCapability enum values | ||||||
| constexpr int COLOR_CAPABILITY_COUNT = 6; | constexpr int COLOR_CAPABILITY_COUNT = 6; | ||||||
| @@ -194,34 +211,3 @@ inline bool has_capability(const ColorModeMask &mask, ColorCapability capability | |||||||
|  |  | ||||||
| }  // namespace light | }  // namespace light | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|  |  | ||||||
| // Template specializations for ColorMode must be in global namespace |  | ||||||
| // |  | ||||||
| // C++ requires template specializations to be declared in the same namespace as the |  | ||||||
| // original template. Since FiniteSetMask is in the esphome namespace (not esphome::light), |  | ||||||
| // we must provide these specializations at global scope with fully-qualified names. |  | ||||||
| // |  | ||||||
| // These specializations define how ColorMode enum values map to/from bit positions. |  | ||||||
|  |  | ||||||
| /// Map ColorMode enum values to bit positions (0-9) |  | ||||||
| /// Bit positions follow the enum declaration order |  | ||||||
| template<> |  | ||||||
| constexpr int esphome::FiniteSetMask<esphome::light::ColorMode, esphome::light::COLOR_MODE_BITMASK_SIZE>::value_to_bit( |  | ||||||
|     esphome::light::ColorMode mode) { |  | ||||||
|   // Linear search through COLOR_MODE_LOOKUP array |  | ||||||
|   // Compiler optimizes this to efficient code since array is constexpr |  | ||||||
|   for (int i = 0; i < esphome::light::COLOR_MODE_BITMASK_SIZE; ++i) { |  | ||||||
|     if (esphome::light::COLOR_MODE_LOOKUP[i] == mode) |  | ||||||
|       return i; |  | ||||||
|   } |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /// Map bit positions (0-9) to ColorMode enum values |  | ||||||
| /// Bit positions follow the enum declaration order |  | ||||||
| template<> |  | ||||||
| inline esphome::light::ColorMode esphome::FiniteSetMask< |  | ||||||
|     esphome::light::ColorMode, esphome::light::COLOR_MODE_BITMASK_SIZE>::bit_to_value(int bit) { |  | ||||||
|   return (bit >= 0 && bit < esphome::light::COLOR_MODE_BITMASK_SIZE) ? esphome::light::COLOR_MODE_LOOKUP[bit] |  | ||||||
|                                                                      : esphome::light::ColorMode::UNKNOWN; |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -8,44 +8,54 @@ | |||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
|  |  | ||||||
|  | /// Default bit mapping policy for contiguous enums starting at 0 | ||||||
|  | /// Provides 1:1 mapping where enum value equals bit position | ||||||
|  | template<typename ValueType, int MaxBits> struct DefaultBitPolicy { | ||||||
|  |   // Automatic bitmask type selection based on MaxBits | ||||||
|  |   // ≤8 bits: uint8_t, ≤16 bits: uint16_t, otherwise: uint32_t | ||||||
|  |   using mask_t = typename std::conditional<(MaxBits <= 8), uint8_t, | ||||||
|  |                                            typename std::conditional<(MaxBits <= 16), uint16_t, uint32_t>::type>::type; | ||||||
|  |  | ||||||
|  |   static constexpr int max_bits = MaxBits; | ||||||
|  |  | ||||||
|  |   static constexpr unsigned to_bit(ValueType value) { return static_cast<unsigned>(value); } | ||||||
|  |  | ||||||
|  |   static constexpr ValueType from_bit(unsigned bit) { return static_cast<ValueType>(bit); } | ||||||
|  | }; | ||||||
|  |  | ||||||
| /// Generic bitmask for storing a finite set of discrete values efficiently. | /// Generic bitmask for storing a finite set of discrete values efficiently. | ||||||
| /// Replaces std::set<ValueType> to eliminate red-black tree overhead (~586 bytes per instantiation). | /// Replaces std::set<ValueType> to eliminate red-black tree overhead (~586 bytes per instantiation). | ||||||
| /// | /// | ||||||
| /// Template parameters: | /// Template parameters: | ||||||
| ///   ValueType: The type to store (typically enum, but can be any discrete bounded type) | ///   ValueType: The type to store (typically enum, but can be any discrete bounded type) | ||||||
| ///   MaxBits: Maximum number of bits needed (auto-selects uint8_t/uint16_t/uint32_t) | ///   BitPolicy: Policy class defining bit mapping and mask type (defaults to DefaultBitPolicy) | ||||||
| /// | /// | ||||||
| /// Requirements: | /// BitPolicy requirements: | ||||||
| ///   - ValueType must have a bounded discrete range that maps to bit positions | ///   - using mask_t = <uint8_t|uint16_t|uint32_t>  // Bitmask storage type | ||||||
| ///   - For 1:1 mappings (contiguous enums starting at 0), no specialization needed | ///   - static constexpr int max_bits               // Maximum number of bits | ||||||
| ///   - For custom mappings (like ColorMode), specialize value_to_bit() and/or bit_to_value() | ///   - static constexpr unsigned to_bit(ValueType) // Convert value to bit position | ||||||
| ///   - MaxBits must be sufficient to hold all possible values | ///   - static constexpr ValueType from_bit(unsigned) // Convert bit position to value | ||||||
| /// | /// | ||||||
| /// Example usage (1:1 mapping - climate enums): | /// Example usage (1:1 mapping - climate enums): | ||||||
| ///   // For enums with contiguous values starting at 0, no specialization needed! | ///   // For contiguous enums starting at 0, use DefaultBitPolicy | ||||||
| ///   using ClimateModeMask = FiniteSetMask<ClimateMode, CLIMATE_MODE_AUTO + 1>; | ///   using ClimateModeMask = FiniteSetMask<ClimateMode, DefaultBitPolicy<ClimateMode, CLIMATE_MODE_AUTO + 1>>; | ||||||
| ///   ClimateModeMask modes({CLIMATE_MODE_HEAT, CLIMATE_MODE_COOL}); | ///   ClimateModeMask modes({CLIMATE_MODE_HEAT, CLIMATE_MODE_COOL}); | ||||||
| ///   if (modes.count(CLIMATE_MODE_HEAT)) { ... } | ///   if (modes.count(CLIMATE_MODE_HEAT)) { ... } | ||||||
| ///   for (auto mode : modes) { ... }  // Iterate over set bits | ///   for (auto mode : modes) { ... } | ||||||
| /// | /// | ||||||
| /// Example usage (custom mapping - ColorMode): | /// Example usage (custom mapping - ColorMode): | ||||||
| ///   // For non-contiguous enums or custom mappings, specialize value_to_bit() and/or bit_to_value() | ///   // For custom mappings, define a custom BitPolicy | ||||||
| ///   // See esphome/components/light/color_mode.h for complete example | ///   // See esphome/components/light/color_mode.h for complete example | ||||||
| /// | /// | ||||||
| /// Design notes: | /// Design notes: | ||||||
| ///   - Uses compile-time type selection for optimal size (uint8_t/uint16_t/uint32_t) | ///   - Policy-based design allows custom bit mappings without template specialization | ||||||
| ///   - Iterator converts bit positions to actual values during traversal | ///   - Iterator converts bit positions to actual values during traversal | ||||||
| ///   - All operations are constexpr-compatible for compile-time initialization | ///   - All operations are constexpr-compatible for compile-time initialization | ||||||
| ///   - Drop-in replacement for std::set<ValueType> with simpler API | ///   - Drop-in replacement for std::set<ValueType> with simpler API | ||||||
| ///   - Despite the name, works with any discrete bounded type, not just enums |  | ||||||
| /// | /// | ||||||
| template<typename ValueType, int MaxBits = 16> class FiniteSetMask { | template<typename ValueType, typename BitPolicy = DefaultBitPolicy<ValueType, 16>> class FiniteSetMask { | ||||||
|  public: |  public: | ||||||
|   // Automatic bitmask type selection based on MaxBits |   using bitmask_t = typename BitPolicy::mask_t; | ||||||
|   // ≤8 bits: uint8_t, ≤16 bits: uint16_t, otherwise: uint32_t |  | ||||||
|   using bitmask_t = |  | ||||||
|       typename std::conditional<(MaxBits <= 8), uint8_t, |  | ||||||
|                                 typename std::conditional<(MaxBits <= 16), uint16_t, uint32_t>::type>::type; |  | ||||||
|  |  | ||||||
|   constexpr FiniteSetMask() = default; |   constexpr FiniteSetMask() = default; | ||||||
|  |  | ||||||
| @@ -57,7 +67,7 @@ template<typename ValueType, int MaxBits = 16> class FiniteSetMask { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   /// Add a single value to the set (std::set compatibility) |   /// Add a single value to the set (std::set compatibility) | ||||||
|   constexpr void insert(ValueType value) { this->mask_ |= (static_cast<bitmask_t>(1) << value_to_bit(value)); } |   constexpr void insert(ValueType value) { this->mask_ |= (static_cast<bitmask_t>(1) << BitPolicy::to_bit(value)); } | ||||||
|  |  | ||||||
|   /// Add multiple values from initializer list |   /// Add multiple values from initializer list | ||||||
|   constexpr void insert(std::initializer_list<ValueType> values) { |   constexpr void insert(std::initializer_list<ValueType> values) { | ||||||
| @@ -67,7 +77,7 @@ template<typename ValueType, int MaxBits = 16> class FiniteSetMask { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   /// Remove a value from the set (std::set compatibility) |   /// Remove a value from the set (std::set compatibility) | ||||||
|   constexpr void erase(ValueType value) { this->mask_ &= ~(static_cast<bitmask_t>(1) << value_to_bit(value)); } |   constexpr void erase(ValueType value) { this->mask_ &= ~(static_cast<bitmask_t>(1) << BitPolicy::to_bit(value)); } | ||||||
|  |  | ||||||
|   /// Clear all values from the set |   /// Clear all values from the set | ||||||
|   constexpr void clear() { this->mask_ = 0; } |   constexpr void clear() { this->mask_ = 0; } | ||||||
| @@ -75,7 +85,7 @@ template<typename ValueType, int MaxBits = 16> class FiniteSetMask { | |||||||
|   /// Check if the set contains a specific value (std::set compatibility) |   /// Check if the set contains a specific value (std::set compatibility) | ||||||
|   /// Returns 1 if present, 0 if not (same as std::set for unique elements) |   /// Returns 1 if present, 0 if not (same as std::set for unique elements) | ||||||
|   constexpr size_t count(ValueType value) const { |   constexpr size_t count(ValueType value) const { | ||||||
|     return (this->mask_ & (static_cast<bitmask_t>(1) << value_to_bit(value))) != 0 ? 1 : 0; |     return (this->mask_ & (static_cast<bitmask_t>(1) << BitPolicy::to_bit(value))) != 0 ? 1 : 0; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /// Count the number of values in the set |   /// Count the number of values in the set | ||||||
| @@ -109,7 +119,7 @@ template<typename ValueType, int MaxBits = 16> class FiniteSetMask { | |||||||
|  |  | ||||||
|     constexpr ValueType operator*() const { |     constexpr ValueType operator*() const { | ||||||
|       // Return value for the first set bit |       // Return value for the first set bit | ||||||
|       return bit_to_value(find_next_set_bit(mask_, 0)); |       return BitPolicy::from_bit(find_next_set_bit(mask_, 0)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     constexpr Iterator &operator++() { |     constexpr Iterator &operator++() { | ||||||
| @@ -135,30 +145,26 @@ template<typename ValueType, int MaxBits = 16> class FiniteSetMask { | |||||||
|   /// Check if a specific value is present in a raw bitmask |   /// Check if a specific value is present in a raw bitmask | ||||||
|   /// Useful for checking intersection results without creating temporary objects |   /// Useful for checking intersection results without creating temporary objects | ||||||
|   static constexpr bool mask_contains(bitmask_t mask, ValueType value) { |   static constexpr bool mask_contains(bitmask_t mask, ValueType value) { | ||||||
|     return (mask & (static_cast<bitmask_t>(1) << value_to_bit(value))) != 0; |     return (mask & (static_cast<bitmask_t>(1) << BitPolicy::to_bit(value))) != 0; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /// Get the first value from a raw bitmask |   /// Get the first value from a raw bitmask | ||||||
|   /// Used for optimizing intersection logic (e.g., "pick first suitable mode") |   /// Used for optimizing intersection logic (e.g., "pick first suitable mode") | ||||||
|   static constexpr ValueType first_value_from_mask(bitmask_t mask) { return bit_to_value(find_next_set_bit(mask, 0)); } |   static constexpr ValueType first_value_from_mask(bitmask_t mask) { | ||||||
|  |     return BitPolicy::from_bit(find_next_set_bit(mask, 0)); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   /// Find the next set bit in a bitmask starting from a given position |   /// Find the next set bit in a bitmask starting from a given position | ||||||
|   /// Returns the bit position, or MaxBits if no more bits are set |   /// Returns the bit position, or max_bits if no more bits are set | ||||||
|   static constexpr int find_next_set_bit(bitmask_t mask, int start_bit) { |   static constexpr int find_next_set_bit(bitmask_t mask, int start_bit) { | ||||||
|     int bit = start_bit; |     int bit = start_bit; | ||||||
|     while (bit < MaxBits && !(mask & (static_cast<bitmask_t>(1) << bit))) { |     while (bit < BitPolicy::max_bits && !(mask & (static_cast<bitmask_t>(1) << bit))) { | ||||||
|       ++bit; |       ++bit; | ||||||
|     } |     } | ||||||
|     return bit; |     return bit; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   // Default implementations for 1:1 mapping (enum value = bit position) |  | ||||||
|   // For enums with contiguous values starting at 0, these defaults work as-is. |  | ||||||
|   // If you need custom mapping (like ColorMode), provide specializations. |  | ||||||
|   static constexpr int value_to_bit(ValueType value) { return static_cast<int>(value); } |  | ||||||
|   static constexpr ValueType bit_to_value(int bit) { return static_cast<ValueType>(bit); } |  | ||||||
|  |  | ||||||
|   bitmask_t mask_{0}; |   bitmask_t mask_{0}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user