Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
268 changes: 268 additions & 0 deletions src/include/souffle/swig/SwigInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,250 @@
#pragma once

#include "souffle/SouffleInterface.h"
#include <cstdint>
#include <iostream>
#include <string>

// Forward declarations
class SWIGRelation;
class SWIGTuple;
class SWIGRelationIterator;

/**
* Wrapper class for souffle::tuple
* Provides simple methods instead of C++ operator overloading
*/
class SWIGTuple {
souffle::tuple* tuple;
souffle::Relation* relation;
bool owning; // Whether we own the tuple memory

public:
/**
* Constructor for creating a new tuple for insertion
*/
SWIGTuple(souffle::Relation* rel) : relation(rel), owning(true) {
tuple = new souffle::tuple(rel);
}

/**
* Constructor for wrapping an existing tuple (from iteration)
*/
SWIGTuple(souffle::tuple* t, souffle::Relation* rel) : tuple(t), relation(rel), owning(true) {}

~SWIGTuple() {
if (owning && tuple) {
delete tuple;
}
}

/**
* Push a string value into the tuple
*/
void putString(const std::string& val) {
*tuple << val;
}

/**
* Push a signed integer value into the tuple
*/
void putInt(long val) {
*tuple << static_cast<souffle::RamSigned>(val);
}

/**
* Push an unsigned integer value into the tuple
*/
void putUInt(unsigned long val) {
*tuple << static_cast<souffle::RamUnsigned>(val);
}

/**
* Push a float value into the tuple
*/
void putFloat(double val) {
*tuple << static_cast<souffle::RamFloat>(val);
}

/**
* Get the next string value from the tuple
*/
std::string getString() {
std::string val;
*tuple >> val;
return val;
}

/**
* Get the next signed integer value from the tuple
*/
long getInt() {
souffle::RamSigned val;
*tuple >> val;
return static_cast<long>(val);
}

/**
* Get the next unsigned integer value from the tuple
*/
unsigned long getUInt() {
souffle::RamUnsigned val;
*tuple >> val;
return static_cast<unsigned long>(val);
}

/**
* Get the next float value from the tuple
*/
double getFloat() {
souffle::RamFloat val;
*tuple >> val;
return static_cast<double>(val);
}

/**
* Reset the read/write position to the beginning
*/
void rewind() {
tuple->rewind();
}

/**
* Get the number of elements in the tuple
*/
size_t size() {
return tuple->size();
}

/**
* Get the internal tuple pointer (for use by other wrapper classes)
*/
souffle::tuple* getInternalTuple() {
return tuple;
}
};

/**
* Iterator wrapper for iterating over relation tuples
*/
class SWIGRelationIterator {
souffle::Relation::iterator current;
souffle::Relation::iterator end;
souffle::Relation* relation;

public:
SWIGRelationIterator(souffle::Relation* rel)
: current(rel->begin()), end(rel->end()), relation(rel) {}

/**
* Get the next tuple, or nullptr if iteration is complete
*/
SWIGTuple* next() {
if (current == end) {
return nullptr;
}
// Create a copy of the current tuple
souffle::tuple* t = new souffle::tuple(*current);
++current;
return new SWIGTuple(t, relation);
}

/**
* Check if there are more tuples to iterate
*/
bool hasNext() {
return current != end;
}
};

/**
* Wrapper class for souffle::Relation
*/
class SWIGRelation {
souffle::Relation* relation;

public:
SWIGRelation(souffle::Relation* rel) : relation(rel) {}

/**
* Create a new empty tuple for this relation
*/
SWIGTuple* createTuple() {
return new SWIGTuple(relation);
}

/**
* Insert a tuple into the relation
*/
void insert(SWIGTuple* tuple) {
relation->insert(*tuple->getInternalTuple());
}

/**
* Check if the relation contains the given tuple
*/
bool contains(SWIGTuple* tuple) {
return relation->contains(*tuple->getInternalTuple());
}

/**
* Get an iterator for this relation
*/
SWIGRelationIterator* iterator() {
return new SWIGRelationIterator(relation);
}

/**
* Get the name of the relation
*/
std::string getName() {
return relation->getName();
}

/**
* Get the number of tuples in the relation
*/
size_t size() {
return relation->size();
}

/**
* Get the arity (number of columns) of the relation
*/
size_t getArity() {
return relation->getArity();
}

/**
* Get the type of an attribute at the given index
* Returns: "s" (symbol), "i" (signed), "u" (unsigned), "f" (float), "r" (record), "+" (ADT)
*/
std::string getAttrType(size_t index) {
return std::string(relation->getAttrType(index));
}

/**
* Get the name of an attribute at the given index
*/
std::string getAttrName(size_t index) {
return std::string(relation->getAttrName(index));
}

/**
* Get the signature of the relation (e.g., "<s:Node,s:Node>")
*/
std::string getSignature() {
return relation->getSignature();
}

/**
* Remove all tuples from the relation
*/
void purge() {
relation->purge();
}
};

/**
* Abstract base class for generated Datalog programs
*/
Expand Down Expand Up @@ -77,6 +318,33 @@ class SWIGSouffleProgram {
void dumpOutputs() {
program->dumpOutputs();
}

/**
* Get a relation by name
* @param name The name of the relation
* @return A SWIGRelation wrapper, or nullptr if not found
*/
SWIGRelation* getRelation(const std::string& name) {
souffle::Relation* rel = program->getRelation(name);
if (rel == nullptr) {
return nullptr;
}
return new SWIGRelation(rel);
}

/**
* Set the number of threads to use for parallel execution
*/
void setNumThreads(size_t num) {
program->setNumThreads(num);
}

/**
* Get the number of threads used for parallel execution
*/
size_t getNumThreads() {
return program->getNumThreads();
}
};

/**
Expand Down
43 changes: 39 additions & 4 deletions src/include/souffle/swig/SwigInterface.i
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
*
***********************************************************************/

%module SwigInterface
%include "std_string.i"
%include "std_map.i"
%module SwigInterface
%include "std_string.i"
%include "std_map.i"
%include<std_vector.i>
namespace std {
%template(map_string_string) map<string, string>;
Expand All @@ -35,6 +35,41 @@ souffle::Relation* rel;
souffle::Relation* rel_out;
%}

%include "SwigInterface.h"
// Memory management directives - tell SWIG these methods return new objects
%newobject newInstance;
%newobject SWIGSouffleProgram::getRelation;
%newobject SWIGRelation::createTuple;
%newobject SWIGRelation::iterator;
%newobject SWIGRelationIterator::next;

%include "SwigInterface.h"

SWIGSouffleProgram* newInstance(const std::string& name);

// Python-specific extensions for iteration support
#ifdef SWIGPYTHON
%extend SWIGRelation {
%pythoncode %{
def __iter__(self):
"""Iterate over all tuples in this relation"""
it = self.iterator()
while True:
t = it.next()
if t is None:
break
yield t

def __len__(self):
"""Return the number of tuples in this relation"""
return self.size()
%}
}

%extend SWIGTuple {
%pythoncode %{
def __len__(self):
"""Return the number of elements in this tuple"""
return self.size()
%}
}
#endif
4 changes: 4 additions & 0 deletions tests/swig/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,7 @@ souffle_positive_swig_test(flights)
souffle_positive_swig_test(insert_for)
souffle_positive_swig_test(movies)
souffle_positive_swig_test(paths)
souffle_positive_swig_test(test_relation_insert COMPARE_STDOUT)
souffle_positive_swig_test(test_relation_iterate COMPARE_STDOUT)
souffle_positive_swig_test(test_relation_contains COMPARE_STDOUT)
souffle_positive_swig_test(test_relation_types COMPARE_STDOUT)
Loading