Group WaveVersioningSupport

group WaveVersioningSupport

The wave getter functions always return an existing wave. This can result in problems if the layout of the wave changes.

Layout in this context means:

  • Sizes of all dimensions

  • Labels of all dimensions

  • Wave data type

  • Prefilled wave content or wave note

This also means that the name and location of the wave does not influence the wave version. Use UpgradeWaveLocationAndGetIt() if you need to move the wave. The main reason is that for being able to query the wave version you already need to know where it is.

In order to enable smooth upgrades between old and new wave layouts the following code pattern can be used:

Function/Wave GetMyWave(device)
    string device

    DFREF dfr = GetMyPath(device)
    variable versionOfNewWave = 2

    Wave/Z/SDFR=dfr wv = myWave

    if(ExistsWithCorrectLayoutVersion(wv, versionOfNewWave))
        return wv
    elseif(WaveExists(wv)) // handle upgrade
        if(WaveVersionIsAtLeast(wv, 1)) // 1->2
            Redimension/D wv
        else // no-version->2
            // change the required dimensions and leave all others untouched with -1
            // the extended dimensions are initialized with zero
            Redimension/D/N=(10, -1, -1, -1) wv
        endif
    else
        Make/R/N=(10, 2) dfr:myWave/Wave=wv
    endif

    SetWaveVersion(wv, versionOfNewWave)

    return wv
End

Now everytime the layout of myWave changes, raise versionOfNewWave by 1 and add a new WaveVersionIsAtLeast branch. When GetMyWave is called the first time, the wave is redimensioned or rebuilt as double wave depending on the current version, and on successive calls the wave is returned as is.

Hints:

  • Wave layout versioning is mandatory if you change the layout of the wave

  • Wave layout versions start with 1 and are integers

  • Rule of thumb: Raise the version if you change anything in or below the Make line

  • Wave versioning needs a special wave note style, see GetNumberFromWaveNote

Functions

static variable ExistsWithCorrectLayoutVersion(WaveOrNull wv, variable versionOfNewWave)

Check if wv exists and has the correct version UTF_NOINSTRUMENTATION.

static variable WaveVersionIsAtLeast(WaveOrNull wv, variable existingVersion)

Check if the given wave’s version is equal or larger than the given version, if version is not set false is returned.

static variable IsWaveVersioned(wave wv)

Returns 1 if the wave has a valid version information attached, 0 otherwise.

static variable WaveVersionIsSmaller(WaveOrNull wv, variable existingVersion)

Check if the given wave’s version is smaller than the given version, if version is not set true is returned.

variable GetWaveVersion(WaveOrNull wv)

return the Version of the Wave, returns NaN if no version was set UTF_NOINSTRUMENTATION

static variable SetWaveVersion(wave wv, variable val)

Set the wave layout version of wave.

static variable IsValidWaveVersion(variable value)

A valid wave version is a positive non-zero integer.

variable ClearWaveNoteExceptWaveVersion(wave wv)

Clear the wave note but keep any valid wave version.

dfref UpgradeDataFolderLocation(string oldFolder, string newFolder)

Move/Rename a datafolder across different locations.

Both parameters must be absolute datafolder locations. Cases where both exist are also handled gracefully.

Function/DF GetMyFolder()
    return UpgradeDataFolderLocation("root:old", "root:new")
End

Returns:

DFREF to the newFolder with the contents of oldFolder

wave UpgradeWaveLocationAndGetIt(WaveLocationMod *p)

Rename/Move a wave to a new location.

Valid transformations (and all combinations of them):

  • Moving into a new datafolder

  • Renaming to a new name

  • Nothing

The function is idempotent (i.e. it can be called also on already relocated waves). Cases where new == old are also handled gracefully.

Function/WAVE GetMyWave(device)
    string device

    variable versionOfNewWave = 1
    string newName = "newAndNiceName"
    DFREF newDFR = GetNewAndFancyFolder(device)

    STRUCT WaveLocationMod p
    p.dfr     = $(GetSomeFolder(device) + ":oldSubFolder")
    p.newDFR  = newDFR
    p.name    = "oldAndUglyName"
    p.newName = newName

    WAVE/Z wv = UpgradeWaveLocationAndGetIt(p)

    if(ExistsWithCorrectLayoutVersion(wv, versionOfNewWave))
        return wv
    elseif(WaveExists(wv))
        // handle upgrade
    else
        Make/R/N=(10, 2) newDFR:newName/Wave=wv
    end

    SetWaveVersion(wv, versionOfNewWave)

    return wv
End

Returns:

wave reference to the wave in the new location, an invalid one if the wave does not exist at the specified former location