13 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: 
 25: 
 26: 
 27: 
 28: 
 29: 
 30: 
 31: 
 32: 
 33: 
 34: 
 35: 
 36: 
 37: 
 38: 
 39: 
 40: 
 41: 
 42: 
 43: 
 44: 
 45: 
 46: 
 47: 
 48: 
 49: 
 50: 
 51: 
 52: 
 53: 
 54: 
 55: 
 56: 
 57: 
 58: 
 59: 
 60: 
 61: 
 62: 
 63: 
 64: 
 65: 
 66: 
 67: 
 68: 
 69: 
 70: 
 71: 
 72: 
 73: 
 74: 
 75: 
 76: 
 77: 
 78: 
 79: 
 80: 
 81: 
 82: 
 83: 
 84: 
 85: 
 86: 
 87: 
 88: 
 89: 
 90: 
 91: 
 92: 
 93: 
 94: 
 95: 
 96: 
 97: 
 98: 
 99: 
100: 
101: 
102: 
103: 
104: 
105: 
106: 
107: 
108: 
109: 
110: 
111: 
112: 
113: 
114: 
115: 
116: 
117: 
118: 
119: 
120: 
(*[omit:boyer-moore.c]
/*
    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 "";
} 
[/omit]*)
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"
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
Next Version Raw view Test code New version

More information

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