
    MiN                        S r SSKrSSKrSSKrSSKJr  SSKJr  SSK	r
SSKJr  SSKJr   SSKJr  S	\4S
 jr\R&                  S:  a
  SSKJr  S rO\r SSKJr  SS jrS r " S S\
R<                  5      r " S S5      r  " S S5      r! " S S\5      r"g! \ a	    SSKJr   Nuf = f! \ a+     SSKJr   N^! \ a    \R6                  " S5        \r  N{f = ff = f)a  
caching.py
-----------

Functions and classes that help with tracking changes
in `numpy.ndarray` and clearing cached values based
on those changes.

You should really `pip install xxhash`:

```
In [23]: %timeit int(blake2b(d).hexdigest(), 16)
102 us +/- 684 ns per loop

In [24]: %timeit int(sha256(d).hexdigest(), 16)
142 us +/- 3.73 us

In [25]: %timeit xxh3_64_intdigest(d)
3.37 us +/- 116 ns per loop
```
    N)wraps)sha256   )log)is_sequence)Mappingreturnc                 H    [        [        U 5      R                  5       S5      $ )N   )int_sha256	hexdigestitems    i/var/www/eduai.edurigo.com/storigo/production/storigo_env/lib/python3.13/site-packages/trimesh/caching.pyr   r   (   s    wt}&&("--    )   	   )blake2bc                 F    [        [        U SS9R                  5       S5      $ )NF)usedforsecurityr   )r   _blake2br   r   s    r   hash_fallbackr   0   s    8D%8BBDbIIr   )xxh3_64_intdigest)xxh64_intdigestzPfalling back to hashlib hashing: `pip install xxhash`for 50x faster cache checksc                     U c  / n [         R                  " XS9R                  [        5      nUR                  S   (       d   eU$ )aq  
Properly subclass a numpy ndarray to track changes.

Avoids some pitfalls of subclassing by forcing contiguous
arrays and does a view into a TrackedArray.

Parameters
------------
array : array- like object
  To be turned into a TrackedArray
dtype : np.dtype
  Which dtype to use for the array

Returns
------------
tracked : TrackedArray
  Contains input array data.
dtypeC_CONTIGUOUS)npascontiguousarrayviewTrackedArrayflags)arrayr   trackeds      r   tracked_arrayr'   I   s@    ( }""56;;LIG==(((Nr   c                 B   ^  [        T 5      U 4S j5       n[        U5      $ )a  
A decorator for class methods, replaces @property
but will store and retrieve function return values
in object cache.

Parameters
------------
function : method
  This is used as a decorator:
  ```
  @cache_decorator
  def foo(self, things):
    return 'happy days'
  ```
c                    > U S   nTR                   nUR                  R                  5         X2R                  R                  ;   a  UR                  R                  U   $ T" U 0 UD6nUR                  R                  (       a;  [        US5      (       a*  [        UR                  5      S:  a  SUR                  l	        XBR                  R                  U'   U$ )zG
Only execute the function if its value isn't stored
in cache already.
r   r$   F)
__name___cacheverifycacheforce_immutablehasattrlenshaper$   	writeable)argskwargsselfnamevaluefunctions        r   
get_cached#cache_decorator.<locals>.get_cachedy   s     Aw   	 ;;$$$;;$$T**$)&) KK''w''EKK 1$$)EKK!"'$r   )r   property)r8   r9   s   ` r   cache_decoratorr<   g   s)    $ 8_ B Jr   c                   ~  ^  \ rS rSrSrS rS S jr\S 5       r\R                  S 5       rS r
U 4S jrU 4S	 jrU 4S
 jrU 4S jrU 4S jrU 4S jrU 4S jrU 4S jrU 4S jrU 4S jrU 4S jrU 4S jrU 4S jrU 4S jrU 4S jrU 4S jrU 4S jrU 4S jrU 4S jrU 4S jrU 4S jrU 4S jr U 4S jr!Sr"U =r#$ )!r#      a  
Subclass of numpy.ndarray that provides hash methods
to track changes.

General method is to aggressively set 'modified' flags
on operations which might (but don't necessarily) alter
the array, ideally we sometimes compute hashes when we
don't need to, but we don't return wrong hashes ever.

We store boolean modified flag for each hash type to
make checks fast even for queries of different hashes.

Methods
----------
__hash__ : int
  Runs the fastest available hash in this order:
    `xxh3_64, xxh_64, blake2b, sha256`
c                 V    SU l         [        U[        U 5      5      (       a  SUl         gg)z
Sets a modified flag on every TrackedArray
This flag will be set on every change as well as
during copies and certain types of slicing.
TN)_dirty_hash
isinstancetype)r5   objs     r   __array_finalize__TrackedArray.__array_finalize__   s)      c4:&&"CO 'r   c                 x    UR                   (       a%  [        R                  R                  " XU/UQ70 UD6$ US   $ )zV
Return a numpy scalar if array is 0d.
See https://github.com/numpy/numpy/issues/5819
 )ndimr    ndarray__array_wrap__)r5   out_arrcontextr3   r4   s        r   rJ   TrackedArray.__array_wrap__   s6    
 <<::,,TGUdUfUUr{r   c                      U R                   S   $ )N	WRITEABLE)r$   r5   s    r   mutableTrackedArray.mutable   s    zz+&&r   c                 $    XR                   l        g N)r$   r2   )r5   r7   s     r   rQ   rR      s    $

r   c                     U R                   (       d  [        U S5      (       a  U R                  $ [        U R	                  SS95      nXl        SU l         U$ )zy
Return a fast hash of the contents of the array.

Returns
-------------
hash : long int
  A hash of the array contents.
_hashedC)orderF)r@   r/   rV   	hash_fasttobytes)r5   hasheds     r   __hash__TrackedArray.__hash__   sN     GD)$<$<<< 4<<c<23  r   c                 F   > SU l         [        U R                  U ]  " U0 UD6$ )zk
In-place addition.

The i* operations are in- place and modify the array,
so we better catch all of them.
T)r@   super	__class____iadd__r5   r3   r4   r`   s      r   ra   TrackedArray.__iadd__   s(      T^^T3TDVDDr   c                 F   > SU l         [        U R                  U ]  " U0 UD6$ NT)r@   r_   r`   __isub__rb   s      r   rf   TrackedArray.__isub__   &    T^^T3TDVDDr   c                 F   > SU l         [        U R                  U ]  " U0 UD6$ re   )r@   r_   r`   fillrb   s      r   rj   TrackedArray.fill   &    T^^T/@@@r   c                 F   > SU l         [        U R                  U ]  " U0 UD6$ re   )r@   r_   r`   	partitionrb   s      r   rn   TrackedArray.partition   s&    T^^T4dEfEEr   c                 F   > SU l         [        U R                  U ]  " U0 UD6$ re   )r@   r_   r`   putrb   s      r   rq   TrackedArray.put   s&    T^^T.???r   c                 F   > SU l         [        U R                  U ]  " U0 UD6$ re   )r@   r_   r`   byteswaprb   s      r   rt   TrackedArray.byteswap  rh   r   c                 F   > SU l         [        U R                  U ]  " U0 UD6$ re   )r@   r_   r`   itemsetrb   s      r   rw   TrackedArray.itemset  &    T^^T2DCFCCr   c                 F   > SU l         [        U R                  U ]  " U0 UD6$ re   )r@   r_   r`   sortrb   s      r   r{   TrackedArray.sort	  rl   r   c                 F   > SU l         [        U R                  U ]  " U0 UD6$ re   )r@   r_   r`   setflagsrb   s      r   r~   TrackedArray.setflags  rh   r   c                 F   > SU l         [        U R                  U ]  " U0 UD6$ re   )r@   r_   r`   __imul__rb   s      r   r   TrackedArray.__imul__  rh   r   c                 F   > SU l         [        U R                  U ]  " U0 UD6$ re   )r@   r_   r`   __idiv__rb   s      r   r   TrackedArray.__idiv__  rh   r   c                 F   > SU l         [        U R                  U ]  " U0 UD6$ re   )r@   r_   r`   __itruediv__rb   s      r   r   TrackedArray.__itruediv__  &    T^^T7HHHr   c                 F   > SU l         [        U R                  U ]  " U0 UD6$ re   )r@   r_   r`   __imatmul__rb   s      r   r   TrackedArray.__imatmul__  &    T^^T6GGGr   c                 F   > SU l         [        U R                  U ]  " U0 UD6$ re   )r@   r_   r`   __ipow__rb   s      r   r   TrackedArray.__ipow__!  rh   r   c                 F   > SU l         [        U R                  U ]  " U0 UD6$ re   )r@   r_   r`   __imod__rb   s      r   r   TrackedArray.__imod__%  rh   r   c                 F   > SU l         [        U R                  U ]  " U0 UD6$ re   )r@   r_   r`   __ifloordiv__rb   s      r   r   TrackedArray.__ifloordiv__)  s&    T^^T8$I&IIr   c                 F   > SU l         [        U R                  U ]  " U0 UD6$ re   )r@   r_   r`   __ilshift__rb   s      r   r   TrackedArray.__ilshift__-  r   r   c                 F   > SU l         [        U R                  U ]  " U0 UD6$ re   )r@   r_   r`   __irshift__rb   s      r   r   TrackedArray.__irshift__1  r   r   c                 F   > SU l         [        U R                  U ]  " U0 UD6$ re   )r@   r_   r`   __iand__rb   s      r   r   TrackedArray.__iand__5  rh   r   c                 F   > SU l         [        U R                  U ]  " U0 UD6$ re   )r@   r_   r`   __ixor__rb   s      r   r   TrackedArray.__ixor__9  rh   r   c                 F   > SU l         [        U R                  U ]  " U0 UD6$ re   )r@   r_   r`   __ior__rb   s      r   r   TrackedArray.__ior__=  ry   r   c                 F   > SU l         [        U R                  U ]  " U0 UD6$ re   )r@   r_   r`   __setitem__rb   s      r   r   TrackedArray.__setitem__A  r   r   c                 F   > SU l         [        U R                  U ]  " U0 UD6$ re   )r@   r_   r`   __setslice__rb   s      r   r   TrackedArray.__setslice__E  r   r   )r@   rV   rT   )$r*   
__module____qualname____firstlineno____doc__rD   rJ   r;   rQ   setterr\   ra   rf   rj   rn   rq   rt   rw   r{   r~   r   r   r   r   r   r   r   r   r   r   r   r   r   r   __static_attributes____classcell__)r`   s   @r   r#   r#      s    &	# ' ' ^^% %.	EEAF@EDAEEEIHEEJHHEEDHI Ir   r#   c                   h    \ rS rSrSrSS jrS rS rSS jrS r	S	 r
S
 rS rS rS rS rS rSrg)CacheiJ  zX
Class to cache values which will be stored until the
result of an ID function changes.
c                 Z    Xl         [        U5      U l        SU l        SU l        0 U l        g)z
Create a cache object.

Parameters
------------
id_function : function
  Returns hashable value
force_immutable : bool
  If set will make all numpy arrays read-only
Nr   )_id_functionboolr.   
id_current_lockr-   )r5   id_functionr.   s      r   __init__Cache.__init__P  s,     (#O4

r   c                 \    XR                   ;   a  U R                   R                  US5        gg)z
Remove a key from the cache.
N)r-   popr5   keys     r   deleteCache.deletee  s%     **JJNN3% r   c           
      \   U R                   S:w  a  gU R                  5       nXR                  :w  a|  [        U R                  5      S:  aU  [
        R                  " S[        U R                  5      [        [        U R                  R                  5       5      5      5        0 U l        Xl        gg)z
Verify that the cached values are still for the same
value of id_function and delete all stored items if
the value of id_function has changed.
r   Nz%d items cleared from cache: %s)
r   r   r   r0   r-   r   debugstrlistkeys)r5   id_news     r   r,   Cache.verifyl  s     ::? ""$ __$4::"		5

OTZZ__./0 DJ$O %r   Nc                     Uc  0 U l         gU R                   R                  5        VVs0 s H  u  p#X!;   d  M  X#_M     snnU l         gs  snnf )zl
Remove elements in the cache.

Parameters
-----------
exclude : list
  List of keys in cache to not clear.
N)r-   items)r5   excludekvs       r   clearCache.clear  sB     ?DJ+/::+;+;+=N+=41$!$+=NDJNs
   AAc                 <   U R                   R                  U5        U R                  (       a`  U R                   R                  5        HB  n[	        US5      (       d  M  [        UR                  5      S:  d  M1  SUR                  l        MD     U R                  5         g)zO
Update the cache with a set of key, value pairs without
checking id_function.
r$   r   FN)
r-   updater.   valuesr/   r0   r1   r$   r2   id_set)r5   r   r   s      r   r   Cache.update  si    
 	

% ZZ&&(1g&&3qww<!+;(-AGG% ) 	r   c                 .    U R                  5       U l        g)z5
Set the current ID to the value of the ID function.
N)r   r   rP   s    r   r   Cache.id_set  s     ++-r   c                 `    U R                  5         XR                  ;   a  U R                  U   $ g)z
Get an item from the cache. If the item
is not in the cache, it will return None

Parameters
-------------
key : hashable
       Key in dict

Returns
-------------
cached : object, or None
  Object that was stored
Nr,   r-   r   s     r   __getitem__Cache.__getitem__  s(     	**::c?"r   c                     U R                  5         U R                  (       a;  [        US5      (       a*  [        UR                  5      S:  a  SUR
                  l        X R                  U'   U$ )z
Add an item to the cache.

Parameters
------------
key : hashable
  Key to reference value
value : any
  Value to store in cache
r$   r   F)r,   r.   r/   r0   r1   r$   r2   r-   )r5   r   r7   s      r   r   Cache.__setitem__  sO     	GE7$;$;EKK@PST@T$)EKK!

3r   c                 >    U R                  5         XR                  ;   $ rT   r   r   s     r   __contains__Cache.__contains__  s    jj  r   c                 L    U R                  5         [        U R                  5      $ rT   )r,   r0   r-   rP   s    r   __len__Cache.__len__  s    4::r   c                 .    U =R                   S-  sl         g Nr   )r   rP   s    r   	__enter__Cache.__enter__  s    

a
r   c                 X    U =R                   S-  sl         U R                  5       U l        g r   )r   r   r   )r5   r3   s     r   __exit__Cache.__exit__  s    

a
++-r   )r   r   r-   r.   r   )FrT   )r*   r   r   r   r   r   r   r,   r   r   r   r   r   r   r   r   r   r   rG   r   r   r   r   J  sD    
*&%8O.(*!.r   r   c                   (    \ rS rSrSrSS jrS rSrg)	DiskCachei  z
Store results of expensive operations on disk
with an option to expire the results. This is used
to cache the multi-gigabyte test corpuses in
`tests/corpus.py`
c                     X l         [        R                  R                  [        R                  R	                  U5      5      U l        [        R
                  " U R                  SS9  g)z
Create a cache on disk for storing expensive results.

Parameters
--------------
path : str
  A writeable location on the current file path.
expire_days : int or float
  How old should results be considered expired.

T)exist_okN)expire_daysospathabspath
expandusermakedirs)r5   r   r   s      r   r   DiskCache.__init__  s?     'GGOOBGG$6$6t$<=	
DII-r   c                    [        UR                  S5      5      R                  5       n[        R                  R                  U R                  U5      n[        R                  R                  U5      (       an  [        R                  " 5       [        R                  " U5      R                  -
  S-  nXPR                  :  a&  [        US5       nUR                  5       sSSS5        $ [        R                  " SU S35        U" 5       n[        US5       nUR                  U5        SSS5        U$ ! , (       d  f       NW= f! , (       d  f       U$ = f)z
Get a key from the cache or run a calculation.

Parameters
-----------
key : str
  Key to reference item with
fetch : function
  If key isn't stored and recent run this
  function and store its result on disk.
zutf-8g     @rbNznot in cache fetching: ``wb)r   encoder   r   r   joinisfiletimestatst_mtimer   openreadr   r   write)r5   r   fetchkey_hashr   age_daysfraws           r   getDiskCache.get  s     3::g./99;ww||DIIx0 77>>$		bggdm&<&<<GH*** $%668 &% 			,SE34 g$GGCL  
 &%  
s   D.D?.
D<?
E)r   r   N)   )r*   r   r   r   r   r   r  r   rG   r   r   r   r     s    .&%r   r   c                       \ rS rSrSrS rS rS rS r\	S 5       r
\
R                  S 5       r
S	 rS
 rS rS rS rS rS rS rSrg)	DataStorei%  z}
A class to store multiple numpy arrays and track them all
for changes.

Operates like a dict that only stores numpy.ndarray
c                     0 U l         g rT   datarP   s    r   r   DataStore.__init__-  s	    	r   c                 ,    [        U R                  5      $ rT   )iterr  rP   s    r   __iter__DataStore.__iter__0  s    DIIr   c                 :    U R                   R                  US 5      $ rT   r  r   r   s     r   r   DataStore.pop3  s    yy}}S$''r   c                 <    U R                   R                  US 5        g rT   r  r   s     r   __delitem__DataStore.__delitem__6  s    		c4 r   c                     [        U SS5      $ )zu
Is data allowed to be altered or not.

Returns
-----------
is_mutable : bool
  Can data be altered in the DataStore
_mutableT)getattrrP   s    r   rQ   DataStore.mutable9  s     tZ..r   c                     [        U5      nU R                  R                  5        H   n[        U[        5      (       d  M  Xl        M"     X l        g)zy
Is data allowed to be altered or not.

Parameters
------------
is_mutable : bool
  Should data be allowed to be altered
N)r   r  r   rA   r#   rQ   r  )r5   r7   
is_mutabler   s       r   rQ   r  E  s=     %[
!!#A!\**!	 $ #r   c                    [        U R                  5      S:X  a  gU R                  R                  5        HL  n[        U5      (       a  [        U5      S:X  a    g  g[	        [
        R                  " U5      5      (       d  ML    g   g)zu
Is the current DataStore empty or not.

Returns
----------
empty : bool
  False if there are items in the DataStore
r   TF)r0   r  r   r   r   r    isrealr5   r   s     r   is_emptyDataStore.is_emptyX  sc     tyy>Q!!#A1~~q6Q; biil## $ r   c                     0 U l         g)z%
Remove all data from the DataStore.
Nr  rP   s    r   r   DataStore.clearm  s     	r   c                      U R                   U   $ rT   r  r   s     r   r   DataStore.__getitem__s  s    yy~r   c           	         U R                   (       d  [        S5      e[        U[        5      (       a  UnOI[        U[        R
                  [        [        [        45      (       a  [        U5      nO [        U5        Un[        U S5      (       a  U R                   Ul         X0R                  U'   g! [         a    [        SU S[        U5       S35      ef = f)z
Store an item in the DataStore.

Parameters
-------------
key
  A hashable key to store under
data
  Usually a numpy array which will be subclassed
  but anything hashable should be able to be stored.
z"DataStore is configured immutable!zunhashable `:r   r  N)rQ   
ValueErrorrA   r#   r    rI   r   settupler'   hashBaseExceptionrB   r/   r  )r5   r   r  r&   s       r   r   DataStore.__setitem__v  s     ||ABBdL))Grzz4e<==#D)GET
 G 4$$"llGO 		# ! E <uAd4j\!CDDEs   1B/ /&Cc                     XR                   ;   $ rT   r  r   s     r   r   DataStore.__contains__  s    iir   c                 ,    [        U R                  5      $ rT   )r0   r  rP   s    r   r   DataStore.__len__  s    499~r   c                 ~    [        U[        5      (       d  [        S5      eUR                  5        H	  u  p#X0U'   M     g )Nz!Update only implemented for dicts)rA   dictr,  r   )r5   r   r   r7   s       r   r   DataStore.update  s4    &$''@AA ,,.JCI )r   c                 2   [        [        R                  " U R                  R	                  5        Vs/ s H5  nUc  M  [        US5      (       a  [        U5      S:  d  M*  [        U5      PM7     sn[        R                  S9R                  5       5      $ s  snf )zq
Get a hash reflecting everything in the DataStore.

Returns
----------
hash : str
  hash of data in hexadecimal
r   r   r   )
rY   r    r%   r  r   r/   r0   r/  int64rZ   r#  s     r   r\   DataStore.__hash__  s     HH "YY--// .5a.C.Cs1vPQz DG/
 hh gi	
 		
s   BBB)r  r  N)r*   r   r   r   r   r   r  r   r  r;   rQ   r   r$  r   r   r   r   r   r   r\   r   rG   r   r   r  r  %  sp    (! 	/ 	/ ^^# #$*#!J 
r   r  rT   )#r   r   sysr   	functoolsr   hashlibr   r   numpyr    	constantsr   utilr   collections.abcr   r0  r   version_infor   r   r   xxhashr   rY   r   r   r'   r<   rI   r#   r   r   r  rG   r   r   <module>rE     s   , 
 
   %   ('
.C . v+J M"5<4 niI2:: iIXU. U.p@ @FV
 V
C  ('(.  "
"7 "		,	

 "	"	"s;   B B+ B('B(+C2B::CCCC