Skip to content

Commit

Permalink
More python bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
Pencilcaseman committed Oct 21, 2023
1 parent 822482f commit 663ecd7
Show file tree
Hide file tree
Showing 4 changed files with 260 additions and 14 deletions.
221 changes: 214 additions & 7 deletions librapid/bindings/generators/arrayGenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,219 @@
import module
import file

constructors = [
# Default constructor
function.Function(
name="__init__",
args=[]
),
import itertools

# The set of Array types we support in Python
arrayTypes = []

]
for scalar in [("int16_t", "Int16"),
("int32_t", "Int32"),
("int64_t", "Int64"),
("float", "Float"),
("double", "Double"),
("lrc::Complex<float>", "ComplexFloat"),
("lrc::Complex<double>", "ComplexDouble")]:
for backend in ["CPU", "OpenCL", "CUDA"]:
arrayTypes.append({
"scalar": scalar[0],
"backend": backend,
"name": f"Array{scalar[1]}{backend}"
})


def generateCppArrayType(config):
return f"lrc::Array<{config['scalar']}, lrc::backend::{config['backend']}>"


def generateCppArrayViewType(config):
return f"lrc::array::GeneralArrayView<{generateCppArrayType(config)}>"


def generateFunctionsForArray(config):
methods = [
# Default constructor
function.Function(
name="__init__",
args=[]
)
]

# Static fromData (n dimensions)
for n in range(1, 9):
cppType = ""
for j in range(n):
cppType += "std::vector<"
cppType += config['scalar'] + ">" * n

methods.append(
function.Function(
name="fromData",
args=[
argument.Argument(
name=f"array{n}D",
type=cppType,
const=True,
ref=True,
)
],
static=True,
op=f"""
return {generateCppArrayType(config)}::fromData(array{n}D);
"""
)
)

methods += [
# Shape
function.Function(
name="__init__",
args=[
argument.Argument(
name="shape",
type="lrc::Shape",
const=True,
ref=True
)
]
),

# Shape and fill
function.Function(
name="__init__",
args=[
argument.Argument(
name="shape",
type="lrc::Shape",
const=True,
ref=True
),
argument.Argument(
name="val",
type=config['scalar'],
const=True,
ref=True
)
]
),

# Copy constructor
function.Function(
name="__init__",
args=[
argument.Argument(
name="other",
type=generateCppArrayType(config),
const=True,
ref=True
)
]
),

# String representation
function.Function(
name="__str__",
args=[
argument.Argument(
name="self",
type=generateCppArrayType(config),
const=True,
ref=True
)
],
op="""
return fmt::format("{}", self);
"""
),

# String representation
function.Function(
name="__repr__",
args=[
argument.Argument(
name="self",
type=generateCppArrayType(config),
const=True,
ref=True
)
],
op=f"""
return fmt::format("<librapid.{config['name']} ~ {{}}>", self.shape());
"""
),

# Format (__format__)
function.Function(
name="__format__",
args=[
argument.Argument(
name="self",
type=generateCppArrayType(config),
const=True,
ref=True
),
argument.Argument(
name="formatSpec",
type="std::string",
const=True,
ref=True
)
],
op="""
std::string format = fmt::format("{{:{}}}", formatSpec);
return fmt::format(fmt::runtime(format), self);
"""
)
]

return methods, []


def generateArrayModule(config):
arrayClass = class_.Class(
name=config["name"],
type=generateCppArrayType(config)
)

methods, functions = generateFunctionsForArray(config)
arrayClass.functions.extend(methods)

includeGuard = None
if config["backend"] == "CUDA":
includeGuard = "defined(LIBRAPID_HAS_CUDA)"
elif config["backend"] == "OpenCL":
includeGuard = "defined(LIBRAPID_HAS_OPENCL)"

arrayModule = module.Module(
name=f"librapid.{config['name']}",
includeGuard=includeGuard
)
arrayModule.addClass(arrayClass)
arrayModule.functions.extend(functions)

return arrayModule


def writeArray(root, config):
fileType = file.File(
path=f"{root}/{config['name']}.cpp"
)

fileType.modules.append(generateArrayModule(config))

interfaceFunctions = fileType.write()
# Run clang-format if possible
try:
import subprocess

subprocess.run(["clang-format", "-i", fileType.path])
except Exception as e:
print("Unable to run clang-format:", e)

return interfaceFunctions


def write(root):
interfaces = []
for config in arrayTypes:
interfaces.extend(writeArray(root, config))
return interfaces
5 changes: 4 additions & 1 deletion librapid/bindings/generators/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import textwrap

import shapeGenerator
import arrayGenerator

outputDir = "../python/generated"

Expand All @@ -19,14 +20,16 @@
namespace lrc = librapid;
""").strip()


def main():
# Ensure the output directory exists
if not os.path.exists(outputDir):
os.makedirs(outputDir)

interfaceFunctions = []

interfaceFunctions += shapeGenerator.write(outputDir + "/shape.cpp")
interfaceFunctions += shapeGenerator.write(outputDir)
interfaceFunctions += arrayGenerator.write(outputDir)

with open(f"{outputDir}/librapidPython.hpp", "w") as f:
f.write(boilerplate)
Expand Down
21 changes: 17 additions & 4 deletions librapid/bindings/generators/module.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from class_ import Class
import textwrap


class Module:
def __init__(self, name, parentModule=None, docstring=None):
def __init__(self, name, parentModule=None, docstring=None, includeGuard=None):
self.name = name
self.parent = parentModule
self.docstring = docstring if docstring is not None else f"Bindings for {name}"
self.docstring = docstring
self.includeGuard = includeGuard
self.classes = []
self.functions = []

Expand Down Expand Up @@ -34,7 +36,8 @@ def genInterface(self):
ret += f"module.def_submodule(\"{self.name}\", \"{self.parent.name}.{self.name}\") {{\n"
moduleName = self.name

ret += f"{moduleName}.doc() = \"{self.docstring}\";\n\n"
if self.docstring is not None:
ret += f"{moduleName}.doc() = \"{self.docstring}\";\n\n"

for class_ in self.classes:
ret += class_.genInterface(moduleName)
Expand All @@ -45,7 +48,17 @@ def genInterface(self):
ret += "\n"

ret += "}\n"
return ret

if self.includeGuard is None:
return ret
else:
return textwrap.dedent(f"""
#if {self.includeGuard}
{ret}
#else
{self.genInterfaceDefinition()} {{}}
#endif
""")


if __name__ == "__main__":
Expand Down
27 changes: 25 additions & 2 deletions librapid/bindings/generators/shapeGenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,29 @@
op="""
return fmt::format("_librapid.{}", self);
"""
),

# Format (__format__)
function.Function(
name="__format__",
args=[
argument.Argument(
name="self",
type="lrc::Shape",
const=True,
ref=True
),
argument.Argument(
name="formatSpec",
type="std::string",
const=True,
ref=True
)
],
op="""
std::string format = fmt::format("{{:{}}}", formatSpec);
return fmt::format(fmt::runtime(format), self);
"""
)
]

Expand All @@ -275,9 +298,9 @@
moduleType.classes.append(classType)


def write(path):
def write(root):
fileType = file.File(
path="../python/generated/shape.cpp"
path=f"{root}/shape.cpp"
)

fileType.modules.append(moduleType)
Expand Down

0 comments on commit 663ecd7

Please sign in to comment.