packages feed

souffle-haskell-1.0.0: cbits/souffle/CompiledTuple.h

/*
 * Souffle - A Datalog Compiler
 * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved
 * Licensed under the Universal Permissive License v 1.0 as shown at:
 * - https://opensource.org/licenses/UPL
 * - <souffle root>/licenses/SOUFFLE-UPL.txt
 */

/************************************************************************
 *
 * @file CompiledTuple.h
 *
 * The central file covering the data structure utilized by
 * the souffle compiler for representing relations in compiled queries.
 *
 ***********************************************************************/

#pragma once

#include <cstddef>
#include <functional>
#include <iostream>
#include <system_error>

namespace souffle {

/**
 * The type of object stored within relations representing the actual
 * tuple value. Each tuple consists of a constant number of components.
 *
 * @tparam Domain the domain of the component values
 * @tparam arity the number of components within an instance
 */
template <typename Domain, std::size_t _arity>
struct Tuple {
    // some features for template meta programming
    using value_type = Domain;
    static constexpr size_t arity = _arity;

    // the stored data
    Domain data[arity];

    // constructores, destructors and assignment are default

    // provide access to components
    const Domain& operator[](std::size_t index) const {
        return data[index];
    }

    // provide access to components
    Domain& operator[](std::size_t index) {
        return data[index];
    }

    // a comparison operation
    bool operator==(const Tuple& other) const {
        for (std::size_t i = 0; i < arity; i++) {
            if (data[i] != other.data[i]) return false;
        }
        return true;
    }

    // inequality comparison
    bool operator!=(const Tuple& other) const {
        return !(*this == other);
    }

    // required to put tuples into e.g. a std::set container
    bool operator<(const Tuple& other) const {
        for (std::size_t i = 0; i < arity; ++i) {
            if (data[i] < other.data[i]) return true;
            if (data[i] > other.data[i]) return false;
        }
        return false;
    }

    // required to put tuples into e.g. a btree container
    bool operator>(const Tuple& other) const {
        for (std::size_t i = 0; i < arity; ++i) {
            if (data[i] > other.data[i]) return true;
            if (data[i] < other.data[i]) return false;
        }
        return false;
    }

    // allow tuples to be printed
    friend std::ostream& operator<<(std::ostream& out, const Tuple& tuple) {
        if (arity == 0) return out << "[]";
        out << "[";
        for (std::size_t i = 0; i < (std::size_t)(arity - 1); ++i) {
            out << tuple.data[i];
            out << ",";
        }
        return out << tuple.data[arity - 1] << "]";
    }
};

#ifdef _MSC_VER
/**
 * A template specialization for 0-arity tuples when compiling with microsoft's
 * compiler, because it doesn't like the 0 length array even though it is the
 * last member of the struct.
 */
template <typename Domain>
struct Tuple<Domain, 0> {
    // some features for template meta programming
    using value_type = Domain;
    enum { arity = 0 };

    // the stored data
    Domain data[1];

    // constructores, destructors and assignment are default

    // provide access to components
    const Domain& operator[](std::size_t index) const {
        return data[index];
    }

    // provide access to components
    Domain& operator[](std::size_t index) {
        return data[index];
    }

    // a comparison operation
    bool operator==(const Tuple& other) const {
        for (std::size_t i = 0; i < arity; i++) {
            if (data[i] != other.data[i]) return false;
        }
        return true;
    }

    // inequality comparison
    bool operator!=(const Tuple& other) const {
        return !(*this == other);
    }

    // required to put tuples into e.g. a std::set container
    bool operator<(const Tuple& other) const {
        for (std::size_t i = 0; i < arity; ++i) {
            if (data[i] < other.data[i]) return true;
            if (data[i] > other.data[i]) return false;
        }
        return false;
    }

    // required to put tuples into e.g. a btree container
    bool operator>(const Tuple& other) const {
        for (std::size_t i = 0; i < arity; ++i) {
            if (data[i] > other.data[i]) return true;
            if (data[i] < other.data[i]) return false;
        }
        return false;
    }

    // allow tuples to be printed
    friend std::ostream& operator<<(std::ostream& out, const Tuple& tuple) {
        if (arity == 0) return out << "[]";
        out << "[";
        for (std::size_t i = 0; i < (std::size_t)(arity - 1); ++i) {
            out << tuple.data[i];
            out << ",";
        }
        return out << tuple.data[arity - 1] << "]";
    }
};
#endif  // _MSC_VER
}  // end of namespace souffle

// -- add hashing support --

namespace std {

template <typename Domain, std::size_t arity>
struct hash<souffle::Tuple<Domain, arity>> {
    size_t operator()(const souffle::Tuple<Domain, arity>& value) const {
        std::hash<Domain> hash;
        size_t res = 0;
        for (unsigned i = 0; i < arity; i++) {
            // from boost hash combine
            res ^= hash(value[i]) + 0x9e3779b9 + (res << 6) + (res >> 2);
        }
        return res;
    }
};
}  // namespace std