9 people like it.

F# yet another Interop example

Quick demo of using F# to interop with a native C library. C Library has not been checked for algorithm correctness (but works exactly as the origional).

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
boyer-moore.c
module native = 
  module string_search = 
    open System.Text
    open System.Runtime.InteropServices
    
    [<DllImport(@"boyermoore.dll", EntryPoint="boyerMoore", CharSet = CharSet.Ansi)>]
    extern nativeint boyerMoore(nativeint data, nativeint search)
    
    let alloc_a (data : string) = 
      let strbuf = Encoding.UTF8.GetBytes data
      let buffer = Marshal.AllocHGlobal(strbuf.Length + 1)
      Marshal.Copy(strbuf, 0, buffer, strbuf.Length)
      Marshal.WriteByte( buffer + (nativeint strbuf.Length), 0uy)
      buffer

    let bMoore data search =
      let d,s = alloc_a <| data, alloc_a <| search
      let x = Marshal.PtrToStringAnsi(boyerMoore(d,s) )
      Marshal.FreeHGlobal d
      Marshal.FreeHGlobal s 
      x
    
native.string_search.bMoore "aaaabouaaa384982n chwercoiewar45u0943 twert3aaaaaaMarabou t9034u5t09t8493t43vkdsropgb" "Marabou"
(*
/*
    Simple implementation of the fast Boyer-Moore string search algorithm.

    By X-Calibre, 2002
    
    - slight modifications by davidk (main removed, cdecl added, casting for return types)
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <strsafe.h>

#define EXTERN_DLL_EXPORT extern "C" __declspec(dllexport)

char *BoyerMoore( unsigned char *data, unsigned int dataLength, unsigned char *string, unsigned int strLength ) {
    unsigned int skipTable[256], i;
    unsigned char *search;
    register unsigned char lastChar;

    if (strLength == 0)
        return NULL;

    // Initialize skip lookup table
    for (i = 0; i < 256; i++)
        skipTable[i] = strLength;

    search = string;

    // Decrease strLength here to make it an index
    i = --strLength;

    do
    {
        skipTable[*search++] = i;
    } while (i--);

    lastChar = *--search;

    // Start searching, position pointer at possible end of string.
    search = data + strLength;
    dataLength -= strLength+(strLength-1);

    while ((int)dataLength > 0 )
    {
        unsigned int skip;

        skip = skipTable[*search];
        search += skip;
        dataLength -= skip;
        skip = skipTable[*search];
        search += skip;
        dataLength -= skip;
        skip = skipTable[*search];

        if (*search != lastChar) /*if (skip > 0)*/
        {
            // Character does not match, realign string and try again
            search += skip;
            dataLength -= skip;
            continue;
        }

        // We had a match, we could be at the end of the string
        i = strLength;

        do
        {
            // Have we found the entire string?
            if (i-- == 0)
                return (char * )search;
        } while (*--search == string[i]);

        // Skip past the part of the string that we scanned already
        search += (strLength - i + 1);
        dataLength--;
    }

    // We reached the end of the data, and didn't find the string
    return NULL;
}

EXTERN_DLL_EXPORT
char *boyerMoore(unsigned char *data, unsigned char *search) {

    char *str = BoyerMoore( data, strlen((const char *)data), search, strlen((const char *)search) );

    if (str == NULL)
       return "String not found";
    else
       return str;

    return "";
}
*)
module string_search

from Script.native
namespace System
namespace System.Text
namespace System.Runtime
namespace System.Runtime.InteropServices
Multiple items
type DllImportAttribute =
  inherit Attribute
  new : dllName:string -> DllImportAttribute
  val EntryPoint : string
  val CharSet : CharSet
  val SetLastError : bool
  val ExactSpelling : bool
  val PreserveSig : bool
  val CallingConvention : CallingConvention
  val BestFitMapping : bool
  val ThrowOnUnmappableChar : bool
  member Value : string

Full name: System.Runtime.InteropServices.DllImportAttribute

--------------------
DllImportAttribute(dllName: string) : unit
Multiple items
type EntryPointAttribute =
  inherit Attribute
  new : unit -> EntryPointAttribute

Full name: Microsoft.FSharp.Core.EntryPointAttribute

--------------------
new : unit -> EntryPointAttribute
type CharSet =
  | None = 1
  | Ansi = 2
  | Unicode = 3
  | Auto = 4

Full name: System.Runtime.InteropServices.CharSet
field CharSet.Ansi = 2
Multiple items
val nativeint : value:'T -> nativeint (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.nativeint

--------------------
type nativeint = System.IntPtr

Full name: Microsoft.FSharp.Core.nativeint
val boyerMoore : data:nativeint * search:nativeint -> nativeint

Full name: Script.native.string_search.boyerMoore
val data : nativeint
val search : nativeint
val alloc_a : data:string -> nativeint

Full name: Script.native.string_search.alloc_a
val data : string
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = System.String

Full name: Microsoft.FSharp.Core.string
val strbuf : byte []
type Encoding =
  member BodyName : string
  member Clone : unit -> obj
  member CodePage : int
  member DecoderFallback : DecoderFallback with get, set
  member EncoderFallback : EncoderFallback with get, set
  member EncodingName : string
  member Equals : value:obj -> bool
  member GetByteCount : chars:char[] -> int + 3 overloads
  member GetBytes : chars:char[] -> byte[] + 5 overloads
  member GetCharCount : bytes:byte[] -> int + 2 overloads
  ...

Full name: System.Text.Encoding
property Encoding.UTF8: Encoding
Encoding.GetBytes(s: string) : byte []
Encoding.GetBytes(chars: char []) : byte []
Encoding.GetBytes(chars: char [], index: int, count: int) : byte []
Encoding.GetBytes(chars: nativeptr<char>, charCount: int, bytes: nativeptr<byte>, byteCount: int) : int
Encoding.GetBytes(s: string, charIndex: int, charCount: int, bytes: byte [], byteIndex: int) : int
Encoding.GetBytes(chars: char [], charIndex: int, charCount: int, bytes: byte [], byteIndex: int) : int
val buffer : nativeint
type Marshal =
  static val SystemDefaultCharSize : int
  static val SystemMaxDBCSCharSize : int
  static member AddRef : pUnk:nativeint -> int
  static member AllocCoTaskMem : cb:int -> nativeint
  static member AllocHGlobal : cb:nativeint -> nativeint + 1 overload
  static member AreComObjectsAvailableForCleanup : unit -> bool
  static member BindToMoniker : monikerName:string -> obj
  static member ChangeWrapperHandleStrength : otp:obj * fIsWeak:bool -> unit
  static member CleanupUnusedObjectsInCurrentContext : unit -> unit
  static member Copy : source:int[] * startIndex:int * destination:nativeint * length:int -> unit + 15 overloads
  ...

Full name: System.Runtime.InteropServices.Marshal
Marshal.AllocHGlobal(cb: int) : nativeint
Marshal.AllocHGlobal(cb: nativeint) : nativeint
property System.Array.Length: int
Marshal.Copy(source: nativeint, destination: nativeint [], startIndex: int, length: int) : unit
   (+0 other overloads)
Marshal.Copy(source: nativeint, destination: byte [], startIndex: int, length: int) : unit
   (+0 other overloads)
Marshal.Copy(source: nativeint, destination: float [], startIndex: int, length: int) : unit
   (+0 other overloads)
Marshal.Copy(source: nativeint, destination: float32 [], startIndex: int, length: int) : unit
   (+0 other overloads)
Marshal.Copy(source: nativeint, destination: int64 [], startIndex: int, length: int) : unit
   (+0 other overloads)
Marshal.Copy(source: nativeint, destination: int16 [], startIndex: int, length: int) : unit
   (+0 other overloads)
Marshal.Copy(source: nativeint, destination: char [], startIndex: int, length: int) : unit
   (+0 other overloads)
Marshal.Copy(source: nativeint, destination: int [], startIndex: int, length: int) : unit
   (+0 other overloads)
Marshal.Copy(source: nativeint [], startIndex: int, destination: nativeint, length: int) : unit
   (+0 other overloads)
Marshal.Copy(source: byte [], startIndex: int, destination: nativeint, length: int) : unit
   (+0 other overloads)
Marshal.WriteByte(ptr: nativeint, val: byte) : unit
Marshal.WriteByte(ptr: obj, ofs: int, val: byte) : unit
Marshal.WriteByte(ptr: nativeint, ofs: int, val: byte) : unit
val bMoore : data:string -> search:string -> string

Full name: Script.native.string_search.bMoore
val search : string
val d : nativeint
val s : nativeint
val x : string
Marshal.PtrToStringAnsi(ptr: nativeint) : string
Marshal.PtrToStringAnsi(ptr: nativeint, len: int) : string
Marshal.FreeHGlobal(hglobal: nativeint) : unit
module native

from Script

More information

Link:http://fssnip.net/c1
Posted:4 years ago
Author:David Klein
Tags: f# , interop , boyer moore , string matching