sbv-14.8: Data/SBV/Compilers/C/Arena.hs
-----------------------------------------------------------------------------
-- |
-- Module : Data.SBV.Compilers.C.Arena
-- Copyright : (c) Levent Erkok
-- License : BSD3
-- Maintainer: erkokl@gmail.com
-- Stability : experimental
--
-- Shared emission of per-call storage arenas for text and collections.
-----------------------------------------------------------------------------
{-# OPTIONS_GHC -Wall -Werror #-}
module Data.SBV.Compilers.C.Arena (CArena(..), arenaRuntime) where
-- | Separate ownership domains sharing the same allocation protocol. Keep
-- their C types and lifetimes independent even though their emitter is shared.
data CArena = TextArena -- ^ Byte-addressed UTF-8 string storage.
| ListArena -- ^ Aligned storage for symbolic-list elements.
| SetArena -- ^ Aligned storage for symbolic-set elements.
-- | Emit overflow-checked allocation and whole-arena cleanup. Empty allocations
-- return null without allocating. Collection storage retains its long-double
-- alignment and checks both multiplication and header-addition overflow; text
-- storage accepts a byte count directly. Nodes own only their payload buffer,
-- not the managed values referenced by collection elements.
arenaRuntime :: CArena -> [String]
arenaRuntime arena
= [ "/* Per-call ownership arena for " ++ description ++ " temporaries. */"
, "typedef struct " ++ nodeType ++ " { struct " ++ nodeType ++ " *next; " ++ payloadType ++ " data[]; } " ++ nodeType ++ ";"
, "typedef struct { " ++ nodeType ++ " *head; } " ++ contextType ++ ";"
]
++ separator
++ [ "static " ++ resultType ++ " *" ++ prefix ++ "_alloc(" ++ contextType ++ " *ctx, size_t count" ++ elementParameter ++ ")"
, "{"
, " if (count == 0) return NULL;"
]
++ [ line
| not byteStorage
, line <- [ " if (element_size == 0 || count > SIZE_MAX / element_size) abort();"
, " const size_t bytes = count * element_size;"
]
]
++ [ " if (" ++ byteCount ++ " > SIZE_MAX - sizeof(" ++ nodeType ++ ")) abort();"
, " " ++ nodeType ++ " *node = (" ++ nodeType ++ " *) malloc(sizeof(*node) + " ++ byteCount ++ ");"
, " if (node == NULL) abort();"
, " node->next = ctx->head; ctx->head = node; return node->data;"
, "}"
]
++ separator
++ [ "static void " ++ prefix ++ "_ctx_end(" ++ contextType ++ " *ctx)"
, "{"
, " while (ctx->head != NULL) {"
, " " ++ nodeType ++ " *next = ctx->head->next; free(ctx->head); ctx->head = next;"
, " }"
, "}"
]
where stem = case arena of
TextArena -> "text"
ListArena -> "list"
SetArena -> "set"
description = case arena of
TextArena -> "string"
ListArena -> "symbolic-list"
SetArena -> "symbolic-set"
byteStorage = case arena of
TextArena -> True
_ -> False
prefix = "sbv_" ++ stem
nodeType = prefix ++ "_node"
contextType = prefix ++ "_ctx"
payloadType = if byteStorage then "uint8_t" else "long double"
resultType = if byteStorage then "uint8_t" else "void"
byteCount = if byteStorage then "count" else "bytes"
elementParameter = if byteStorage then "" else ", size_t element_size"
separator = ["" | byteStorage]