{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
module HaskellWorks.Data.Json.Simd.Index.Simple
( makeSimpleJsonIbBps
, makeSimpleJsonIbBpsUnsafe
, enabledMakeSimpleJsonIbBps
) where
import Control.Monad.ST
import Data.Word
import HaskellWorks.Data.Json.Simd.Internal.Index.Simple
import qualified Control.Monad.ST.Unsafe as ST
import qualified Data.ByteString as BS
import qualified Data.ByteString.Internal as BSI
import qualified Data.ByteString.Lazy as LBS
import qualified Data.Vector.Storable.Mutable as DVSM
import qualified Foreign.ForeignPtr as F
import qualified Foreign.ForeignPtr.Unsafe as F
import qualified Foreign.Marshal.Unsafe as F
import qualified Foreign.Ptr as F
import qualified HaskellWorks.Data.Json.Simd.Capabilities as C
import qualified HaskellWorks.Data.Json.Simd.Internal.Foreign as F
import qualified HaskellWorks.Data.Json.Simd.Internal.List as L
import qualified System.IO.Unsafe as IO
makeSimpleJsonIbBps :: LBS.ByteString -> Either String [(BS.ByteString, BS.ByteString)]
makeSimpleJsonIbBps :: ByteString -> Either String [(ByteString, ByteString)]
makeSimpleJsonIbBps ByteString
lbs = if Bool
enabledMakeSimpleJsonIbBps
then [(ByteString, ByteString)]
-> Either String [(ByteString, ByteString)]
forall a b. b -> Either a b
Right (ByteString -> [(ByteString, ByteString)]
makeSimpleJsonIbBpsUnsafe ByteString
lbs)
else String -> Either String [(ByteString, ByteString)]
forall a b. a -> Either a b
Left String
"makeSimpleJsonIbBps function is disabled"
makeSimpleJsonIbBpsUnsafe :: LBS.ByteString -> [(BS.ByteString, BS.ByteString)]
makeSimpleJsonIbBpsUnsafe :: ByteString -> [(ByteString, ByteString)]
makeSimpleJsonIbBpsUnsafe ByteString
lbs = ByteString
-> ByteString
-> [ByteString]
-> [ByteString]
-> [(ByteString, ByteString)]
forall a b. a -> b -> [a] -> [b] -> [(a, b)]
L.zipPadded ByteString
BS.empty ByteString
BS.empty [ByteString]
ibs [ByteString]
bps
where chunks :: [(ByteString, ByteString, ByteString)]
chunks = ByteString -> [(ByteString, ByteString, ByteString)]
makeIbs ByteString
lbs
ibs :: [ByteString]
ibs = ((ByteString, ByteString, ByteString) -> ByteString)
-> [(ByteString, ByteString, ByteString)] -> [ByteString]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\(ByteString
a, ByteString
_, ByteString
_) -> ByteString
a) [(ByteString, ByteString, ByteString)]
chunks
bps :: [ByteString]
bps = [(ByteString, ByteString, ByteString)] -> [ByteString]
ibsToIndexByteStrings [(ByteString, ByteString, ByteString)]
chunks
makeIbs :: LBS.ByteString -> [(BS.ByteString, BS.ByteString, BS.ByteString)]
makeIbs :: ByteString -> [(ByteString, ByteString, ByteString)]
makeIbs ByteString
lbs = IO [(ByteString, ByteString, ByteString)]
-> [(ByteString, ByteString, ByteString)]
forall a. IO a -> a
F.unsafeLocalState (IO [(ByteString, ByteString, ByteString)]
-> [(ByteString, ByteString, ByteString)])
-> IO [(ByteString, ByteString, ByteString)]
-> [(ByteString, ByteString, ByteString)]
forall a b. (a -> b) -> a -> b
$ do
WorkBuffers
wb <- Int -> IO WorkBuffers
allocWorkBuffers (Int
32 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
1024 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
1204)
WorkState
ws <- IO WorkState
allocWorkState
IO [(ByteString, ByteString, ByteString)]
-> IO [(ByteString, ByteString, ByteString)]
forall a. IO a -> IO a
IO.unsafeInterleaveIO (IO [(ByteString, ByteString, ByteString)]
-> IO [(ByteString, ByteString, ByteString)])
-> IO [(ByteString, ByteString, ByteString)]
-> IO [(ByteString, ByteString, ByteString)]
forall a b. (a -> b) -> a -> b
$ WorkBuffers
-> WorkState
-> [ByteString]
-> IO [(ByteString, ByteString, ByteString)]
go WorkBuffers
wb WorkState
ws (ByteString -> [ByteString]
LBS.toChunks ByteString
lbs)
where go :: WorkBuffers -> WorkState -> [BS.ByteString] -> IO [(BS.ByteString, BS.ByteString, BS.ByteString)]
go :: WorkBuffers
-> WorkState
-> [ByteString]
-> IO [(ByteString, ByteString, ByteString)]
go WorkBuffers
_ WorkState
_ [] = [(ByteString, ByteString, ByteString)]
-> IO [(ByteString, ByteString, ByteString)]
forall (m :: * -> *) a. Monad m => a -> m a
return []
go WorkBuffers
wb WorkState
ws (ByteString
bs:[ByteString]
bss) = do
let resLen :: Int
resLen = ByteString -> Int
BS.length ByteString
bs Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
8
ForeignPtr Word8
resIbFptr <- Int -> IO (ForeignPtr Word8)
forall a. Int -> IO (ForeignPtr a)
F.mallocForeignPtrBytes Int
resLen
ForeignPtr Word8
resAFptr <- Int -> IO (ForeignPtr Word8)
forall a. Int -> IO (ForeignPtr a)
F.mallocForeignPtrBytes Int
resLen
ForeignPtr Word8
resBFptr <- Int -> IO (ForeignPtr Word8)
forall a. Int -> IO (ForeignPtr a)
F.mallocForeignPtrBytes Int
resLen
let resIbPtr :: Ptr UInt8
resIbPtr = Ptr Word8 -> Ptr UInt8
forall a b. Ptr a -> Ptr b
F.castPtr (ForeignPtr Word8 -> Ptr Word8
forall a. ForeignPtr a -> Ptr a
F.unsafeForeignPtrToPtr ForeignPtr Word8
resIbFptr)
let resAPtr :: Ptr UInt8
resAPtr = Ptr Word8 -> Ptr UInt8
forall a b. Ptr a -> Ptr b
F.castPtr (ForeignPtr Word8 -> Ptr Word8
forall a. ForeignPtr a -> Ptr a
F.unsafeForeignPtrToPtr ForeignPtr Word8
resAFptr )
let resBPtr :: Ptr UInt8
resBPtr = Ptr Word8 -> Ptr UInt8
forall a b. Ptr a -> Ptr b
F.castPtr (ForeignPtr Word8 -> Ptr Word8
forall a. ForeignPtr a -> Ptr a
F.unsafeForeignPtrToPtr ForeignPtr Word8
resBFptr )
let (ForeignPtr Word8
bsFptr, Int
bsOff, Int
bsLen) = ByteString -> (ForeignPtr Word8, Int, Int)
BSI.toForeignPtr ByteString
bs
let bsPtr :: Ptr Any
bsPtr = Ptr Word8 -> Ptr Any
forall a b. Ptr a -> Ptr b
F.castPtr (ForeignPtr Word8 -> Ptr Word8
forall a. ForeignPtr a -> Ptr a
F.unsafeForeignPtrToPtr ForeignPtr Word8
bsFptr)
UInt64
_ <- Ptr UInt8
-> UInt64
-> Ptr UInt8
-> Ptr UInt8
-> Ptr UInt8
-> Ptr UInt8
-> Ptr UInt8
-> Ptr UInt8
-> Ptr UInt64
-> Ptr UInt64
-> Ptr UInt64
-> Ptr UInt64
-> Ptr UInt8
-> Ptr UInt8
-> Ptr UInt8
-> IO UInt64
F.processChunk
(Ptr Any -> Int -> Ptr UInt8
forall a b. Ptr a -> Int -> Ptr b
F.plusPtr Ptr Any
bsPtr Int
bsOff)
(Int -> UInt64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
bsLen)
(WorkBuffers -> Ptr UInt8
workBuffersD WorkBuffers
wb)
(WorkBuffers -> Ptr UInt8
workBuffersA WorkBuffers
wb)
(WorkBuffers -> Ptr UInt8
workBuffersZ WorkBuffers
wb)
(WorkBuffers -> Ptr UInt8
workBuffersQ WorkBuffers
wb)
(WorkBuffers -> Ptr UInt8
workBuffersB WorkBuffers
wb)
(WorkBuffers -> Ptr UInt8
workBuffersE WorkBuffers
wb)
(WorkState -> Ptr UInt64
workStateZ WorkState
ws)
(WorkState -> Ptr UInt64
workStateO WorkState
ws)
(WorkState -> Ptr UInt64
workStateE WorkState
ws)
(WorkState -> Ptr UInt64
workStateM WorkState
ws)
Ptr UInt8
resIbPtr
Ptr UInt8
resAPtr
Ptr UInt8
resBPtr
let r :: (ByteString, ByteString, ByteString)
r =
( ForeignPtr Word8 -> Int -> Int -> ByteString
BSI.fromForeignPtr ForeignPtr Word8
resIbFptr Int
0 Int
resLen
, ForeignPtr Word8 -> Int -> Int -> ByteString
BSI.fromForeignPtr ForeignPtr Word8
resAFptr Int
0 Int
resLen
, ForeignPtr Word8 -> Int -> Int -> ByteString
BSI.fromForeignPtr ForeignPtr Word8
resBFptr Int
0 Int
resLen
)
[(ByteString, ByteString, ByteString)]
rs <- IO [(ByteString, ByteString, ByteString)]
-> IO [(ByteString, ByteString, ByteString)]
forall a. IO a -> IO a
IO.unsafeInterleaveIO (IO [(ByteString, ByteString, ByteString)]
-> IO [(ByteString, ByteString, ByteString)])
-> IO [(ByteString, ByteString, ByteString)]
-> IO [(ByteString, ByteString, ByteString)]
forall a b. (a -> b) -> a -> b
$ WorkBuffers
-> WorkState
-> [ByteString]
-> IO [(ByteString, ByteString, ByteString)]
go WorkBuffers
wb WorkState
ws [ByteString]
bss
[(ByteString, ByteString, ByteString)]
-> IO [(ByteString, ByteString, ByteString)]
forall (m :: * -> *) a. Monad m => a -> m a
return ((ByteString, ByteString, ByteString)
r(ByteString, ByteString, ByteString)
-> [(ByteString, ByteString, ByteString)]
-> [(ByteString, ByteString, ByteString)]
forall a. a -> [a] -> [a]
:[(ByteString, ByteString, ByteString)]
rs)
ibsToIndexByteStrings :: ()
=> [(BS.ByteString, BS.ByteString, BS.ByteString)]
-> [BS.ByteString]
ibsToIndexByteStrings :: [(ByteString, ByteString, ByteString)] -> [ByteString]
ibsToIndexByteStrings [(ByteString, ByteString, ByteString)]
bits = IO [ByteString] -> [ByteString]
forall a. IO a -> a
F.unsafeLocalState (IO [ByteString] -> [ByteString])
-> IO [ByteString] -> [ByteString]
forall a b. (a -> b) -> a -> b
$ do
BpState
bpState <- IO BpState
emptyBpState
IO [ByteString] -> IO [ByteString]
forall a. IO a -> IO a
IO.unsafeInterleaveIO (IO [ByteString] -> IO [ByteString])
-> IO [ByteString] -> IO [ByteString]
forall a b. (a -> b) -> a -> b
$ BpState -> [Step] -> IO [ByteString]
go BpState
bpState (((ByteString, ByteString, ByteString) -> Step)
-> [(ByteString, ByteString, ByteString)] -> [Step]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\(ByteString
a, ByteString
b, ByteString
c) -> ByteString -> ByteString -> ByteString -> Step
mkIndexStep ByteString
a ByteString
b ByteString
c) [(ByteString, ByteString, ByteString)]
bits)
where go :: ()
=> BpState
-> [Step]
-> IO [BS.ByteString]
go :: BpState -> [Step] -> IO [ByteString]
go BpState
s (Step
step:[Step]
steps) = do
let bp :: ByteString
bp = BpState -> Step -> ByteString
stepToByteString BpState
s Step
step
[ByteString]
bps <- IO [ByteString] -> IO [ByteString]
forall a. IO a -> IO a
IO.unsafeInterleaveIO (IO [ByteString] -> IO [ByteString])
-> IO [ByteString] -> IO [ByteString]
forall a b. (a -> b) -> a -> b
$ BpState -> [Step] -> IO [ByteString]
go BpState
s [Step]
steps
[ByteString] -> IO [ByteString]
forall (m :: * -> *) a. Monad m => a -> m a
return ([ByteString] -> IO [ByteString])
-> [ByteString] -> IO [ByteString]
forall a b. (a -> b) -> a -> b
$ ByteString
bpByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
:[ByteString]
bps
go BpState
s [] = [ByteString] -> IO [ByteString]
forall (m :: * -> *) a. Monad m => a -> m a
return [BpState -> Step -> ByteString
stepToByteString BpState
s Step
indexStepFinal]
mkIndexStep :: BS.ByteString -> BS.ByteString -> BS.ByteString -> Step
mkIndexStep :: ByteString -> ByteString -> ByteString -> Step
mkIndexStep ByteString
is ByteString
as ByteString
zs | Int
isLen Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
asLen Bool -> Bool -> Bool
&& Int
asLen Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
zsLen = (forall s. BpState -> MVector s Word64 -> ST s Int) -> Int -> Step
Step forall s. BpState -> MVector s Word64 -> ST s Int
go Int
isLen
where isLen :: Int
isLen = ByteString -> Int
BS.length ByteString
is
asLen :: Int
asLen = ByteString -> Int
BS.length ByteString
as
zsLen :: Int
zsLen = ByteString -> Int
BS.length ByteString
zs
(ForeignPtr Word8
isFptr, Int
_, Int
_) = ByteString -> (ForeignPtr Word8, Int, Int)
BSI.toForeignPtr ByteString
is
(ForeignPtr Word8
asFptr, Int
_, Int
_) = ByteString -> (ForeignPtr Word8, Int, Int)
BSI.toForeignPtr ByteString
as
(ForeignPtr Word8
zsFptr, Int
_, Int
_) = ByteString -> (ForeignPtr Word8, Int, Int)
BSI.toForeignPtr ByteString
zs
go :: BpState
-> DVSM.MVector s Word64
-> ST s Int
go :: BpState -> MVector s Word64 -> ST s Int
go BpState
bpState MVector s Word64
bpvm = (UInt64 -> Int) -> ST s UInt64 -> ST s Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap UInt64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ST s UInt64 -> ST s Int)
-> (IO UInt64 -> ST s UInt64) -> IO UInt64 -> ST s Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO UInt64 -> ST s UInt64
forall a s. IO a -> ST s a
ST.unsafeIOToST (IO UInt64 -> ST s Int) -> IO UInt64 -> ST s Int
forall a b. (a -> b) -> a -> b
$ do
let (ForeignPtr Word64
outFptr, Int
_, Int
_) = MVector s Word64 -> (ForeignPtr Word64, Int, Int)
forall a s. Storable a => MVector s a -> (ForeignPtr a, Int, Int)
DVSM.unsafeToForeignPtr MVector s Word64
bpvm
ForeignPtr Word64 -> (Ptr Word64 -> IO UInt64) -> IO UInt64
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
F.withForeignPtr ForeignPtr Word64
outFptr ((Ptr Word64 -> IO UInt64) -> IO UInt64)
-> (Ptr Word64 -> IO UInt64) -> IO UInt64
forall a b. (a -> b) -> a -> b
$ \Ptr Word64
outPtr ->
ForeignPtr Word8 -> (Ptr Word8 -> IO UInt64) -> IO UInt64
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
F.withForeignPtr ForeignPtr Word8
isFptr ((Ptr Word8 -> IO UInt64) -> IO UInt64)
-> (Ptr Word8 -> IO UInt64) -> IO UInt64
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
isPtr ->
ForeignPtr Word8 -> (Ptr Word8 -> IO UInt64) -> IO UInt64
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
F.withForeignPtr ForeignPtr Word8
asFptr ((Ptr Word8 -> IO UInt64) -> IO UInt64)
-> (Ptr Word8 -> IO UInt64) -> IO UInt64
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
asPtr ->
ForeignPtr Word8 -> (Ptr Word8 -> IO UInt64) -> IO UInt64
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
F.withForeignPtr ForeignPtr Word8
zsFptr ((Ptr Word8 -> IO UInt64) -> IO UInt64)
-> (Ptr Word8 -> IO UInt64) -> IO UInt64
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
zsPtr ->
ForeignPtr Word8 -> (Ptr Word8 -> IO UInt64) -> IO UInt64
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
F.withForeignPtr (BpState -> ForeignPtr Word8
bpStateP BpState
bpState) ((Ptr Word8 -> IO UInt64) -> IO UInt64)
-> (Ptr Word8 -> IO UInt64) -> IO UInt64
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
bpStatePtr -> do
Ptr UInt8
-> Ptr UInt8
-> Ptr UInt8
-> UInt64
-> Ptr ()
-> Ptr UInt8
-> IO UInt64
F.writeBpChunk
(Ptr Word8 -> Ptr UInt8
forall a b. Ptr a -> Ptr b
F.castPtr Ptr Word8
isPtr)
(Ptr Word8 -> Ptr UInt8
forall a b. Ptr a -> Ptr b
F.castPtr Ptr Word8
asPtr)
(Ptr Word8 -> Ptr UInt8
forall a b. Ptr a -> Ptr b
F.castPtr Ptr Word8
zsPtr)
(Int -> UInt64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int
BS.length ByteString
is))
(Ptr Word8 -> Ptr ()
forall a b. Ptr a -> Ptr b
F.castPtr Ptr Word8
bpStatePtr)
(Ptr Word64 -> Ptr UInt8
forall a b. Ptr a -> Ptr b
F.castPtr Ptr Word64
outPtr)
mkIndexStep ByteString
_ ByteString
_ ByteString
_ = String -> Step
forall a. HasCallStack => String -> a
error String
"Mismatched input size"
indexStepFinal :: Step
indexStepFinal :: Step
indexStepFinal = (forall s. BpState -> MVector s Word64 -> ST s Int) -> Int -> Step
Step forall s. BpState -> MVector s Word64 -> ST s Int
go Int
2
where go :: BpState
-> DVSM.MVector s Word64
-> ST s Int
go :: BpState -> MVector s Word64 -> ST s Int
go BpState
bpState MVector s Word64
bpvm = (UInt64 -> Int) -> ST s UInt64 -> ST s Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap UInt64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ST s UInt64 -> ST s Int)
-> (IO UInt64 -> ST s UInt64) -> IO UInt64 -> ST s Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO UInt64 -> ST s UInt64
forall a s. IO a -> ST s a
ST.unsafeIOToST (IO UInt64 -> ST s Int) -> IO UInt64 -> ST s Int
forall a b. (a -> b) -> a -> b
$ do
let (ForeignPtr Word64
outFptr, Int
_, Int
_) = MVector s Word64 -> (ForeignPtr Word64, Int, Int)
forall a s. Storable a => MVector s a -> (ForeignPtr a, Int, Int)
DVSM.unsafeToForeignPtr MVector s Word64
bpvm
ForeignPtr Word64 -> (Ptr Word64 -> IO UInt64) -> IO UInt64
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
F.withForeignPtr ForeignPtr Word64
outFptr ((Ptr Word64 -> IO UInt64) -> IO UInt64)
-> (Ptr Word64 -> IO UInt64) -> IO UInt64
forall a b. (a -> b) -> a -> b
$ \Ptr Word64
outPtr ->
ForeignPtr Word8 -> (Ptr Word8 -> IO UInt64) -> IO UInt64
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
F.withForeignPtr (BpState -> ForeignPtr Word8
bpStateP BpState
bpState) ((Ptr Word8 -> IO UInt64) -> IO UInt64)
-> (Ptr Word8 -> IO UInt64) -> IO UInt64
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
bpStatePtr -> do
Ptr () -> Ptr UInt8 -> IO UInt64
F.writeBpChunkFinal (Ptr Word8 -> Ptr ()
forall a b. Ptr a -> Ptr b
F.castPtr Ptr Word8
bpStatePtr) (Ptr Word64 -> Ptr UInt8
forall a b. Ptr a -> Ptr b
F.castPtr Ptr Word64
outPtr)
stepToByteString :: BpState -> Step -> BS.ByteString
stepToByteString :: BpState -> Step -> ByteString
stepToByteString BpState
state (Step forall s. BpState -> MVector s Word64 -> ST s Int
step Int
size) = IO ByteString -> ByteString
forall a. IO a -> a
F.unsafeLocalState (IO ByteString -> ByteString) -> IO ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ do
let bsSize :: Int
bsSize = Int
size Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
8
ForeignPtr Word8
bpFptr <- Int -> IO (ForeignPtr Word8)
forall a. Int -> IO (ForeignPtr a)
BSI.mallocByteString Int
bsSize
let bpVm :: MVector RealWorld Word64
bpVm = ForeignPtr Word64 -> Int -> Int -> MVector RealWorld Word64
forall a s. Storable a => ForeignPtr a -> Int -> Int -> MVector s a
DVSM.unsafeFromForeignPtr (ForeignPtr Word8 -> ForeignPtr Word64
forall a b. ForeignPtr a -> ForeignPtr b
F.castForeignPtr ForeignPtr Word8
bpFptr) Int
0 Int
size
Int
w64Size <- ST RealWorld Int -> IO Int
forall a. ST RealWorld a -> IO a
stToIO (ST RealWorld Int -> IO Int) -> ST RealWorld Int -> IO Int
forall a b. (a -> b) -> a -> b
$ BpState -> MVector RealWorld Word64 -> ST RealWorld Int
forall s. BpState -> MVector s Word64 -> ST s Int
step BpState
state MVector RealWorld Word64
bpVm
ByteString -> IO ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return (ForeignPtr Word8 -> Int -> Int -> ByteString
BSI.PS ForeignPtr Word8
bpFptr Int
0 (Int
w64Size Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
8))
enabledMakeSimpleJsonIbBps :: Bool
enabledMakeSimpleJsonIbBps :: Bool
enabledMakeSimpleJsonIbBps = Bool
C.avx_2 Bool -> Bool -> Bool
&& Bool
C.sse_4_2 Bool -> Bool -> Bool
&& Bool
C.bmi_2