<commit_before>#include "Resolver.h"

#include "Requirement.h"

#include <cassert>
#include <exception>
#include <map>
#include <set>
#include <stdexcept>

using namespace Arbiter;
using namespace Resolver;

namespace {

struct DependencyNode final
{
  public:
    const ArbiterProjectIdentifier _project;
    const ArbiterSelectedVersion _proposedVersion;

    std::unique_ptr<ArbiterRequirement> _requirement;
    std::set<DependencyNode> _dependencies;

    DependencyNode (ArbiterProjectIdentifier project, ArbiterSelectedVersion proposedVersion, const ArbiterRequirement &requirement)
      : _project(std::move(project))
      , _proposedVersion(std::move(proposedVersion))
      , _requirement(requirement.clone())
    {
      assert(_requirement->satisfiedBy(_proposedVersion._semanticVersion));
    }

    bool operator== (const DependencyNode &other) const
    {
      return _project == other._project && _proposedVersion == other._proposedVersion;
    }

    bool operator< (const DependencyNode &other) const
    {
      if (_project != other._project) {
        // There's no well-defined ordering between nodes for different
        // projects, and we don't want them to appear equal within a set.
        return true;
      }

      // Sort such that higher versions are tried first.
      return _proposedVersion > other._proposedVersion;
    }
};

class DependencyGraph final
{
  public:
    std::set<DependencyNode> _allNodes;
    std::map<DependencyNode, std::set<DependencyNode>> _edges;
    std::set<DependencyNode> _roots;

    bool operator== (const DependencyGraph &other) const
    {
      return _edges == other._edges && _roots == other._roots;
    }
};
<commit_msg>Add operator<< overloads for dependency graph types<commit_after>#include "Resolver.h"

#include "Requirement.h"

#include <cassert>
#include <exception>
#include <map>
#include <set>
#include <stdexcept>

using namespace Arbiter;
using namespace Resolver;

namespace {

struct DependencyNode final
{
  public:
    const ArbiterProjectIdentifier _project;
    const ArbiterSelectedVersion _proposedVersion;

    std::unique_ptr<ArbiterRequirement> _requirement;
    std::set<DependencyNode> _dependencies;

    DependencyNode (ArbiterProjectIdentifier project, ArbiterSelectedVersion proposedVersion, const ArbiterRequirement &requirement)
      : _project(std::move(project))
      , _proposedVersion(std::move(proposedVersion))
      , _requirement(requirement.clone())
    {
      assert(_requirement->satisfiedBy(_proposedVersion._semanticVersion));
    }

    bool operator== (const DependencyNode &other) const
    {
      return _project == other._project && _proposedVersion == other._proposedVersion;
    }

    bool operator< (const DependencyNode &other) const
    {
      if (_project != other._project) {
        // There's no well-defined ordering between nodes for different
        // projects, and we don't want them to appear equal within a set.
        return true;
      }

      // Sort such that higher versions are tried first.
      return _proposedVersion > other._proposedVersion;
    }
};

std::ostream &operator<< (std::ostream &os, const DependencyNode &node)
{
  return os
    << node._project << " @ " << node._proposedVersion
    << " (restricted to " << *node._requirement << ")";
}

class DependencyGraph final
{
  public:
    std::set<DependencyNode> _allNodes;
    std::map<DependencyNode, std::set<DependencyNode>> _edges;
    std::set<DependencyNode> _roots;

    bool operator== (const DependencyGraph &other) const
    {
      return _edges == other._edges && _roots == other._roots;
    }
};

std::ostream &operator<< (std::ostream &os, const DependencyGraph &graph)
{
  os << "Roots:";
  for (const DependencyNode &root : graph._roots) {
    os << "\n\t" << root;
  }

  os << "\n\nEdges";
  for (const auto &pair : graph._edges) {
    const DependencyNode &node = pair.first;
    os << "\n\t" << node._project << " ->";

    const auto &dependencies = pair.second;
    for (const DependencyNode &dep : dependencies) {
      os << "\n\t\t" << dep;
    }
  }

  return os;
}

{'fraction_non_alphanumeric': 0.11262466553150086, 'fraction_numerical': 0.0, 'mean_word_length': 3.6994285714285713, 'pattern_counts': {'":': 0, '<': 63, '<?xml version=': 0, '>': 30, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6912487', 'n_tokens_mistral': 1247, 'n_tokens_neox': 1194, 'n_words': 309}