APL/D Source Code:

────────────────────────────────────────────────────────────────────────────────

create←{⎕IO ⎕ML←0                               ⍝ Create table.
    error←⎕SIGNAL⍨                              ⍝ signal error.
    tps←80 160 320 83 163 323 645               ⍝ expected types.
    0::⎕EN error⊃⎕DM                            ⍝ pass error to caller.
    0=⎕NC'⍺':⎕SIGNAL 2                          ⍝ left arg is table name.
    2=|≡⍵:⍺ ∇,⊂⍵                                ⍝ single field: enclose.
    tab←#.⎕NS'' ⋄ tab.(⎕IO ⎕ML←0)               ⍝ new table handle.
    tab.tname←⍺,('.'≠⊃⌽⍺∩'/.\')/'.ddb'          ⍝ table file name.
    tab.access←'w'                              ⍝ read/write access.
    tab.(names types)←↓⍉↑2↑¨⍵                   ⍝ field names, data types,
    tab.shapes←3↓¨0,¨⍵                          ⍝   and shapes.
    0∊tab.types∊tps:11 error'BAD FIELD TYPE'    ⍝ unexpected type.
    _fill tab:                                  ⍝ install handle parameters.
    fix←{83 ⎕DR⊃(⎕DR ⍵)⍺ ⎕DR ⍵}                 ⍝ ⍺ type fix.

    buff←¯86 ¯128 0 ¯128                        ⍝ magic no: aa 80 00 80
    buff,←323 fix tab.(0 _cols _flds)           ⍝ skip cols flds
    buff,←163 fix tab.types                     ⍝ types
    buff,←83 fix tab.(⊃∘⍴¨shapes)               ⍝ ranks
    buff,←323 fix tab.(↑,/shapes)               ⍝ shapes
    buff,←80 fix↑,/tab.names,¨⊃⎕AV              ⍝ 0-terminated field names.
    tab._skip←⌈(⊃⍴buff)÷tab._cols               ⍝ rows occupied by header.
    buff[4+⍳4]←323 fix tab._skip                ⍝ set skip field in buff.

    22::⎕EN error'BAD TABLE NAME'               ⍝ can't create: table exists.
    ntie←tab.tname ⎕NCREATE 0                   ⍝ create ⍺.ddb file.
    0::⎕EN error⊃⎕DM{⍺}⎕NUNTIE ntie             ⍝ untie file on error.
    _←(tab.(_skip×_cols)↑buff)⎕NAPPEND ntie 83  ⍝ write header bytes.
    _←⎕NUNTIE ntie                              ⍝ release file.
    tab.(_map←83 ¯1 _cols ⎕MAP tname access)    ⍝ map as byte matrix.
    1:shy←tab                                   ⍝ shy result: table handle.
}

────────────────────────────────────────────────────────────────────────────────

remove←{                                        ⍝ Remove table.
    error←⎕SIGNAL⍨                              ⍝ signal error.
    0::⎕EN error⊃⎕DM                            ⍝ pass error to caller.
    9=⎕NC'⍵':∇ ⍵.({tname}⎕EX'_map')             ⍝ open: retry after close.
    tname←⍵,('.'≠⊃⌽⍵∩'/.\')/'.ddb'              ⍝ table file name.
    22::{1:shy←0}0                              ⍝ table didn't exist.
    ntie←tname ⎕NTIE 0                          ⍝ tie table file.
    19::⎕EN error'TABLE OPEN'{⍺}⎕NUNTIE ntie    ⍝ table mapped.
    1:shy←{1}tname ⎕NERASE ntie                 ⍝ erase table file.
}

────────────────────────────────────────────────────────────────────────────────

append←{⎕IO ⎕ML←0                               ⍝ Append row(s) to table.
    error←⎕SIGNAL⍨                              ⍝ signal error.
    0=⎕NC'⍺':⎕SIGNAL 2                          ⍝ left arg is table.
    9≠⎕NC'⍺':('w'open ⍺)∇ ⍵                     ⍝ file name: retry with handle.
    0::⎕EN error⊃⎕DM                            ⍝ pass error to caller.
    'w'≠⍺.access:19 error'READ-ONLY TABLE'      ⍝ check write access.
    put←{⍵ ⎕NAPPEND ntie 83}                    ⍝ put rows to file.
    vals←⍺.(_flds=1)⊃⍵(⊂⍵)                      ⍝ enclose if single field table.
    puts←⍺.{types shapes _xtra ⍵}vals           ⍝ put parameters.
    ntie←⍺.tname ⎕NTIE 0{⍺}⍺.⎕EX'_map'          ⍝ tie native file.
    remap←⍺.{83 ¯1 _cols ⎕MAP tname access}     ⍝ remap file.
    reset←{⍺._map←remap ⎕NUNTIE ⍵}              ⍝ reset after error.
    0::⎕EN error⊃⎕DM{⍺}⍺ reset ntie             ⍝ reset & signal error.
    size←put↑,/⍺.names _83mat¨↓⍉↑puts           ⍝ append extra rows.
    1:shy←{size}⍺ reset ntie                    ⍝ shy result: table handle.
}

────────────────────────────────────────────────────────────────────────────────

retain←{⎕IO ⎕ML←0                               ⍝ Retain only selected rows.
    0::(⊃⎕DM)⎕SIGNAL ⎕EN                        ⍝ pass error to caller.
    0=⎕NC'⍺':⎕SIGNAL 2                          ⍝ left arg is table.
    9≠⎕NC'⍺':('w'open ⍺)∇ ⍵                     ⍝ file name: retry with handle.
    error←⎕SIGNAL⍨                              ⍝ signal error.
    'w'≠⍺.access:19 error'READ-ONLY TABLE'      ⍝ check write access.
    mask←⍺.((_skip/1),⍵∨0×⍳(⊃⍴_map)-_skip)      ⍝ mask for whole file.
    size←⍺._cols×+/mask                         ⍝ new file size.
    ∧/mask:shy←size                             ⍝ all rows retained: done.
    unmap←⍺.{tname ⎕NTIE 0{⍺}⎕EX'_map'}         ⍝ unmap and tie native file.
    remap←{⍺._map←_map ⎕NUNTIE ⍵}               ⍝ untie and map native file.
    _map←⍺.{83 ¯1 _cols ⎕MAP tname access}      ⍝ map file.
    ntie←unmap 0                                ⍝ unmap and tie native file.
    lndx←¯1+⎕NSIZE ntie                         ⍝ last byte index.
    last←⎕NREAD ntie 83 1 lndx                  ⍝ last byte in file.
    19::⎕EN error'TABLE OPEN'{⍺}⍺ remap ntie    ⍝ failure: too many handles.
    {0}last ⎕NAPPEND lndx ⎕NRESIZE ntie:        ⍝ attempt remove/replace byte.
    {0}⍺ remap ntie:                            ⍝ success: not too many handles.
    ⍺._map[⍳+/mask;]←mask⌿⍺._map                ⍝ compress mapped file rows.
    1:shy←{size}⍺ remap size ⎕NRESIZE unmap 0   ⍝ truncate and remap file.
}

────────────────────────────────────────────────────────────────────────────────

open←{⎕IO ⎕ML←0                                 ⍝ Open table {read/write}.
    error←⎕SIGNAL⍨                              ⍝ signal error.
    0::⎕EN error⊃⎕DM                            ⍝ pass error to caller.
    ⍺←'r'                                       ⍝ default: read-only.
    9=⎕NC'⍵':⍺ ∇ ⍵.tname                        ⍝ handle: reopen.
    tab←#.⎕NS'' ⋄ tab.(⎕IO ⎕ML)←0               ⍝ create handle.
    tab.access←('rRwW'⍳⍺)⊃'rrwwr'               ⍝ read/write access.
    tab.tname←⍵,('.'≠⊃⌽⍵∩'/.\')/'.ddb'          ⍝ table file name.
    19 22::22 error'BAD TABLE NAME'             ⍝ bad name signals 19 or 22.
    vec←83 ¯1 ⎕MAP tab.(tname access)           ⍝ map table as byte vector.
    tab.(_skip _cols _flds)←1↓323 ⎕DR 16↑vec    ⍝ field size values.
    slice←{vec[(16+⍺×tab._flds)+⍳⍵]}            ⍝ slice from vec.
    ranks←2 slice tab._flds                     ⍝ field ranks.
    tab.types←163 ⎕DR 0 slice 2×tab._flds       ⍝ field types.
    size←4×+/ranks                              ⍝ size of shape vector.
    shapes←0+323 ⎕DR 3 slice size               ⍝ all shapes.
    tab.shapes←ranks{(-⍺)↑¨(+\⍺)↑¨⊂⍵}shapes     ⍝ shape per field.
    drop←16+size+3×tab._flds                    ⍝ size of fixed header region.
    nvec←drop↓tab.(_skip×_cols)↑vec             ⍝ names vector.
    split←{¯1↓¨80 ⎕DR¨(0=¯1⌽⍵)⊂⍵}               ⍝ name split.
    tab.names←tab._flds↑split nvec              ⍝ field names.
    _fill tab:                                  ⍝ install handle parameters.
    tab.(_map←83 ¯1 _cols ⎕MAP tname access)    ⍝ remap file as byte matrix.
    tab                                         ⍝ result is table handle.
}

────────────────────────────────────────────────────────────────────────────────

defs←{                                          ⍝ Field definitions.
    error←⎕SIGNAL⍨                              ⍝ signal error.
    0::⎕EN error⊃⎕DM                            ⍝ pass error to caller.
    9≠⎕NC'⍵':∇ open ⍵                           ⍝ accepts table name or handle.
    ⍵.((↓⍉↑names types),¨shapes)                ⍝   ..    table handle.
}

────────────────────────────────────────────────────────────────────────────────

get←{⎕IO ⎕ML←0                                  ⍝ Get rows from table field(s).
    error←⎕SIGNAL⍨                              ⍝ signal error.
    0=⎕NC'⍺':⎕SIGNAL 2                          ⍝ left arg is table.
    0::⎕EN error⊃⎕DM                            ⍝ pass errors to caller.
    9≠⎕NC'⍺':(open ⍺)∇ ⍵                        ⍝ file name: open.
    rows field_s←(2|⎕DR⊃⍵)⊃(1 ⍵)⍵               ⍝ row selection, field name(s).
    fields←(1=≡,field_s)⊃field_s(⊂field_s)      ⍝ enclose if single field.
    qt←{'"',⍵,'"'}                              ⍝ quote bad field name.
    3::6 error'BAD NAME',⍕qt¨fields~⍺.names     ⍝ unexpected field name(s).
    inds←⍺.names⍳fields                         ⍝ fields indices from key.
    mask←(⍳⍺._flds)∊inds                        ⍝ field selection mask.
    cols←↑∨/inds⊃¨⊂⍺._cvex                      ⍝ column indices.
    cons←mask/⍺.(↓⍉↑types shapes _svex _xtra)   ⍝ conversion parameters.
    fix←{                                       ⍝ fix values' type and shape.
        type shape svec xtra←⍺                  ⍝ conversion parameters.
        conv←{(|⍺)⎕DR⊃(⎕DR ⍵)83 ⎕DR ⍵}          ⍝ type conversion.
        resp←{((⊃⍴⍵),⍺)⍴⍵}                      ⍝ reshape.
        ~¯1∊×shape:shape resp type conv ⍵       ⍝ simple: convert type.
        sconv←{↓⍉↑,¨(3+80×xtra~0)conv¨⍵}        ⍝ shape conversion.
        split←{(sconv ¯1↓⍵)(type conv⊃⌽⍵)}      ⍝ split out shape and values.
        svex←{(⊂shape)⌈(⊂shape<0)\¨⍵}           ⍝ shape vectors.
        encls←{(svex ⍺)↑¨(⊂|shape)⍴¨↓⍵}         ⍝ reshape each value.
        ↑encls/split svec⊂⍵                     ⍝ shape vectors and values.
    }

    xtract←{                                    ⍝ mask out rows and cols.
        1≡rows:⍺._skip 0↓cols/⍵                 ⍝ get 1 ...: get all rows.
        0≡rows:cols/0⌿⍵                         ⍝ get 0 ...: get no rows.
        cols/((⍺._skip⍴0 0),rows)⌿⍵             ⍝ use header-padded mask.
    }

    1=≡,field_s:(⊃cons)fix ⍺ xtract ⍺._map      ⍝ fetch single field.
    part←↑,/mask/⍺._pvex                        ⍝ partition vector for fields.
    (⍋inds)⊃¨⊂cons fix¨part⊂⍺ xtract ⍺._map     ⍝ fetch multiple fields.
}

────────────────────────────────────────────────────────────────────────────────

put←{⎕IO ⎕ML←0                                  ⍝ Replace values in field(s).
    0=⎕NC'⍺':⎕SIGNAL 2                          ⍝ error: missing table.
    9≠⎕NC'⍺':('w'open ⍺)∇ ⍵                     ⍝ file name: open and continue.
    error←⎕SIGNAL⍨                              ⍝ signal error.
    0::⎕EN error⊃⎕DM                            ⍝ pass error to caller.
    mask field_s val_s←¯3↑1,⍵                   ⍝ rows, field(s) and new values.
    encl←{⍺⊃⍵(,⊂⍵)}                             ⍝ enclose ⍵ if ⍺.
    single←1=≡,field_s                          ⍝ single field.
    fields vals←single encl¨field_s val_s       ⍝ enclose if single field.
    'w'≠⍺.access:19 error'READ-ONLY TABLE'      ⍝ opened without 'w' option.
    3::6 error'BAD NAME',⍕fields~⍺.names        ⍝ unexpected field name(s).
    inds←⍺.names⍳fields                         ⍝ field indices from key.
    rows←mask/⍺.(_skip↓⍳⊃⍴_map)                 ⍝ row indices.
    cols←↑,/inds⊃¨⊂⍺._xvex                      ⍝ column indices.
    puts←↓⍉↑inds⊃¨⊂↓⍉↑⍺.(types shapes _xtra)    ⍝ conversion parameters.
    collect←{↑,/fields _83mat¨↓⍉↑puts,⊂⍵}       ⍝ collect values.
    ⍺._map[rows;cols]←collect vals              ⍝ insert map rows.
    1:shy←single⊃vals(⊃vals)                    ⍝ shy rslt: new values.
}

────────────────────────────────────────────────────────────────────────────────

_fill←{                                         ⍝ Install handle parameters.
    0::(⊃⎕DM)⎕SIGNAL ⎕EN                        ⍝ pass errors to caller.
    ⍵.(_xtra←(shapes<0)×⌊(⎕DR¨⍵.shapes)÷80)     ⍝ extra shape bytes per axis.
    bpt←⍵.((+/¨_xtra)+(×/¨|shapes)×⌊types÷80)   ⍝ bytes per type.
    ⍵.(_flds←⊃⍴,types)                          ⍝ number of fields
    ⍵._cols←+/bpt                               ⍝ no of bytes per row.
    ⍵._cvex←↓bpt{⍵∘.=⍺/⍵}⍳⍴bpt                  ⍝ byte-column masks.
    ⍵.(_xvex←_cvex/¨⊂⍳⍴⊃_cvex)                  ⍝ byte-column indices.
    ⍵._pvex←1=bpt↑¨1                            ⍝ field partition vectors.
    ⍵._svex←⍵.(_pvex{(⍴⍺)↑↑,/1,⍵↑¨1}¨-_xtra)    ⍝ shape partition vectors.
    0                                           ⍝ zero rslt to foil guard.
}

────────────────────────────────────────────────────────────────────────────────

_83mat←{⎕IO ⎕ML←0                               ⍝ type 83 rows for map mat.
    type shape xtra vals←⍵                      ⍝ conversion parameters.
    error←⍺{(⍵,' in "',⍺⍺,'"')⎕SIGNAL ⍺}        ⍝ signal error.
    0::⎕EN error⊃⎕DM                            ⍝ pass error to caller.

    simple←{                                    ⍝ simple: quick special case.
        rdiff←(⍴⍴⍵)-⍴⍺                          ⍝ rank difference.
        rdiff=0:⍺ ∇(1,⍴⍵)⍴⍵                     ⍝ single row: increase rank.
        rdiff≠1:4 error'BAD RANK'               ⍝ rank error.
        1<|≡⍵:11 error'BAD DEPTH'               ⍝ nested values: depth error.
        1∊⍺<1↓⍴⍵:10 error'BAD SIZE'             ⍝ value items truncated.
        1≠≡⍵:11 error'BAD DEPTH'                ⍝ depth error.
        ≠/2|type,⎕DR ⍵:11 error'BAD TYPE'       ⍝ impossible conversion.
        matr←{,[1+⍳⍴⍺]((⊃⍴⍵),⍺)↑⍵}              ⍝ pad to required size.
        type conv ⍺ matr ⍵                      ⍝ padded matrix.
    }

    nested←{                                    ⍝ nested: slower general case.
        2>|≡⍵:⍺ ∇,⊂⍵                            ⍝ single row: increase depth.
        svec←(⍺<0)/↓⍉↑⍴¨,⍵                      ⍝ shapes.
        pre←↑,/(3+80×xtra~0)conv∘(,[⍬])¨svec    ⍝ shape bytes.
        pre,(|⍺)simple↑((⊂⍺)⌈⍴¨⍵)↑¨⍵            ⍝ prefix simple mix.
    }

    conv←{83 ⎕DR⊃vchk\(⎕DR ⍵)⍺ ⎕DR ⍵}           ⍝ ⍺-type conversion,
    vchk←{0∊⍵:11 error'BAD VALUE' ⋄ ⍵}          ⍝ error if conversion fails.

    ¯1∊×shape:shape nested vals                 ⍝ nested field:
              shape simple vals                 ⍝ simple field:
}

────────────────────────────────────────────────────────────────────────────────


Back to: Contents