ddc-code-0.4.3.1: tetra/base/Data/Text/Base.ds
-- | Basic types and operators on Text objects.
module Data.Text.Base
export
{ -- Runtime operators.
makeTextLit;
sizeOfTextLit;
indexTextLit;
-- Construction.
textOfChar;
textOfWord8;
textOfVector;
-- Conversion.
vectorOfText;
-- Projections.
sizeOfText;
indexText;
-- Operators.
eqText;
}
import Data.Text.Char
import Data.Numeric.Nat
import Data.Numeric.Word
import Data.Maybe
-------------------------------------------------------------------------------
-- Foreign imports.
-- | A TextLit is a boxed object that contains a pointer to literal
-- UTF-8 data in static memory.
import foreign boxed type
TextLit : Data
-- | Runtime operators for working with unboxed text literals.
import foreign c value
-- | Make a text literal.
-- The TextLit# type is a pointer to literal UTF-8 data in
-- static memory, which we pack into a boxed object.
makeTextLit : TextLit# -> TextLit
-- | Get the size of a boxed text literal.
sizeOfTextLit : TextLit -> Nat#
-- | Get a single byte from a boxed text literal.
-- This is a byte rather than a character,
-- as UTF-8 encoded characters can consist of multiple bytes.
indexTextLit : TextLit -> Nat# -> Word8#
-- | Top level region containing text vectors.
-- All our dynamic character data is in this region.
import foreign abstract type
RegionText : Region
-- | Capabilities to allocate and read top-level text vectors.
import foreign abstract capability
capTopTextAlloc : Alloc RegionText
capTopTextRead : Read RegionText
where
-- Text -----------------------------------------------------------------------
data Text where
-- | Wrap a text literal into a text object.
-- The characterdata is stored in static memory.
TextLit : TextLit -> Text
-- | Wrap some character data into a text object.
-- The character data is stored on the heap.
TextVec : Vector# RegionText Word8# -> Text
-- | Append two text objects.
TextApp : Text -> Text -> Text
-- Construction ---------------------------------------------------------------
-- | O(1). Wrap a single character into a text object.
-- We're only taking the lowest 8 bit bytes,
-- rather than doing proper UTF-8 encoding.
textOfChar (c: Word32): Text
= textOfWord8 (truncate# c)
-- | O(1). Wrap a single byte into a text object.
textOfWord8 (w8: Word8): Text
= TextVec
$ extend RegionText using r1 with { Alloc r1; Write r1 } in
do -- Allocate the vector to hold the data,
-- including an extra null terminator byte.
vec = vectorAlloc# [r1] 2
-- Write the character.
vectorWrite# vec 0 w8
-- Write the null terminator.
vectorWrite# vec 1 0w8
vec
-- | O(1). Wrap a vector of UTF-8 data into a text object.
textOfVector (vec: Vector# RegionText Word8): Text
= TextVec vec
-- Conversion -----------------------------------------------------------------
-- | Copy a Text object into a flat vector of UTF-8 data.
vectorOfText
[r1: Region] (tt: Text)
: S (Alloc r1) (Vector# r1 Word8)
= extend r1 using r2 with { Alloc r2; Write r2 } in
do
-- Allocate a vector to hold all the data,
-- including an extra null terminator byte.
vec = vectorAlloc# [r2] (add (sizeOfText tt) 1)
-- Copy the text data into the vector.
iEnd = copyTextToVector tt vec 0
-- Write the null terminator.
vectorWrite# vec iEnd 0w8
vec
-- | Copy a text object to a mutable vector of UTF-8 data.
copyTextToVector
[r: Region] (tt: Text) (vec: Vector# r Word8) (i0: Nat)
: S (Write r) Nat
= case tt of
TextLit lit
-> copyTextLitToVector lit vec i0 0 (sizeOfTextLit lit)
TextVec vec2
-> copyTextVecToVector vec2 vec i0 0 (vectorLength# vec2 - 1)
TextApp t1 t2
-> do i1 = copyTextToVector t1 vec i0
i2 = copyTextToVector t2 vec i1
i2
-- | Copy a text literal to a mutable vector of UTF-8 data.
copyTextLitToVector
[r: Region] (tt: TextLit) (vec: Vector# r Word8)
(iDst iSrc nSrc: Nat)
: S (Write r) Nat
| iSrc >= nSrc = iDst
| otherwise
= do vectorWrite# vec iDst (indexTextLit tt iSrc)
copyTextLitToVector
tt vec (iDst + 1) (iSrc + 1) nSrc
-- | Copy a text source vector to a mutable vector of UTF-8 data.
copyTextVecToVector
[r1 r2: Region]
(vecSrc: Vector# r1 Word8) (vecDst: Vector# r2 Word8)
(iDst iSrc nSrc: Nat)
: S (Read r1 + Write r2) Nat
| iSrc >= nSrc = iDst
| otherwise
= do vectorWrite# vecDst iDst (vectorRead# vecSrc iSrc)
copyTextVecToVector
vecSrc vecDst (iDst + 1) (iSrc + 1) nSrc
-- Projections ----------------------------------------------------------------
-- | Get the size of the utf8 data in a Text object, in bytes.
--
-- * This is NOT the same as the length of the text string in characters,
-- as single characters can be encoded using multiple bytes.
--
sizeOfText (tt: Text): Nat
= case tt of
TextLit lit
-> sizeOfTextLit lit
-- The size of a text vector is the vector size minus
-- the null terminator byte.
TextVec vec
-> vectorLength# vec - 1
TextApp t1 t2
-> sizeOfText t1 + sizeOfText t2
-- | Get a single word8 character from a Text object.
indexText (tt: Text) (ix: Nat): Maybe Word8
= case tt of
TextLit lit
| ix >= sizeOfTextLit lit -> Nothing
| otherwise -> Just (indexTextLit lit ix)
TextVec vec
| ix >= vectorLength# vec - 1 -> Nothing
| otherwise -> Just (vectorRead# vec ix)
TextApp t1 t2
-> case indexText t1 ix of
Just x -> Just x
Nothing -> indexText t2 (ix - sizeOfText t1)
-- Comparison -----------------------------------------------------------------
-- | O(max len1 len2).
-- Check if two text objects represent the same characters.
eqText (tx1 tx2: Text): Bool
= private r with {Read r; Alloc r} in
do
-- We copy both strings into new vectors before doing the comparison.
-- It would be better to do it in-place.
vec1 = vectorOfText [r] tx1
len1 = vectorLength# vec1
vec2 = vectorOfText [r] tx2
len2 = vectorLength# vec2
match
| len1 /= len2 = False
| len1 == 0 = True
| otherwise = go vec1 vec2 len1 0
where
go (vec1 vec2: Vector# r Word8)
(len: Nat) (ix: Nat): S (Read r) Bool
| ix >= (len - 1)
= True
| not (eq# (vectorRead# vec1 ix) (vectorRead# vec2 ix))
= False
| otherwise
= go vec1 vec2 len (ix + 1)