{- Copyright (c) Meta Platforms, Inc. and affiliates. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. -} module Glean.RTS.Foreign.Subst ( Subst , empty , serialize , substIntervals , unsafeSubstIntervalsAndRelease , subst , substVector , deserialize , substOffset ) where import Control.Exception import Data.Int import Data.Word import qualified Data.Vector.Storable as VS import Foreign.C.String import Foreign.C.Types import Foreign.ForeignPtr import Foreign.Ptr import System.IO.Unsafe import Util.FFI import Glean.FFI import Glean.RTS.Types (Fid(..), lowestFid) import qualified Glean.Types as Thrift newtype Subst = Subst (ForeignPtr Subst) instance Object Subst where wrap = Subst unwrap (Subst p) = p destroy = glean_free_subst instance Semigroup Subst where s <> t = unsafePerformIO $ with s $ \s_ptr -> with t $ \t_ptr -> construct $ invoke $ glean_subst_compose s_ptr t_ptr instance Monoid Subst where mempty = empty empty :: Subst {-# NOINLINE empty #-} empty = unsafePerformIO $ construct $ invoke $ glean_new_subst lowestFid 0 serialize :: Subst -> Thrift.Subst serialize subst = unsafePerformIO $ with subst $ \subst_ptr -> do (Fid id,count,p) <- invoke $ glean_serialize_subst subst_ptr vec <- unsafeMallocedVector p count return $ Thrift.Subst id vec substOffset :: Subst -> Int substOffset subst = fromIntegral $ unsafeDupablePerformIO $ with subst glean_subst_offset -- | Apply the given substitution to one Fid subst :: Subst -> Fid -> Fid subst subst old = unsafePerformIO $ with subst $ \subst_ptr -> mask_ $ invoke $ glean_subst_subst subst_ptr old -- | Apply the given subsitution to all the Fids in the vector substVector :: Subst -> VS.Vector Fid -> IO (VS.Vector Fid) substVector subst vec = with subst $ \subst_ptr -> VS.unsafeWith vec $ \vec_ptr -> mask_ $ do (outs_ptr, outs_size) <- invoke $ glean_subst_vector subst_ptr vec_ptr (fromIntegral $ VS.length vec) unsafeMallocedVector outs_ptr outs_size -- | Apply the given substitution to the intervals substIntervals :: Subst -> VS.Vector Fid -> IO (VS.Vector Fid) substIntervals subst ins = with subst $ \subst_ptr -> VS.unsafeWith ins $ \ins_ptr -> mask_ $ do (outs_ptr, outs_size) <- invoke $ glean_subst_intervals subst_ptr ins_ptr (fromIntegral $ VS.length ins) unsafeMallocedVector outs_ptr outs_size -- | Like 'substIntervals', but also releases the input vector -- immediately, rather than waiting for the GC to run. The input -- vector must never be used again. unsafeSubstIntervalsAndRelease :: Subst -> VS.Vector Fid -> IO (VS.Vector Fid) unsafeSubstIntervalsAndRelease subst ins = do new <- substIntervals subst ins let !(fp, _) = VS.unsafeToForeignPtr0 ins finalizeForeignPtr fp return new deserialize :: Thrift.Subst -> IO Subst deserialize Thrift.Subst{..} = VS.unsafeWith subst_ids $ \ids_ptr -> construct $ invoke $ glean_subst_deserialize (Fid subst_firstId) (fromIntegral $ VS.length subst_ids) ids_ptr foreign import ccall unsafe glean_new_subst :: Fid -> CSize -> Ptr (Ptr Subst) -> IO CString foreign import ccall unsafe "&glean_free_subst" glean_free_subst :: FunPtr (Ptr Subst -> IO ()) foreign import ccall unsafe glean_subst_compose :: Ptr Subst -> Ptr Subst -> Ptr (Ptr Subst) -> IO CString foreign import ccall safe glean_serialize_subst :: Ptr Subst -> Ptr Fid -> Ptr CSize -> Ptr (Ptr Int64) -> IO CString foreign import ccall safe glean_subst_deserialize :: Fid -> CSize -> Ptr Int64 -> Ptr (Ptr Subst) -> IO CString foreign import ccall safe glean_subst_intervals :: Ptr Subst -> Ptr Fid -> CSize -> Ptr (Ptr Fid) -> Ptr CSize -> IO CString foreign import ccall unsafe glean_subst_subst :: Ptr Subst -> Fid -> Ptr Fid -> IO CString foreign import ccall safe glean_subst_vector :: Ptr Subst -> Ptr Fid -> CSize -> Ptr (Ptr Fid) -> Ptr CSize -> IO CString foreign import ccall unsafe glean_subst_offset :: Ptr Subst -> IO Word64