gachi-core-0.1.0.0: src/Gachi/Osteology/Atomic.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}
-- | Module: Gachi.Osteology.Atomic
-- Description: Unboxed atomic state references and tagged word layouts for skeletal joints
--
-- Provides low-level, high-performance unboxed atomic memory primitives for representing
-- skeletal joint lifecycles without heap overhead or global locks.
--
-- Each joint is backed by an unboxed 64-bit tagged word stored inside a contiguous primitive
-- byte array ('AtomicJoint'), enabling native CPU compare-and-swap (CAS) instructions.
--
-- = Joint Lifecycle
--
-- Joint lifecycles progress through four canonical phases:
--
-- 1. 'JointInert' (Tag @00_2@): Stationary joint awaiting excitation. Zero-initialized memory
-- (@0x0000000000000000@) naturally decodes to this state.
-- 2. 'JointChattering' (Tag @01_2@): High-frequency lock-free oscillation carrying a 62-bit
-- chattering generation or sequence counter.
-- 3. 'JointSynchronized' (Tag @10_2@): Harmonically locked joint carrying a 62-bit phase
-- or frequency identifier.
-- 4. 'JointFused' (Tag @11_2@): Immutable terminal joint state resisting further mutation.
--
-- = Memory Layout (64-bit Tagged Word)
--
-- @
-- 63 62 61 0
-- +-----+---------------------------------------------------------------+
-- | Tag | Payload (62-bit generation / frequency / phase word) |
-- +-----+---------------------------------------------------------------+
-- 00: JointInert
-- 01: JointChattering
-- 10: JointSynchronized
-- 11: JointFused
-- @
module Gachi.Osteology.Atomic
( -- * Joint Lifecycle State
JointState(..)
, isJointInert
, isJointChattering
, isJointSynchronized
, isJointFused
-- * Tagged Word Codecs
, encodeJointState
, decodeJointState
, tagMask
, payloadMask
-- * Unboxed Atomic Joint Reference
, AtomicJoint(..)
, newAtomicJoint
, newAtomicJointRaw
, readAtomicJointRaw
, writeAtomicJointRaw
, casAtomicJointRaw
, casAtomicJointRawOld
) where
import Control.Monad.Primitive (RealWorld)
import Data.Bits (shiftL, shiftR, (.&.), (.|.))
import qualified Data.Primitive.ByteArray as BA
import Data.Word (Word64)
import GHC.Exts
( Int(..)
, atomicReadIntArray#
, atomicWriteIntArray#
, casIntArray#
, isTrue#
, (==#)
)
import GHC.Generics (Generic)
import GHC.IO (IO(..))
--------------------------------------------------------------------------------
-- Joint Lifecycle State
--------------------------------------------------------------------------------
-- | Algebraic data type representing the lifecycle state of a skeletal joint.
--
-- Encoded compactly into a single 64-bit word using the top 2 bits as discriminator tag
-- and the bottom 62 bits as the numeric payload.
data JointState
= JointInert
-- ^ Stationary joint awaiting signal excitation (Tag @00_2@).
| JointChattering !Word64
-- ^ High-frequency lock-free oscillation under multi-agent signal propagation (Tag @01_2@).
| JointSynchronized !Word64
-- ^ Harmonically locked joint in phase equilibrium (Tag @10_2@).
| JointFused
-- ^ Immutable terminal joint state (Tag @11_2@).
deriving stock (Eq, Ord, Show, Generic)
-- | Query whether a 'JointState' is 'JointInert'.
isJointInert :: JointState -> Bool
isJointInert JointInert = True
isJointInert _ = False
{-# INLINE isJointInert #-}
-- | Query whether a 'JointState' is 'JointChattering'.
isJointChattering :: JointState -> Bool
isJointChattering (JointChattering _) = True
isJointChattering _ = False
{-# INLINE isJointChattering #-}
-- | Query whether a 'JointState' is 'JointSynchronized'.
isJointSynchronized :: JointState -> Bool
isJointSynchronized (JointSynchronized _) = True
isJointSynchronized _ = False
{-# INLINE isJointSynchronized #-}
-- | Query whether a 'JointState' is 'JointFused'.
isJointFused :: JointState -> Bool
isJointFused JointFused = True
isJointFused _ = False
{-# INLINE isJointFused #-}
--------------------------------------------------------------------------------
-- Tagged Word Codecs
--------------------------------------------------------------------------------
-- | Bitmask selecting the upper 2 tag bits of a 64-bit word (@0xC000000000000000@).
tagMask :: Word64
tagMask = 0xC000000000000000
{-# INLINE tagMask #-}
-- | Bitmask selecting the lower 62 payload bits of a 64-bit word (@0x3FFFFFFFFFFFFFFF@).
payloadMask :: Word64
payloadMask = 0x3FFFFFFFFFFFFFFF
{-# INLINE payloadMask #-}
-- | Encode a 'JointState' into an unboxed 64-bit tagged word.
--
-- * 'JointInert': Encoded as @0x0000000000000000@.
-- * 'JointChattering': Encoded with tag @01_2@ in bits 63..62 and masked payload in bits 61..0.
-- * 'JointSynchronized': Encoded with tag @10_2@ in bits 63..62 and masked payload in bits 61..0.
-- * 'JointFused': Encoded with tag @11_2@ in bits 63..62 (@0xC000000000000000@).
encodeJointState :: JointState -> Word64
encodeJointState JointInert = 0
encodeJointState (JointChattering !payload) =
(1 `shiftL` 62) .|. (payload .&. payloadMask)
encodeJointState (JointSynchronized !payload) =
(2 `shiftL` 62) .|. (payload .&. payloadMask)
encodeJointState JointFused = 3 `shiftL` 62
{-# INLINE encodeJointState #-}
-- | Decode an unboxed 64-bit tagged word back into its corresponding 'JointState'.
--
-- Discriminates on the high 2 bits (63..62):
-- * @00_2@ -> 'JointInert'
-- * @01_2@ -> 'JointChattering' with masked 62-bit payload
-- * @10_2@ -> 'JointSynchronized' with masked 62-bit payload
-- * @11_2@ -> 'JointFused'
decodeJointState :: Word64 -> JointState
decodeJointState !w =
let !tag = w `shiftR` 62
!payload = w .&. payloadMask
in case tag of
0 -> JointInert
1 -> JointChattering payload
2 -> JointSynchronized payload
3 -> JointFused
_ -> JointInert
{-# INLINE decodeJointState #-}
--------------------------------------------------------------------------------
-- Unboxed Atomic Joint Reference
--------------------------------------------------------------------------------
-- | An unboxed atomic reference storing a tagged joint state word.
--
-- Backed by an 8-byte contiguous 'BA.MutableByteArray' to permit direct hardware-level
-- atomic compare-and-swap ('casIntArray#') instructions and wait-free memory reads
-- without acquiring OS mutexes or runtime reader-writer locks.
newtype AtomicJoint = AtomicJoint (BA.MutableByteArray RealWorld)
instance Eq AtomicJoint where
AtomicJoint mba1 == AtomicJoint mba2 = BA.sameMutableByteArray mba1 mba2
instance Show AtomicJoint where
show _ = "<AtomicJoint>"
-- | Allocate a new 'AtomicJoint' initialized to the given raw 64-bit word.
newAtomicJointRaw :: Word64 -> IO AtomicJoint
newAtomicJointRaw !val = do
mba <- BA.newByteArray 8
let !joint = AtomicJoint mba
writeAtomicJointRaw joint val
pure joint
-- | Allocate a new 'AtomicJoint' initialized to the given 'JointState'.
newAtomicJoint :: JointState -> IO AtomicJoint
newAtomicJoint !st = newAtomicJointRaw (encodeJointState st)
-- | Wait-free atomic memory read of the raw 64-bit tagged word.
readAtomicJointRaw :: AtomicJoint -> IO Word64
readAtomicJointRaw (AtomicJoint mba) = IO $ \s0# ->
let !(BA.MutableByteArray mba#) = mba
in case atomicReadIntArray# mba# 0# s0# of
(# s1#, val# #) ->
(# s1#, fromIntegral (I# val#) #)
{-# INLINE readAtomicJointRaw #-}
-- | Atomic memory write of the raw 64-bit tagged word.
writeAtomicJointRaw :: AtomicJoint -> Word64 -> IO ()
writeAtomicJointRaw (AtomicJoint mba) !val = IO $ \s0# ->
let !(I# v#) = fromIntegral val
!(BA.MutableByteArray mba#) = mba
in case atomicWriteIntArray# mba# 0# v# s0# of
s1# -> (# s1#, () #)
{-# INLINE writeAtomicJointRaw #-}
-- | Hardware compare-and-swap (CAS) operation on the raw 64-bit tagged word.
--
-- Atomically compares the current word at slot 0 with @expected@. If they match,
-- writes @newVal@ and returns 'True'. If they do not match, leaves memory untouched
-- and returns 'False'.
casAtomicJointRaw :: AtomicJoint -> Word64 -> Word64 -> IO Bool
casAtomicJointRaw (AtomicJoint mba) !expected !newVal = IO $ \s0# ->
let !(I# exp#) = fromIntegral expected
!(I# new#) = fromIntegral newVal
!(BA.MutableByteArray mba#) = mba
in case casIntArray# mba# 0# exp# new# s0# of
(# s1#, old# #) ->
(# s1#, isTrue# (old# ==# exp#) #)
{-# INLINE casAtomicJointRaw #-}
-- | Hardware compare-and-swap returning both success status and the observed previous word.
casAtomicJointRawOld :: AtomicJoint -> Word64 -> Word64 -> IO (Bool, Word64)
casAtomicJointRawOld (AtomicJoint mba) !expected !newVal = IO $ \s0# ->
let !(I# exp#) = fromIntegral expected
!(I# new#) = fromIntegral newVal
!(BA.MutableByteArray mba#) = mba
in case casIntArray# mba# 0# exp# new# s0# of
(# s1#, old# #) ->
let !oldW = fromIntegral (I# old#)
!succCAS = isTrue# (old# ==# exp#)
in (# s1#, (succCAS, oldW) #)
{-# INLINE casAtomicJointRawOld #-}