| /* | 
 |  *    Copyright (c) 2025 Project CHIP Authors | 
 |  *    All rights reserved. | 
 |  * | 
 |  *    Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  *    you may not use this file except in compliance with the License. | 
 |  *    You may obtain a copy of the License at | 
 |  * | 
 |  *        http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  *    Unless required by applicable law or agreed to in writing, software | 
 |  *    distributed under the License is distributed on an "AS IS" BASIS, | 
 |  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  *    See the License for the specific language governing permissions and | 
 |  *    limitations under the License. | 
 |  */ | 
 | #pragma once | 
 |  | 
 | #include <app/server-cluster/ServerClusterInterfaceRegistry.h> | 
 |  | 
 | namespace chip { | 
 | namespace app { | 
 |  | 
 | /// This class specializes ServerClusterInterfaceRegistry to register ServerClusterInterface references | 
 | /// that are limited to a single endpoint. In other words, GetPaths() must return path(s) in the same | 
 | /// endpoint. | 
 | /// The assumption that every ServerClusterInterface registered is limited to a single endpoint | 
 | /// allows us to provide additional helper methods such as `ClustersOnEndpoint()` and `UnregisterAllFromEndpoint()`. | 
 | class SingleEndpointServerClusterRegistry : public ServerClusterInterfaceRegistry | 
 | { | 
 | public: | 
 |     /// represents an iterable list of clusters | 
 |     class ClustersList | 
 |     { | 
 |     public: | 
 |         class Iterator | 
 |         { | 
 |         public: | 
 |             Iterator(ServerClusterRegistration * interface, EndpointId endpoint) : mEndpointId(endpoint), mRegistration(interface) | 
 |             { | 
 |                 if (mRegistration != nullptr) | 
 |                 { | 
 |                     mSpan = interface->serverClusterInterface->GetPaths(); | 
 |                 } | 
 |                 AdvanceUntilMatchingEndpoint(); | 
 |             } | 
 |  | 
 |             Iterator & operator++() | 
 |             { | 
 |                 if (!mSpan.empty()) | 
 |                 { | 
 |                     mSpan = mSpan.SubSpan(1); | 
 |                 } | 
 |                 AdvanceUntilMatchingEndpoint(); | 
 |                 return *this; | 
 |             } | 
 |             bool operator==(const Iterator & other) const { return mRegistration == other.mRegistration; } | 
 |             bool operator!=(const Iterator & other) const { return mRegistration != other.mRegistration; } | 
 |             ClusterId operator*() { return mSpan.begin()->mClusterId; } | 
 |  | 
 |         private: | 
 |             const EndpointId mEndpointId; | 
 |             ServerClusterRegistration * mRegistration; | 
 |             Span<const ConcreteClusterPath> mSpan; | 
 |  | 
 |             void AdvanceUntilMatchingEndpoint() | 
 |             { | 
 |                 while (mRegistration != nullptr) | 
 |                 { | 
 |                     if (mSpan.empty()) | 
 |                     { | 
 |                         mRegistration = mRegistration->next; | 
 |                         if (mRegistration != nullptr) | 
 |                         { | 
 |                             mSpan = mRegistration->serverClusterInterface->GetPaths(); | 
 |                         } | 
 |                         continue; | 
 |                     } | 
 |                     if (mSpan.begin()->mEndpointId == mEndpointId) | 
 |                     { | 
 |                         return; | 
 |                     } | 
 |  | 
 |                     // need to keep searching | 
 |                     mSpan = mSpan.SubSpan(1); | 
 |                 } | 
 |             } | 
 |         }; | 
 |  | 
 |         constexpr ClustersList(ServerClusterRegistration * start, EndpointId endpointId) : mEndpointId(endpointId), mStart(start) {} | 
 |         Iterator begin() { return { mStart, mEndpointId }; } | 
 |         Iterator end() { return { nullptr, mEndpointId }; } | 
 |  | 
 |     private: | 
 |         const EndpointId mEndpointId; | 
 |         ServerClusterRegistration * mStart; | 
 |     }; | 
 |  | 
 |     ~SingleEndpointServerClusterRegistry() = default; | 
 |  | 
 |     /// Add the given entry to the registry. | 
 |     /// NOTE the requirement of entries to be part of the same endpoint. | 
 |     /// | 
 |     /// Requirements: | 
 |     ///   - entry MUST NOT be part of any other registration | 
 |     ///   - paths MUST be part of the same endpoint | 
 |     /// | 
 |     ///   - LIFETIME of entry must outlive the Registry (or entry must be unregistered) | 
 |     /// | 
 |     /// There can be only a single registration for a given `endpointId/clusterId` path. | 
 |     [[nodiscard]] CHIP_ERROR Register(ServerClusterRegistration & entry); | 
 |  | 
 |     /// Provides a list of clusters that are registered for the given endpoint. | 
 |     /// | 
 |     /// ClustersList points inside the internal registrations of the registry, so | 
 |     /// the list is only valid as long as the registry is not modified. | 
 |     ClustersList ClustersOnEndpoint(EndpointId endpointId); | 
 |  | 
 |     /// Unregister all registrations for the given endpoint. | 
 |     void UnregisterAllFromEndpoint(EndpointId endpointId); | 
 | }; | 
 |  | 
 | } // namespace app | 
 | } // namespace chip |