1 C pointer
share/lib/std/c/cptr.flx
// move to separate file later. open class AbstractPointers { typefun rptr (T:TYPE) : TYPE => (get: 1 -> T); typefun wptr (T:TYPE) : TYPE => (set : T -> 0); typefun rwptr (T:TYPE) : TYPE => (get: 1 -> T, set : T -> 0); fun mkr[T] (p:&<T) => (get= { *p }); fun mkw[T] (p:&>T) => (set = proc (v:T) { p<-v; }); fun mkrw[T] (p:&T) => mkr p + mkw p; fun deref[T] (p: rptr T) => p.get (); proc storeat[T] (p: wptr T, v: T) { p.set v; } } open class MachinePointers { // ordinary pointers proc storeat[T:LINEAR] ( p: &>T, v: T) = { _storeat (p,v); } Dereference a Felx pointer. //fun _deref[T:LINEAR]: &<T -> T = "*$t"; //fun _deref[T:LINEAR]: &<<T -> T = "*$t"; // NOTE: at present we need all these cases because overload resolution // does not "rank" kinds .. hmm .. but even this doesn't work! // adding the RW case changes the ambiguity from the view and read only case // to the view and read/write case // looks like a problem in unification not ranking the modes fun deref[T:LINEAR] (p:&<T) => /* { println$ "deref R"; return */ _deref p; /* }(); */ fun deref[T:LINEAR] (p:&<<T) => /* { println$ "deref V"; return */ _deref p; /* }(); */ } open class CompactLinearPointers { // concrete compact linear type pointers proc storeat[D,C] ( p:_wpclt< D, C >, v: C) = { _storeat (p,v); } // deref a pointer to compact linear component //fun _deref[mach,clv]: _rpclt<mach,clv> -> clv = "::flx::rtl::clt_deref($t)"; //fun _deref[mach,clv]: _rpclt<mach,clv> -> clv = "*($t)"; // operator * added to C++ fun deref[mach,clv] (p: _rpclt<mach,clv>) => _deref p; } Felix and C pointers. Felix pointer ptr[T] = &T. C pointer cptr[T] = &T. See also carray for incrementable pointers carray[T] = +T. open class Cptr { Type of a Felix pointer. Always points to an object. Cannot be NULL. Cannot be incremented. typedef ptr[T] = &T; Type of a C pointer. Either pointes to an object or is NULL. Cannot be incremented. variant cptr[T] = | nullptr | Ptr of &T; Demote a Felix pointer to a C pointer. Safe. ctor[T] cptr[T]: &T = "$t"; Promote a C pointer to a Felix pointer. Conversion is checked. Aborts with match failure if NULL. ctor[T] ptr[T](px:cptr[T]) => let Ptr p = px in p ; // match failure if null Checked dereference of C pointer. fun deref[T] (px:cptr[T])=> *(px.ptr); Test if a C pointer is NULL. fun is_nullptr[T] (px:cptr[T])=> match px with | #nullptr => true | _ => false endmatch; instance[T] Eq[cptr[T]] { Equality of C pointers. fun == : cptr[T] * cptr[T] -> bool = "$1==$2"; } instance[T] Tord[cptr[T]] { Total ordering of C pointer. NULL is the least element. fun < : cptr[T] * cptr[T] -> bool = "$1<$2"; } Allocate unmanaged C++ object on the heap and return pointer. Felix does not check the argument type, but C++ does. The argument must select a suitable C++ constructor. gen cnew[T,A] : A -> &T = "new (?1)($a)"; Delete unmanaged C++ object from heap proc delete[T] : &T = "delete $1;"; Allocate managed C++ object directly on heap. Felix does not check the argument type, but C++ does. The argument must select a suitable constructor. gen gcnew[T,A] : A -> &T = "new (*ptf->gcp, @?1,true) (?1)($a)"; } open[T] Eq[cptr[T]]; open[T] Tord[cptr[T]]; Special notation @T for type of a C pointer. typefun n"@" (T:TYPE) : TYPE => cptr[T];
2 C Arrays
A carray[T]
, with more suggestive shorthand notation +T
,
is an incrementable, non-NULL pointer to a contiguous store.
share/lib/std/c/carray.flx
// For some reason this functor must be in global scope Define prefix + notation. typefun tprefix_plus(T:TYPE) : TYPE => Carray::carray[T]; A carray[T] = +T is an incrementable, non-NULL, pointer. open class Carray { requires Cxx_headers::cstdlib; open C_hack; The carray type. type carray[T] = new &T;
2.1 Allocation
These allocators use raw malloc
/calloc
/free
and therefore
provide store of which the garbage collector is unaware. It is best
to reserve such carrays for C datatypes.
share/lib/std/c/carray.flx
Allocate a C array on the C heap (malloc). Unsafe: Not tracked by GC. fun array_alloc[T]: !ints -> carray[T] = '(?1*)::std::malloc(sizeof(?1)*$1)'; Allocate a C array on the C heap with 0 fill (cmalloc). Unsafe: Not tracked by GC. fun array_calloc[T]: !ints -> carray[T] = '(?1*)::std::calloc(sizeof(?1),$1)'; Free a C array (free). Must point to C heap allocated storage. Unsafe. proc free[T]: carray[T] = "::std::free($1);";
2.2 Dereference
share/lib/std/c/carray.flx
Functional get by index. fun get[T]: carray[T] * !ints -> T = '$1[$2]'; Store value in array at index position. proc set[T] : carray[T] * !ints * T = "$1[$2]=$3;"; proc set[T] : carray[T] * T = "$1[0]=$2;"; proc storeat[T] (lhs: carray[T], rhs: T) { set (lhs, 0, rhs); } Get by index using application. i x = x . i = get (x,i) fun apply [T,I in ints] (i:I, x:carray[T]) => get (x,i);
2.3 Lvalue dereferences
Note that lvalue operators are for convenience of those familiar with C notation. Felix does not support the notion of lvalues in general: this is a very special case.
share/lib/std/c/carray.flx
Lvalue reference to element by index position. Unsafe. //lvalue fun subscript[T]: carray[T] * !ints -> T = '$1[$2]'; fun subscript[T]: carray[T] * !ints -> T = '$1[$2]'; Lvalue reference to element by pointer. //lvalue fun deref[T]: carray[T] -> T = '*$1'; fun deref[T]: carray[T] -> T = '*$1';
2.4 Pointer operators
share/lib/std/c/carray.flx
Advance carray to next element. fun + [T]: carray[T] * !ints -> carray[T]= '$1+$2'; Backup carray to previous element. fun - [T]: carray[T] * !ints -> carray[T] = '$1-$2'; Calculate the offset in elements between two overlapping carrays. fun - [T]: carray[T] * carray[T]-> ptrdiff = '$1-$2';
2.5 Mutators
share/lib/std/c/carray.flx
Mutable pre-increment ++p. proc pre_incr[T]: &carray[T] = '++*$1;'; Mutable post-increment p++. proc post_incr[T]: &carray[T] = '(*$1)++;'; Mutable pre-decarement --p. proc pre_decr[T]: &carray[T] = '--*$1;'; Mutable post-decarement p--. proc post_decr[T]: &carray[T] = '(*$1)--;'; Mutable advance by offset amount. proc += [T]: &carray[T] * !ints = '*$1+=$2;'; Mutable backup by offset amount. proc -= [T]: &carray[T] * !ints = '*$1-=$2;';
2.6 Comparisons
share/lib/std/c/carray.flx
Pointer equality. instance[T] Eq[carray[T]] { fun == : carray[T] * carray[T] -> bool = '$1==$2'; fun != : carray[T] * carray[T] -> bool = '$1!=$2'; } Pointer total ordering. instance[T] Tord[carray[T]] { fun < : carray[T] * carray[T] -> bool = '$1<$2'; fun <= : carray[T] * carray[T] -> bool = '$1<=$2'; fun > : carray[T] * carray[T] -> bool = '$1>$2'; fun >= : carray[T] * carray[T] -> bool = '$1>=$2'; }
2.7 Conversions
share/lib/std/c/carray.flx
Get carray of an array. fun stl_begin[T,N:COMPACTLINEAR]: carray[array[T,N]] -> carray[T] = "(?1*)&($1->data)"; Unsafe conversion of Felix pointer to carray. fun prefix_plus [T]:&T -> carray[T] = "$t"; // unsafe Demote carray to Felix pointer (safe unless off the end). fun neg [T]: carray[T] -> &T = "$t"; // safe (unless we allow +T to be NULL later ..) Unsafe conversion of Felix pointer to carray. ctor[T] carray[T] : &T = "$t"; Get a carray from a Felix array object. ctor[T,N:COMPACTLINEAR] carray[T]: &array[T,N] = "($1)->data"; Convert C array to Felix array. fun array_of[T,N:COMPACTLINEAR]: carray[T] -> &array[T,N] = "*(#0*)(void*)$1"; } open[T] Eq[carray[T]]; open[T] Tord[carray[T]];
test/regress/rt/carray_test.flx
// carray test var a : +int = array_alloc[int] 10; for var i in 0 upto 9 do set(a, i, i * i); set(a,i,get(a,i)+1); done for i in 0 upto 9 do println$ a.[i], *(a+i), a.i; done free a;
test/regress/rt/carray_test.expect
(1, 1, 1) (2, 2, 2) (5, 5, 5) (10, 10, 10) (17, 17, 17) (26, 26, 26) (37, 37, 37) (50, 50, 50) (65, 65, 65) (82, 82, 82)
3 Array sort
Sort an array using STL sort.
share/lib/std/datatype/sort.flx
Utility class to leverage STL sort. class Sort { STL compliant comparator object built from a closure of a Felix function. private header stl_comparator_def = """ """ requires Cxx_headers::utility; private type _comparator[CT,FT2,FFT] = "comparator<?1,?2,?3>" requires stl_comparator_def; type stl_comparator[T] = new _comparator[T,T*T,T*T->bool]; private fun _make_comparator[CT,FT2,FFT]: FFT -> stl_comparator[CT] = "comparator<?1,?2,?3>($1)" ; Make a C++ STL comparator object from a Felix comparison function. ctor[T] stl_comparator[T] (cmp:T * T -> bool) => _make_comparator[T, T*T, T*T->bool] (cmp) ; Invoke stl sort with C++ comparator. proc stl_sort[T]: stl_comparator[T] * +T * +T = "::std::sort($2, $3, $1);" requires Cxx_headers::algorithm; Invoke stl sort with Felix comparison function. inline proc stl_sort[T] (cmp: T * T -> bool, b: +T, e:+T) => stl_sort (stl_comparator cmp, b, e) ; Invoke stl sort default comparison function. inline proc stl_sort[T with Tord[T]] (b:+T, e:+T) => stl_sort ( (< of (T * T)), b, e); }
4 Reference counting pointer.
share/lib/std/c/shared_ptr.flx
open class SharedPtr { type shared_ptr[T] = "::std::shared_ptr<?1>" requires Cxx_headers::memory ; ctor[T] shared_ptr[T] : 1 = "::std::shared_ptr<?1>()"; // nullptr ctor[T] shared_ptr[T] : &T = "::std::shared_ptr<?1>($1)"; proc reset[T] : &shared_ptr[T] = "$1->reset();"; proc swap[T] : &shared_ptr[T] * &shared_ptr[T] = "$1->swap(*$2);"; fun get[T] : shared_ptr[T] -> &T = "$1.get()"; fun deref[T] : shared_ptr[T] -> T = "*$1"; fun use_count[T] : shared_ptr[T] -> long = "$1.use_count()"; fun unique[T] : shared_ptr[T] -> bool = "$1.unique"; fun is_null[T] : shared_ptr[T] -> bool = "(bool)$1"; }
5 MMap
Address mapping facility. Note: this is the posix function mmap(). Windows has a similar capability we have not modelled yet.
share/lib/std/posix/mmap.flx
class Mmap { requires package "mmap"; header """ """; // Offset into file, should be defined elsewhere typedef off_t = ulong; type mmap_prot = "int"; instance Eq[mmap_prot]{ fun == : mmap_prot * mmap_prot -> bool = "$1==$2"; } instance Bits[mmap_prot]{} inherit Eq[mmap_prot]; inherit Bits[mmap_prot]; type mmap_flags = "int"; instance Eq[mmap_flags]{ fun == : mmap_flags * mmap_flags -> bool = "$1==$2"; } instance Bits[mmap_flags]{} inherit Eq[mmap_flags]; inherit Bits[mmap_flags]; // protection options const PROT_NONE : mmap_prot; // Posix: inaccessible const PROT_EXEC : mmap_prot; // Posix: allow exec const PROT_READ : mmap_prot; // Posix: allow read (and perhaps exec) const PROT_WRITE : mmap_prot; // Posix: allow write (and perhaps write and exec) // Linux only const MAP_DENYWRITE: mmap_flags; // Linux only // flags: mode const MAP_FILE: mmap_flags; // Posix: Default mode: map a file const MAP_ANONYMOUS: mmap_flags; // Linux, OSX: Map from VM pool // flags: map address const MAP_FIXED: mmap_flags; // Posix: Client tries to fix the mapping address, // must set address argument non-NULL // Implementation dependent // Default: system chooses address is not specified // must set address NULL // flags: sharing const MAP_SHARED : mmap_flags; // Posix: write changes to backing store on msync const MAP_PRIVATE : mmap_flags; // Posix: don't write changes ever // System dependent: const MAP_HASSEMAPHORE: mmap_flags; const MAP_NORESERVE: mmap_flags; const MAP_LOCKED: mmap_flags; const MAP_GROWSDOWN: mmap_flags; const MAP_32BIT: mmap_flags; const MAP_POPULATE: mmap_flags; const MAP_NONBLOCK: mmap_flags; // return value of mmap const MAP_FAILED : address; // size of a page const _SC_PAGESIZE : long = "sysconf(_SC_PAGESIZE)"; // establish a mapping fun mmap: address * //< start address size * //< bytes to map mmap_prot * //< protection mmap_flags * //< flags int * //< file descriptor off_t //< offset into file, multiple of _SC_PAGESIZE -> address; //< start of reserved address space // unmap a region fun munmap: address * size -> int; // save region to backing store (MAP_SHARED only) fun msync: address * size * int -> int; }