Skip to content

Commit

Permalink
deploy
Browse files Browse the repository at this point in the history
  • Loading branch information
actions-user committed Aug 16, 2023
0 parents commit de05c9e
Show file tree
Hide file tree
Showing 51 changed files with 6,041 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .buildinfo
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: 8096177844411c4989a20708e37b5460
tags: 645f666f9bcd5a90fca523b33c5a78b7
Empty file added .nojekyll
Empty file.
17 changes: 17 additions & 0 deletions _sources/getting_started.md.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Getting Started
===============

fficxx is mainly packaged in nix.
`shell.nix` is for development,
```
nix-shell shell.nix
```
and `use.nix` is for using the generated binding package.
```
nix-shell use.nix
```

For all build,
```
nix-build release.nix
```
41 changes: 41 additions & 0 deletions _sources/index.rst.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
.. fficxx documentation master file, created by
sphinx-quickstart on Thu Dec 29 11:23:22 2022.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to fficxx's documentation!
==================================

fficxx ("eff fix") is an automatic haskell Foreign Function Interface (FFI) generator to C++.

To use fficxx, you write a Haskell model of the C++ public interfaces and fficxx generates both a C wrapper and associated haskell functions and type classes which reflect specified model of the C++ interfaces. It is currently the user's responsibility to specify a correct model of the C++ interfaces, because fficxx does not presently check for model correctness.

While haskell has a well-specified standard for C FFI, making haskell-C++ FFI is an arbitrary and painful process. Since Object-Oriented Programming (OOP) paradigm and Functional Programming (FP) paradigm are different, automatic translation of C++ libraries to haskell libraries is not a straightforward task. The goal of fficxx is to minimize this disparity and maximize user's convenience by providing familiar interface to the original C++ library as a result.

Public Haskell-C++ binding generated by fficxx are now collected in `fficxx-projects <https://github.com/wavewave/fficxx-projects>`_.

fficxx is separated into generator part and runtime part:

* fficxx : FFI types and binding generator library
* fficxx-runtime : runtime modules needed for various common routines

Haskell packages that are generated from fficxx will be dependent on fficxx-runtime.

In addition, C++ standard library under `std` namespace is being generated as a package from fficxx.
* stdcxx: generated by ./stdcxx-gen/Gen.hs

.. toctree::
:maxdepth: 2
:caption: Contents:

getting_started
oop_model_in_fficxx
real_world_usage
references

Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
90 changes: 90 additions & 0 deletions _sources/oop_model_in_fficxx.md.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
OOP Model in fficxx
===================

fficxx generates haskell codes at raw level (C wrapper and haskell foreign pointer that are directly matched with C/C++ types) and at high level (newtype wrapper for raw level pointer and haskell typeclasses reflecting OOP class hierarchy). Haskell does not have a concept of subtyping, i.e. we do not provide any easy way to create a new subclass and overload member functions from existing classes on haskell side. However, fortunately, one can describe the OOP subclass relationship using a typeclass interface as a contract for a class `b` to be equal to or a subclass of `a`. In a sense, typeclasses are Interface Definition Language (IDL) for describing OOP classes. Thus, a C++ class is represented by both haskell concrete type (for a C++ class itself) and typeclass (a set of classes that can be equal to or a subclass of the C++ class).

Assuming that there is a C++ class `A`. fficxx generates a haskell type `A`. This haskell type `A` is nothing but a newtype wrapping `ForeignPtr` tagged by `RawA`.
```
data RawA

newtype A = A (ForeignPtr RawA)
```
`RawA` exists only for the purpose of a phantom type to be used as tags for `Ptr` in FFI imports (`foreign import` statements.) When programming with fficxx-generated code at high level, programmers should seldom encounter `Raw` types. An instance object of C++ class `A` is a value of haskell type `A`. To create an instance, fficxx provides a smart constructor (`newA`) if specified with a corresponding constructor.

Therefore, one can create an instance from a concrete haskell type, and pass it to any functions which needs them. On Haskell side, member functions of a C++ class are nothing but functions whose first argument is the same as the corresponding haskell type to the class. For example, if the class `A` has a member function `foo` of signature `void A::foo( int param )`, then fficxx generates a high level function
```
foo :: A -> CInt -> IO ()
```
which is a wrapper for a raw level FFI call defined by
```
foriegn import ccall "A_foo" c_foo :: Ptr RawA -> CInt -> IO ()
```
where `A_foo` is a generated C shim function for `A::foo`. So one can translate the following C++ code
```
A* a = new A();
a->foo(3);
```
to the haskell code (in do-block of IO monad)
```
do a <- newA
foo a 3
```
Haskell type `A` can be used in the arbitrary argument position. Assume there is another member function `bar` of `A` which takes an object of `A` as an argument like `void A::bar( A* a )`. Then, we have
```
bar :: A -> A -> IO ()
```
for which `x->bar(y)` (`x`,`y` are of class `A`) corresponds to `bar x y`.

In this example, the C++ class `A` may have the following declaration:
```
class A
{
public:
A();
virtual void foo( int );
virtual void bar( A* );
};
```
To reflect subtype relations, fficxx creates an interface typeclass `IA` for `A`, which is defined as
```
class IA a where
foo :: a -> CInt -> IO ()
bar :: (IA b) => a -> b -> IO ()
```
which declares all C++ virtual functions as members. Then, haskell type `A` is a typeclass instance of `IA`:
```
instance IA A where
-- foo :: A -> CInt -> IO ()
foo = ...
-- bar :: (IA b) => A -> b -> IO ()
bar = ...
```
so that `foo` and `bar` functions we considered in the above example were actually defined in the `IA` instance definition of A.
Note that the type signature of `bar` allows generic typeclass instances of `IA` as the argument (paraterized by `b`).

Now consider another C++ class `B` which is a subclass of `A`:
```
class B : public A
{
public:
B();
virtual int baz() ;
}
```
Again, we will have a concrete haskell type `B` and an object of `B` will be created as a value from the `newB` constructor function.
A typeclass `IB` is also generated as well, and it reflects the inheritance relationship for C++ class as constraints:
```
class (IA b) => IB b where
baz :: b -> IO CInt
```
Thanks to the constraints `(IA b) =>` in the declaration, every instance of `IB` must have implementation of `IA`. This is true for `B`, too.
So fficxx generates
```
instance IA B where
foo = ...
bar = ...

instance IB B where
baz = ...
```
This instance generation (*implemenation of C++ class*) is automaticaly done by fficxx, but it's not guaranteed for future subclassing. Any type which implements instances of `IA` and `IB` can be regarded as a subclass of `B`, but it's not automatically done as we have in OOP. The scope of fficxx is to generate such implementations only for existing C++ classes.
18 changes: 18 additions & 0 deletions _sources/real_world_usage.md.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Real World Usage
================

## Projects

### HROOT
[ROOT](https://root.cern.ch) is a modular scientific software toolkit providing all the functionalities needed to deal with big data processing, statistical analysis, visualisation and storage. It is mainly written in C++ but integrated with other languages.

[HROOT](http://ianwookim.org/HROOT) is a haskell binding to the [ROOT](https://root.cern.ch) library. A haskell script called [HROOT-generate](http://github.com/wavewave/HROOT/blob/master/HROOT-generate) using fficxx generates HROOT packages. Once generated, each package can be directly installable as a cabal package. Currently, C++ interface is defined as a haskell data structure as one can see, for example, in the module [HROOT.Data.Core.Class](https://github.com/wavewave/HROOT/blob/master/HROOT-generate/lib/HROOT/Data/Core/Class.hs).

### hgdal
[GDAL](https://gdal.org) is a translator library for raster and vector geospatial data formats that is released under an X/MIT style Open Source License by the Open Source Geospatial Foundation. As a library, it presents a single raster abstract data model and single vector abstract data model to the calling application for all supported formats. It also comes with a variety of useful command line utilities for data translation and processing.

### hs-ogdf
[OGDF](https://ogdf.uos.de/) stands both for Open Graph Drawing Framework (the original name) and Open Graph algorithms and Data structures Framework.

OGDF is a self-contained C++ library for graph algorithms, in particular for (but not restricted to) automatic graph drawing. It offers sophisticated algorithms and data structures to use within your own applications or scientific projects. The library is available under the GNU General Public License.

21 changes: 21 additions & 0 deletions _sources/references.md.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
References
==========

## C Macro tricks

We use C Macro tricks described in the following:
* [C Pre-Processor Magic](http://jhnet.co.uk/articles/cpp_magic)
* [C Macros: How to map another macro to variadic arguments?](https://stackoverflow.com/questions/45585903/c-macros-how-to-map-another-macro-to-variadic-arguments)
* [C Preprocessor tricks, tips, and idioms](https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms)
* [Detect empty macro arguments](https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/)
* [Optional Parameters with C++ Macros](https://stackoverflow.com/questions/3046889/optional-parameters-with-c-macros/3048361#3048361)

## C++ Template tricks

* [Template argument deduction](https://en.cppreference.com/w/cpp/language/template_argument_deduction)
* [C++ variadic templates](http://anderberg.me/2016/08/01/c-variadic-templates/)
* [Practical uses for variadic templates](https://crascit.com/2015/03/21/practical-uses-for-variadic-templates/)

## C++ Template Peculiarity

* [Can a class member function template be virtual?](https://stackoverflow.com/questions/2354210/can-a-c-class-member-function-template-be-virtual)
123 changes: 123 additions & 0 deletions _static/_sphinx_javascript_frameworks_compat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/* Compatability shim for jQuery and underscores.js.
*
* Copyright Sphinx contributors
* Released under the two clause BSD licence
*/

/**
* small helper function to urldecode strings
*
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL
*/
jQuery.urldecode = function(x) {
if (!x) {
return x
}
return decodeURIComponent(x.replace(/\+/g, ' '));
};

/**
* small helper function to urlencode strings
*/
jQuery.urlencode = encodeURIComponent;

/**
* This function returns the parsed url parameters of the
* current request. Multiple values per key are supported,
* it will always return arrays of strings for the value parts.
*/
jQuery.getQueryParameters = function(s) {
if (typeof s === 'undefined')
s = document.location.search;
var parts = s.substr(s.indexOf('?') + 1).split('&');
var result = {};
for (var i = 0; i < parts.length; i++) {
var tmp = parts[i].split('=', 2);
var key = jQuery.urldecode(tmp[0]);
var value = jQuery.urldecode(tmp[1]);
if (key in result)
result[key].push(value);
else
result[key] = [value];
}
return result;
};

/**
* highlight a given string on a jquery object by wrapping it in
* span elements with the given class name.
*/
jQuery.fn.highlightText = function(text, className) {
function highlight(node, addItems) {
if (node.nodeType === 3) {
var val = node.nodeValue;
var pos = val.toLowerCase().indexOf(text);
if (pos >= 0 &&
!jQuery(node.parentNode).hasClass(className) &&
!jQuery(node.parentNode).hasClass("nohighlight")) {
var span;
var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg");
if (isInSVG) {
span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
} else {
span = document.createElement("span");
span.className = className;
}
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
node.parentNode.insertBefore(span, node.parentNode.insertBefore(
document.createTextNode(val.substr(pos + text.length)),
node.nextSibling));
node.nodeValue = val.substr(0, pos);
if (isInSVG) {
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
var bbox = node.parentElement.getBBox();
rect.x.baseVal.value = bbox.x;
rect.y.baseVal.value = bbox.y;
rect.width.baseVal.value = bbox.width;
rect.height.baseVal.value = bbox.height;
rect.setAttribute('class', className);
addItems.push({
"parent": node.parentNode,
"target": rect});
}
}
}
else if (!jQuery(node).is("button, select, textarea")) {
jQuery.each(node.childNodes, function() {
highlight(this, addItems);
});
}
}
var addItems = [];
var result = this.each(function() {
highlight(this, addItems);
});
for (var i = 0; i < addItems.length; ++i) {
jQuery(addItems[i].parent).before(addItems[i].target);
}
return result;
};

/*
* backward compatibility for jQuery.browser
* This will be supported until firefox bug is fixed.
*/
if (!jQuery.browser) {
jQuery.uaMatch = function(ua) {
ua = ua.toLowerCase();

var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
/(webkit)[ \/]([\w.]+)/.exec(ua) ||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
/(msie) ([\w.]+)/.exec(ua) ||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
[];

return {
browser: match[ 1 ] || "",
version: match[ 2 ] || "0"
};
};
jQuery.browser = {};
jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;
}

0 comments on commit de05c9e

Please sign in to comment.