# Copyright 2022 ByteDance Ltd. and/or its affiliates.
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
from ... import _ffi
from .. import _ffi_api
from ..object import Object
from ..object_generic import to_runtime_object
[文档]@_ffi.register_object("FTDict")
@_ffi.register_object("runtime.Dict")
class Dict(Object):
    """matx.Dict implemented refering to python built-in dict,
       supports common methods of built-in list and some custom methods.
    Dict() -> construct empty dict
        >>> import matx
        >>> d = matx.Dict()
        >>> print(d)
        {}
    Dict(mapping) -> construct dict from mapping
        >>> import matx
        >>> d = matx.Dict({'a': 1, 'b':2})
        >>> print(d)
        {a: 1, b: 2}
    """
    __hash__ = None
[文档]    def __init__(self, seq=None, **kwargs):
        if seq:
            new_seqs = list()
            if isinstance(seq, dict):
                for k, v in seq.items():
                    new_seqs.append(to_runtime_object(k))
                    new_seqs.append(to_runtime_object(v))
            else:
                raise RuntimeError("[Dict.__init__] seq type is not support")
            self.__init_handle_by_constructor__(_ffi_api.Dict, *new_seqs)
        else:
            self.__init_handle_by_constructor__(_ffi_api.Dict) 
    def __setstate__(self, state):
        assert isinstance(state, (bytes, bytearray))
        arr = _ffi_api.msgpack_loads(state)
        assert isinstance(arr, Dict), "internal error"
        handle, code = _ffi.matx_script_api.steal_object_handle(arr)
        self.handle = handle
        self.type_code = code
    def __getstate__(self):
        return _ffi_api.msgpack_dumps(self)
    def __repr__(self):
        return _ffi_api.RTValue_Repr(self)
    def __getitem__(self, k):
        """ x.__getitem__(y) <==> x[y] """
        return _ffi_api.DictGetItem(self, to_runtime_object(k))
    def __setitem__(self, key, value):
        """ Set self[key] to value. """
        return _ffi_api.DictSetItem(self, to_runtime_object(key), to_runtime_object(value))
    # def __delitem__(self, *args, **kwargs):
    #     """ Delete self[key]. """
    #     pass
    def __len__(self):
        return _ffi_api.DictSize(self)
    def __contains__(self, k):
        """ True if D has a key k, else False. """
        return _ffi_api.DictContains(self, k)
    # def __getattribute__(self, *args, **kwargs):
    #     """ Return getattr(self, name). """
    #     pass
    #
    # def __iter__(self, *args, **kwargs):
    #     """ Implement iter(self). """
    #     pass
    # def __sizeof__(self):
    #     """ D.__sizeof__() -> size of D in memory, in bytes """
    #     pass
    def __eq__(self, other):
        """ Return self==value. """
        return _ffi_api.DictEqual(self, other)
    def __ne__(self, other):
        """ Return self!=value. """
        return not self.__eq__(other)
    #
    # def __ge__(self, *args, **kwargs):
    #     """ Return self>=value. """
    #     pass
    #
    # def __gt__(self, *args, **kwargs):
    #     """ Return self>value. """
    #     pass
    #
    # def __le__(self, *args, **kwargs):
    #     """ Return self<=value. """
    #     pass
    #
    # def __lt__(self, *args, **kwargs):
    #     """ Return self<value. """
    #     pass
[文档]    def clear(self):
        """Remove all items.
        Returns:
            None
        Examples:
            >>> import matx
            >>> d = matx.Dict({'a': 1, 'b': 2})
            >>> d
            {a: 1, b: 2}
            >>> d.clear()
            >>> d
            {}
        """
        _ffi_api.DictClear(self) 
[文档]    def reserve(self, new_size):
        """Increase the capacity of the dict to a value that's greater or equal to new_size.
        Args:
            new_size (int)
        Returns:
            None
        Examples:
            >>> d = matx.Dict({'a': 1, 'b': 2})
            >>> print(d.bucket_count())
            4
            >>> d.reserve(10)
            >>> print(d.bucket_count())
            32
        """
        _ffi_api.DictReserve(self, new_size) 
[文档]    def bucket_count(self):
        """Returns the number of slots in the hash table.
        Returns:
            int
        Examples:
            >>> d = matx.Dict({'a': 1, 'b': 2})
            >>> print(d.bucket_count())
            4
        """
        return _ffi_api.DictBucketCount(self) 
    # def copy(self):
    #     """ D.copy() -> a shallow copy of D """
    #     return _ffi_api.DictCopy(self)
    # @staticmethod  # known case
    # def fromkeys(*args, **kwargs):
    #     """ Returns a new dict with keys from iterable and values equal to value. """
    #     pass
[文档]    def get(self, k, d=None):
        """Return the value for key if key is in the dictionary, d.
        Args:
            k (item):
            d (item): defautl return value when k is not in dict
        Returns:
            item
        Examples:
            >>> import matx
            >>> d = matx.Dict({'a': 1, 'b': 2})
            >>> d.get('a')
            1
            >>> d.get('a', 3)
            1
            >>> d.get('c', 3)
            3
        """
        return _ffi_api.DictGetDefault(self, k, d) 
[文档]    def items(self):
        """Return a key-value iterable (matx.Iterator).
        Returns:
            matx.Iterator
        Examples:
            >>> import matx
            >>> d = matx.Dict({'a': 1, 'b': 2})
            >>> it = d.items()
            >>> type(it)
            <class 'matx.runtime._container._iterator.Iterator'>
            >>> for k, v in it:
            ...     print(k, v)
            ...
            a 1
            b 2
            """
        return _ffi_api.Dict_ItemIter(self) 
[文档]    def keys(self):
        """Return a key iterable.
        Returns:
            matx.Iterator
        Examples:
            >>> import matx
            >>> d = matx.Dict({'a': 1, 'b': 2})
            >>> it = d.keys()
            >>> type(it)
            <class 'matx.runtime._container._iterator.Iterator'>
            >>> for k in it:
            ...     print(k)
            ...
            a
            b
        """
        return _ffi_api.Dict_KeyIter(self) 
[文档]    def pop(self, k, *args):
        """.pop(k[,d]) -> v, remove specified key and return the corresponding value.
           If key is not found, d is returned if given, otherwise Exception is raised
        Args:
            k(item)
        Returns:
            item
        Examples:
            >>> import matx
            >>> d = matx.Dict({'a': 1, 'b': 2, 'c': 3})
            >>> d.pop('a')
            1
            >>> d.pop('a', 100)
            100
            >>> d.pop('a')
            Traceback (most recent call last):
            File "<stdin>", line 1, in <module>
            File "/data00/shubaihan/repos/matx4/python/matx/runtime/_container/_dict.py", line 223, in pop
                return _ffi_api.DictPop(self, k, *args)
            TypeError: MATXError: dict.pop KeyError
            Stack trace:
            File "/data00/shubaihan/repos/matx4/src/runtime/container/dict_ref.cc", line 305
            [bt] (0) /data00/shubaihan/repos/matx4/lib/libmatx.so(+0x33c9ed) [0x7f70d4ad39ed]
            [bt] (1) /data00/shubaihan/repos/matx4/lib/libmatx.so(matx::runtime::Dict::pop(matx::runtime::PyArgs)+0x92) [0x7f70d4ad5362]
            [bt] (2) /data00/shubaihan/repos/matx4/lib/libmatx.so(+0x33f434) [0x7f70d4ad6434]
            [bt] (3) /data00/shubaihan/repos/matx4/lib/libmatx.so(MATXFuncCall_PYTHON_C_API+0x45) [0x7f70d4ab8c45]
        """
        return _ffi_api.DictPop(self, k, *args) 
    # def popitem(self):
    #     """
    #     D.popitem() -> (k, v), remove and return some (key, value) pair as a
    #     2-tuple; but raise KeyError if D is empty.
    #     """
    #     pass
    #
    # def setdefault(self, k, d=None):
    #     """ D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D """
    #     pass
    #
    # def update(self, E=None, **F):  # known special case of dict.update
    #     """
    #     D.update([E, ]**F) -> None.  Update D from dict/iterable E and F.
    #     If E is present and has a .keys() method, then does:  for k in E: D[k] = E[k]
    #     If E is present and lacks a .keys() method, then does:  for k, v in E: D[k] = v
    #     In either case, this is followed by: for k in F:  D[k] = F[k]
    #     """
    #     pass
    #
[文档]    def values(self):
        """Return a value iterable.
        Returns:
            matx.Iterator
        Examples:
            >>> import matx
            >>> d = matx.Dict({'a': 1, 'b': 2})
            >>> it = d.values()
            >>> type(it)
            <class 'matx.runtime._container._iterator.Iterator'>
            >>> for v in it:
            ...     print(v)
            ...
            1
            2
        """
        return _ffi_api.Dict_ValueIter(self)