blob: d2b83856ec6677d5505f6dd2945db602442ca838 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* 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.
*/
#ifndef SRC_TRACED_PROBES_FILESYSTEM_PREFIX_FINDER_H_
#define SRC_TRACED_PROBES_FILESYSTEM_PREFIX_FINDER_H_
#include <memory>
#include <set>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "perfetto/base/logging.h"
namespace perfetto {
// PrefixFinder allows to find prefixes for filenames that ensure that
// they can be found again within a provided limit of steps when searching
// within that prefix in the same order.
//
// For instance, let the limit be 4 and the filesystem be.
// /a/1
// /a/2
// /a/3
// /b/4
// /b/5
//
// The prefix for /a/1, /a/2 and /a/3/ is /, the one for /b/4 and /b/5 is /b/.
class PrefixFinder {
public:
// Opaque placeholder for a prefix that can be turned into a string
// using ToString.
// Can not be constructed outside of PrefixFinder.
class Node {
public:
friend class PrefixFinder;
Node(std::string name) : Node(std::move(name), nullptr) {}
Node(std::string name, Node* parent)
: name_(std::move(name)), parent_(parent) {}
Node(const Node& that) = delete;
Node& operator=(const Node&) = delete;
// Return string representation of prefix, e.g. /foo/bar.
// Does not include a trailing /.
std::string ToString() const;
private:
// Add a new child to this node.
Node* AddChild(std::string name);
// Get existing child for this node. Return nullptr if it
// does not exist.
Node* MaybeChild(const std::string& name);
const std::string name_;
const Node* parent_;
class NodeComparator {
public:
bool operator()(const Node& one, const Node& other) const {
return one.name_ < other.name_;
}
};
std::set<Node, NodeComparator> children_;
};
explicit PrefixFinder(size_t limit);
// Add path to prefix mapping.
// Must be called in DFS order.
// Must be called before GetPrefix(path) for the same path.
// Must not be called after Finalize.
void AddPath(std::string path);
// Return identifier for prefix. Ownership remains with the PrefixFinder.
// Must be called after AddPath(path) for the same path.
// Must not be before after Finalize.
Node* GetPrefix(std::string path);
// Call this after the last AddPath and before the first GetPrefix.
void Finalize();
private:
// We're about to remove the suffix of state from i onwards,
// if necessary add a prefix for anything in that suffix.
void Flush(size_t i);
void InsertPrefix(size_t len);
const size_t limit_;
// (path element, count) tuples for last path seen.
std::vector<std::pair<std::string, size_t>> state_{{"", 0}};
Node root_{"", nullptr};
#if PERFETTO_DCHECK_IS_ON()
bool finalized_ = false;
#endif
};
} // namespace perfetto
#endif // SRC_TRACED_PROBES_FILESYSTEM_PREFIX_FINDER_H_