<commit_before>#ifndef VG_HANDLE_HPP_INCLUDED
#define VG_HANDLE_HPP_INCLUDED

/** \file 
 * Defines a handle type that can refer to oriented nodes of, and be used to
 * traverse, any backing graph implementation. Not just an ID or a pos_t because
 * XG (and maybe other implementations) provide more efficient local traversal
 * mechanisms if you can skip ID lookups.
 */

#include "types.hpp"
#include "vg.pb.h"
#include "hash_map.hpp"

#include <functional>
#include <cstdint>
#include <vector>

namespace vg {

using namespace std;

/// A handle is 8 (assuming id_t is still int64_t) opaque bytes.
/// A handle refers to an oriented node.
/// Two handles are equal iff they refer to the same orientation of the same node.
/// Only handles in the same graph may be compared.
/// Handles have no ordering, but can be hashed.
struct handle_t {
    char data[sizeof(id_t)];
};

typedef pair<handle_t, handle_t> edge_t;

// XG is going to store node index in its g-vector and node orientation in there
// VG is going to store ID and orientation
// Other implementations can store other things (or maybe int indexes into tables)

/// View a handle as an integer
inline int64_t& as_integer(handle_t& handle) {
    return reinterpret_cast<int64_t&>(handle);
}

/// View a const handle as a const integer
inline const int64_t& as_integer(const handle_t& handle) {
    return reinterpret_cast<const int64_t&>(handle);
}

/// View an integer as a handle
inline handle_t& as_handle(int64_t& value) {
    return reinterpret_cast<handle_t&>(value);
}

/// View a const integer as a const handle
inline const handle_t& as_handle(const int64_t& value) {
    return reinterpret_cast<const handle_t&>(value);
}

/// Define equality on handles
inline bool operator==(const handle_t& a, const handle_t& b) {
    return as_integer(a) == as_integer(b);
}

/// Define inequality on handles
inline bool operator!=(const handle_t& a, const handle_t& b) {
    return as_integer(a) != as_integer(b);
}

/**
 * Define hashes for handles.
 */
template<>
struct wang_hash<handle_t> {
    size_t operator()(const vg::handle_t& handle) const {
        return wang_hash<std::int64_t>()(as_integer(handle));
    }
};
    
struct path_handle_t {
    char data[sizeof(int64_t)];
};
    
/// View a path handle as an integer
inline int64_t& as_integer(path_handle_t& path_handle) {
    return reinterpret_cast<int64_t&>(path_handle);
}

/// View a const path handle as a const integer
inline const int64_t& as_integer(const path_handle_t& path_handle) {<commit_msg>Change int type and add packing helper without exploding<commit_after>#ifndef VG_HANDLE_HPP_INCLUDED
#define VG_HANDLE_HPP_INCLUDED

/** \file 
 * Defines a handle type that can refer to oriented nodes of, and be used to
 * traverse, any backing graph implementation. Not just an ID or a pos_t because
 * XG (and maybe other implementations) provide more efficient local traversal
 * mechanisms if you can skip ID lookups.
 */

#include "types.hpp"
#include "vg.pb.h"
#include "hash_map.hpp"

#include <functional>
#include <cstdint>
#include <vector>

namespace vg {

using namespace std;

/// A handle is 8 (assuming id_t is still int64_t) opaque bytes.
/// A handle refers to an oriented node.
/// Two handles are equal iff they refer to the same orientation of the same node.
/// Only handles in the same graph may be compared.
/// Handles have no ordering, but can be hashed.
struct handle_t {
    char data[sizeof(id_t)];
};

typedef pair<handle_t, handle_t> edge_t;

// XG is going to store node index in its g-vector and node orientation in there
// VG is going to store ID and orientation
// Other implementations can store other things (or maybe int indexes into tables)

/// View a handle as an integer
inline uint64_t& as_integer(handle_t& handle) {
    return reinterpret_cast<uint64_t&>(handle);
}

/// View a const handle as a const integer
inline const uint64_t& as_integer(const handle_t& handle) {
    return reinterpret_cast<const uint64_t&>(handle);
}

/// View an integer as a handle
inline handle_t& as_handle(uint64_t& value) {
    return reinterpret_cast<handle_t&>(value);
}

/// View a const integer as a const handle
inline const handle_t& as_handle(const uint64_t& value) {
    return reinterpret_cast<const handle_t&>(value);
}

/// Define equality on handles
inline bool operator==(const handle_t& a, const handle_t& b) {
    return as_integer(a) == as_integer(b);
}

/// Define inequality on handles
inline bool operator!=(const handle_t& a, const handle_t& b) {
    return as_integer(a) != as_integer(b);
}

/// Define a way to pack an integer and an orientation bit into a handle_t. XG
/// and VG both ought to use these functions instead of doing fiddly bit
/// packing themselves.
struct EasyHandlePacking {

    // Have some masks
    const static uint64_t HIGH_BIT = (uint64_t)1 << 63;
    const static uint64_t LOW_BITS = 0x7FFFFFFFFFFFFFFF;
    

    /// Extract the packed integer
    inline static uint64_t unpack_number(const handle_t& handle) {
        return as_integer(handle) & LOW_BITS;
    }
    
    /// Extract the packed bit
    inline static bool unpack_bit(const handle_t& handle) {
        return as_integer(handle) & HIGH_BIT;
    }
    
    /// Pack up an integer and a bit into a handle
    inline static handle_t pack(const uint64_t& number, const bool& bit) {
        // Make sure the number doesn't use all the bits
        assert(number < (0x1ULL << 63));
        
        return as_handle(number | (bit * HIGH_BIT));
    }
    
    /// Toggle the packed bit and return a new handle
    inline static handle_t toggle_bit(const handle_t& handle) {
        return as_handle(as_integer(handle) ^ HIGH_BIT);
    }

};

/**
 * Define hashes for handles.
 */
template<>
struct wang_hash<handle_t> {
    size_t operator()(const vg::handle_t& handle) const {
        return wang_hash<std::int64_t>()(as_integer(handle));
    }
};
    
struct path_handle_t {
    char data[sizeof(int64_t)];
};
    
/// View a path handle as an integer
inline int64_t& as_integer(path_handle_t& path_handle) {
    return reinterpret_cast<int64_t&>(path_handle);
}

/// View a const path handle as a const integer
inline const int64_t& as_integer(const path_handle_t& path_handle) {
{'fraction_non_alphanumeric': 0.09508564110773171, 'fraction_numerical': 0.011045301744837522, 'mean_word_length': 3.7441154138192863, 'pattern_counts': {'":': 0, '<': 32, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 1, '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': '3340866', 'n_tokens_mistral': 2019, 'n_tokens_neox': 1937, 'n_words': 721}