-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 469fa3f
Showing
51 changed files
with
6,080 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
Oops, something went wrong.