| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_DATABASE_SIGNAL_SAMPLE_VIEW_H_ |
| #define COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_DATABASE_SIGNAL_SAMPLE_VIEW_H_ |
| |
| #include <optional> |
| #include <vector> |
| |
| #include "base/memory/raw_ptr.h" |
| #include "base/time/time.h" |
| #include "components/segmentation_platform/internal/database/signal_database.h" |
| #include "components/segmentation_platform/public/proto/types.pb.h" |
| |
| namespace segmentation_platform { |
| |
| // A container "view" on top of all the signal database sample list, that helps |
| // to query a particular histogram / user action or enum histograms. |
| class SignalSampleView { |
| public: |
| using Entries = std::vector<SignalDatabase::DbEntry>; |
| |
| // Object to query a particular signal to be included. |
| struct Query { |
| Query(proto::SignalType type, |
| uint64_t metric_hash, |
| base::Time start, |
| base::Time end, |
| const std::vector<int>& enum_ids = {}); |
| ~Query(); |
| Query(const Query&); |
| |
| // Returns true if the `sample` matches the view query. |
| bool IsFeatureMatching(const SignalDatabase::DbEntry& sample) const; |
| |
| // The metric type and hash to filter in. |
| const proto::SignalType type = proto::SignalType::UNKNOWN_SIGNAL_TYPE; |
| const uint64_t metric_hash = 0; |
| // The time period to filter in, start and end inclusive. |
| const base::Time start; |
| const base::Time end; |
| // List of enum values to include. If empty, then all signals are included. |
| const std::vector<int> enum_ids; |
| }; |
| |
| // Use begin() to create iterator, and ++ operator to increment the iterator. |
| struct Iterator { |
| Iterator(const SignalSampleView* view, size_t current); |
| ~Iterator(); |
| Iterator(Iterator& other); |
| |
| const SignalDatabase::DbEntry& operator*() { return samples_[current_]; } |
| const SignalDatabase::DbEntry* operator->() { return &samples_[current_]; } |
| |
| Iterator& operator++() { |
| current_ = view_->FindNext(current_); |
| return *this; |
| } |
| bool operator==(const Iterator& other) const { |
| CHECK_EQ(view_, other.view_); |
| return current_ == other.current_; |
| } |
| |
| // Current index the iterator points to. Prefer to use * operator instead: |
| // `*it`. |
| size_t current() const { return current_; } |
| |
| private: |
| const raw_ptr<const SignalSampleView> view_; |
| const Entries& samples_; |
| size_t current_; |
| }; |
| |
| // Creates a view on the database samples. `query` specifies the filter to |
| // apply on the samples for the view. If `query` is empty, all samples are |
| // included, just acts like a vector. |
| SignalSampleView(const std::vector<SignalDatabase::DbEntry>& samples, |
| const std::optional<Query>& query); |
| ~SignalSampleView(); |
| SignalSampleView(const SignalSampleView&) = delete; |
| |
| // C++ iterable object methods. |
| Iterator begin() const { return Iterator(this, FindNext(-1)); } |
| Iterator end() const { return Iterator(this, EndIndex()); } |
| |
| // Returns the last element in the view, if view is empty, returns end(). |
| Iterator Last() const { return Iterator(this, FindPrev(samples_.size())); } |
| |
| // The empty() and size() methods take O(n) time, on the size of the samples. |
| bool empty() const { return size() == 0; } |
| size_t size() const; |
| |
| private: |
| // Returns the index that represents the "end()" iterator of this object. |
| size_t EndIndex() const { return samples_.size(); } |
| |
| // Finds the next index that matches the given query. |
| size_t FindNext(int index) const; |
| |
| // Finds the previous index that matches the given query. |
| size_t FindPrev(int index) const; |
| |
| const std::vector<SignalDatabase::DbEntry>& samples_; |
| std::optional<Query> query_; |
| }; |
| |
| } // namespace segmentation_platform |
| |
| #endif // COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_DATABASE_SIGNAL_SAMPLE_VIEW_H_ |