6.5 FParsec.StaticMapping

This module defines functions for creating optimized mapping functions between keys and values.

This module is not available in the Low‐Trust version of FParsec.

6.5.1 Interface

// FParsec.dll

namespace FParsec

type Range = struct
  new: min: int * max: int -> Range

  val Min: int
  val Max: int
end

module StaticMapping =

  val createStaticCharIndicatorFunction:
          invert: bool -> charsInSet: seq<char>   -> (char -> bool)

  val createStaticCharRangeIndicatorFunction:
          invert: bool -> rangesInSet: seq<Range> -> (char -> bool)

  val createStaticIntIndicatorFunction:
          invert: bool -> valuesInSet: seq<int>   -> (int -> bool)

  val createStaticIntRangeIndicatorFunction:
          invert: bool -> rangesInSet: seq<Range> -> (int -> bool)


  val createStaticIntMapping:
          defaultValue: 'T -> keyValues: seq<int*'T>   -> (int -> 'T)

  val createStaticIntRangeMapping:
          defaultValue: 'T -> keyValues: seq<Range*'T> -> (int -> 'T)


  val createStaticStringMapping:
          defaultValue: 'T -> keyValues: seq<string*'T> -> (string -> 'T)

6.5.2 Remarks

The functions in the StaticMapping module use runtime code generation via System.Reflection.Emit to create optimized mapping functions between keys and values.

Note

Runtime code generation is relatively expensive, so the functions in this module should only be used for optimizing static mappings that are potentially called a (very) large number of times.

Note

The code generated for the optimized mapping functions will occupy memory until the associated AppDomain is unloaded.

The performance of the generated functions depends a lot on the individual key‐value mapping and the application‐specific call pattern. Ignoring the overhead of the function call, the generated mapping functions should generally be as fast as an equivalent statically compiled switch‐statement in C# or F#. In certain cases they will even be faster.

The code size of the generated functions increases about linearly with the number of key ranges (i.e. continuous sequences of keys with the same value). Hence, you should only use the StaticMapping module for small mappings. If you try to turn arbitrarily large key‐value mappings into static mapping functions, you’ll likely hit upon certain implementation limitations (of this module’s code, of Reflection.Emit or of the CLR’s JIT).

If the conditional compilation symbol DEBUG_STATIC_MAPPING is defined when compiling FParsec, the generated mapping functions will compute each result with two different methods and check the results against each other. Of course, this means that they will take more than twice the time than without the DEBUG_STATIC_MAPPING symbol and will also consume more memory. In Debug builds of FParsec DEBUG_STATIC_MAPPING is switched on by default, since the StaticMapping module is still relatively new.

Note

Measuring and comparing the performance of the generated mapping functions only makes sense in Release builds.

6.5.3 Members

type Range

Represents an immutable range between the integer values Min and Max (inclusive).

type Range = struct
  new: min: int * max: int -> Range

  val Min: int
  val Max: int
end

The Min value must not be larger than the Max value. In a Debug build this condition is checked by an assert‐check in the Range constructor.

val createStaticCharIndicatorFunction:
        invert: bool -> charsInSet: seq<char> -> (char -> bool)

Creates an optimized indicator function for the chars specified by the charsInSet sequence.

If invert is false (true), the returned indicator function will return true (false) if and only if it is called with a char contained in charsInSet.

charsInSet may contain duplicate char values.

Internally, this function collects continuous ranges of chars into Range values and then uses the same compilation strategy as createStaticCharRangeIndicatorFunction.

Please also see the remarks at the beginning of this section.

val createStaticCharRangeIndicatorFunction:
        invert: bool -> rangesInSet: seq<Range> -> (char -> bool)

Creates an optimized indicator function for the chars in the ranges specified by the rangesInSet sequence.

If invert is false (true), the returned indicator function will return true (false) if and only if it is called with a char contained in at least one of the ranges of rangesInSet.

rangesInSet may contain overlapping or duplicate ranges. However, the ranges must not contain values less than 0 or greater than 0xffff (the minimum and maximum UTF‐16 char values), otherwise an ArgumentException is thrown.

Please also see the remarks at the beginning of this section.

val createStaticIntIndicatorFunction:
        invert: bool -> valuesInSet: seq<int> -> (int -> bool)

Creates an optimized indicator function for the integers specified by the valuesInSet sequence.

If invert is false (true), the returned indicator function will return true (false) if and only if it is called with an integer contained in valuesInSet.

valuesInSet may contain duplicate integer values.

Internally, this function collects continues ranges of integer into Range values and then uses the same compilation strategy as createStaticIntRangeIndicatorFunction.

Please also see the remarks at the beginning of this section.

val createStaticIntRangeIndicatorFunction:
        invert: bool -> rangesInSet: seq<Range> -> (int -> bool)

Creates an optimized indicator function for the integers in the ranges specified by the rangesInSet sequence.

If invert is false (true), the returned indicator function will return true (false) if and only if it is called with an int contained in at least one of the ranges of rangesInSet.

rangesInSet may contain overlapping or duplicate ranges.

Please also see the remarks at the beginning of this section.

val createStaticIntMapping:
        defaultValue: 'T -> keyValues: seq<int*'T> -> (int -> 'T)

Creates an optimized mapping function that maps integer keys to values.

The keyValues sequence specifies the key‐value pairs for the mapping. All keys not specified in keyValues are mapped to defaultValue.

This function throws an ArgumentException if keyValues contains a duplicate key.

Internally, this function collects continues ranges of integer keys with equal values[1] into Range values and then uses the same compilation strategy as createStaticIntRangeMapping.

Please also see the remarks at the beginning of this section.

val createStaticIntRangeMapping:
        defaultValue: 'T -> keyValues: seq<Range*'T> -> (int -> 'T)

Creates an optimized mapping function that maps integer key ranges to values.

The keyValues sequence specifies the range‐value pairs for the mapping. All keys not contained in one of the ranges in keyValues are mapped to defaultValue.

This function throws an ArgumentException if keyValues contains an overlapping or duplicate key range.

Please also see the remarks at the beginning of this section.

val createStaticStringMapping:
        defaultValue: 'T -> keyValues: seq<string*'T> -> (string -> 'T)

Creates an optimized mapping function that maps string keys to values.

The keyValues sequence specifies the key‐value pairs for the mapping. All keys not specified in keyValues are mapped to defaultValue. A null key is not supported.

createStaticStringMapping throws an ArgumentException if keyValues contains a duplicate key or a null key. If the generated mapping function is called with a null string, it throws a NullReferenceException.

Note

The compilation strategy employed by createStaticStringMapping does not handle all mappings equally well. It is optimized for mapping a relatively small set of string symbols to constants. If you want to use createStaticStringMapping to optimize a frequently used mapping in your program, you should test how well createStaticStringMapping handles your situation (in a Release build!) and see whether the performance is worth the compilation costs and the additional code dependency.

Please also see the remarks at the beginning of this section.

Footnotes:
[1] In the case of a reference type the values are only compared for reference‐equality. In the case of a value type the values are only compared if the type implements System.IEquality<_> or is an int enum type.