Skip to content

Commit

Permalink
Introduce Type::GetAllTypesSortedByLoadDependencies()
Browse files Browse the repository at this point in the history
  • Loading branch information
Al2Klimov committed Sep 2, 2024
1 parent 4c6b93d commit 8725dbb
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 0 deletions.
1 change: 1 addition & 0 deletions lib/base/initialize.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ enum class InitializePriority {
RegisterBuiltinTypes,
RegisterFunctions,
RegisterTypes,
SortTypes,
EvaluateConfigFragments,
Default,
FreezeNamespaces,
Expand Down
65 changes: 65 additions & 0 deletions lib/base/type.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */

#include "base/type.hpp"
#include "base/atomic.hpp"
#include "base/configobject.hpp"
#include "base/debug.hpp"
#include "base/scriptglobal.hpp"
#include "base/namespace.hpp"
#include "base/objectlock.hpp"
#include <algorithm>
#include <functional>
#include <unordered_map>

using namespace icinga;

Expand Down Expand Up @@ -32,6 +38,59 @@ INITIALIZE_ONCE_WITH_PRIORITY([]() {
Type::Register(type);
}, InitializePriority::RegisterTypeType);

static std::vector<Type::Ptr> l_SortedByLoadDependencies;
static Atomic l_SortingByLoadDependenciesDone (false);

typedef std::unordered_map<Type*, bool> Visited; // https://stackoverflow.com/a/8942986

INITIALIZE_ONCE_WITH_PRIORITY([] {
auto types (Type::GetAllTypes());

types.erase(std::remove_if(types.begin(), types.end(), [](auto& type) {
return !ConfigObject::TypeInstance->IsAssignableFrom(type);
}), types.end());

// Depth-first search
std::unordered_set<Type*> unsorted;
Visited visited;
std::vector<Type::Ptr> sorted;

for (auto type : types) {
unsorted.emplace(type.get());
}

std::function<void(Type*)> visit ([&visit, &unsorted, &visited, &sorted](Type* type) {
if (unsorted.find(type) == unsorted.end()) {
return;
}

bool& alreadyVisited (visited.at(type));
VERIFY(!alreadyVisited);
alreadyVisited = true;

for (auto dep : type->GetLoadDependencies()) {
visit(dep);
}

unsorted.erase(type);
sorted.emplace_back(type);
});

while (!unsorted.empty()) {
for (auto& type : types) {
visited[type.get()] = false;
}

visit(*unsorted.begin());
}

VERIFY(sorted.size() == types.size());
VERIFY(sorted[0]->GetLoadDependencies().empty());

std::swap(sorted, l_SortedByLoadDependencies);
l_SortingByLoadDependenciesDone.store(true);
}, InitializePriority::SortTypes);

String Type::ToString() const
{
return "type '" + GetName() + "'";
Expand Down Expand Up @@ -72,6 +131,12 @@ std::vector<Type::Ptr> Type::GetAllTypes()
return types;
}

const std::vector<Type::Ptr>& Type::GetAllTypesSortedByLoadDependencies()
{
VERIFY(l_SortingByLoadDependenciesDone.load());
return l_SortedByLoadDependencies;
}

String Type::GetPluralName() const
{
String name = GetName();
Expand Down
1 change: 1 addition & 0 deletions lib/base/type.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class Type : public Object
static void Register(const Type::Ptr& type);
static Type::Ptr GetByName(const String& name);
static std::vector<Type::Ptr> GetAllTypes();
static const std::vector<Ptr>& GetAllTypesSortedByLoadDependencies();

void SetField(int id, const Value& value, bool suppress_events = false, const Value& cookie = Empty) override;
Value GetField(int id) const override;
Expand Down

0 comments on commit 8725dbb

Please sign in to comment.