def test_ffi_new_allocator_2(self): ffi = FFI(backend=self.Backend()) seen = [] def myalloc(size): seen.append(size) return ffi.new("char[]", b"X" * size) def myfree(raw): seen.append(raw) alloc1 = ffi.new_allocator(myalloc, myfree) alloc2 = ffi.new_allocator(alloc=myalloc, free=myfree, should_clear_after_alloc=False) p1 = alloc1("int[10]") p2 = alloc2("int[]", 10) assert seen == [40, 40] assert ffi.typeof(p1) == ffi.typeof("int[10]") assert ffi.sizeof(p1) == 40 assert ffi.typeof(p2) == ffi.typeof("int[]") assert ffi.sizeof(p2) == 40 assert p1[5] == 0 assert p2[6] == ord('X') * 0x01010101 raw1 = ffi.cast("char *", p1) raw2 = ffi.cast("char *", p2) del p1, p2 retries = 0 while len(seen) != 4: retries += 1 assert retries <= 5 import gc; gc.collect() assert seen == [40, 40, raw1, raw2] assert repr(seen[2]) == "<cdata 'char[]' owning 41 bytes>" assert repr(seen[3]) == "<cdata 'char[]' owning 41 bytes>"
def test_address_of_global_var(): ffi = FFI() ffi.cdef(""" long bottom, bottoms[2]; long FetchRectBottom(void); long FetchRectBottoms1(void); #define FOOBAR 42 """) lib = verify(ffi, "test_address_of_global_var", """ long bottom, bottoms[2]; long FetchRectBottom(void) { return bottom; } long FetchRectBottoms1(void) { return bottoms[1]; } #define FOOBAR 42 """) lib.bottom = 300 assert lib.FetchRectBottom() == 300 lib.bottom += 1 assert lib.FetchRectBottom() == 301 lib.bottoms[1] = 500 assert lib.FetchRectBottoms1() == 500 lib.bottoms[1] += 2 assert lib.FetchRectBottoms1() == 502 # p = ffi.addressof(lib, 'bottom') assert ffi.typeof(p) == ffi.typeof("long *") assert p[0] == 301 p[0] += 1 assert lib.FetchRectBottom() == 302 p = ffi.addressof(lib, 'bottoms') assert ffi.typeof(p) == ffi.typeof("long(*)[2]") assert p[0] == lib.bottoms # py.test.raises(AttributeError, ffi.addressof, lib, 'unknown_var') py.test.raises(AttributeError, ffi.addressof, lib, "FOOBAR")
def test_from_buffer(self): import array ffi = FFI() a = array.array('H', [10000, 20000, 30000]) c = ffi.from_buffer(a) assert ffi.typeof(c) is ffi.typeof("char[]") ffi.cast("unsigned short *", c)[1] += 500 assert list(a) == [10000, 20500, 30000]
def test_new_handle(self): ffi = FFI(backend=self.Backend()) o = [2, 3, 4] p = ffi.new_handle(o) assert ffi.typeof(p) == ffi.typeof("void *") assert ffi.from_handle(p) is o assert ffi.from_handle(ffi.cast("char *", p)) is o py.test.raises(RuntimeError, ffi.from_handle, ffi.NULL)
def test_global_var_array_3(): ffi = FFI() ffi.cdef("int a[][...];") lib = verify(ffi, 'test_global_var_array_3', 'int a[10][8];') lib.a[9][7] = 123456 assert lib.a[9][7] == 123456 py.test.raises(IndexError, 'lib.a[0][8]') assert ffi.typeof(lib.a) == ffi.typeof("int(*)[8]") assert ffi.typeof(lib.a[0]) == ffi.typeof("int[8]")
def test_incomplete_struct_as_result(): ffi = FFI() ffi.cdef("struct foo_s { int x; ...; }; struct foo_s f(int);") lib = verify(ffi, "test_incomplete_struct_as_result", "struct foo_s { int a, x, z; };\n" "struct foo_s f(int x) { struct foo_s r; r.x = x * 2; return r; }") s = lib.f(21) assert s.x == 42 assert ffi.typeof(lib.f) == ffi.typeof("struct foo_s(*)(int)")
def test_struct_array_no_length(self): ffi = FFI() ffi.cdef("struct foo_s { int x; int a[]; };") p = ffi.new("struct foo_s *", [100, [200, 300, 400]]) assert p.x == 100 assert ffi.typeof(p.a) is ffi.typeof("int *") # no length available assert p.a[0] == 200 assert p.a[1] == 300 assert p.a[2] == 400
def test_include_1(): ffi1 = FFI() ffi1.cdef("typedef double foo_t;") verify(ffi1, "test_include_1_parent", "typedef double foo_t;") ffi = FFI() ffi.include(ffi1) ffi.cdef("foo_t ff1(foo_t);") lib = verify(ffi, "test_include_1", "double ff1(double x) { return 42.5; }") assert lib.ff1(0) == 42.5 assert ffi1.typeof("foo_t") is ffi.typeof("foo_t") is ffi.typeof("double")
def test_function_has_a_c_type(self): ffi = FFI(backend=self.Backend()) ffi.cdef(""" int puts(const char *); """) ffi.C = ffi.dlopen(None) fptr = ffi.C.puts assert ffi.typeof(fptr) == ffi.typeof("int(*)(const char*)") if self.Backend is CTypesBackend: assert repr(fptr).startswith("<cdata 'int puts(char *)' 0x")
def test_stdcall_only_on_windows(self): ffi = FFI(backend=self.Backend()) ffi.cdef("double __stdcall sin(double x);") # stdcall ignored m = ffi.dlopen(lib_m) if (sys.platform == 'win32' and sys.maxsize < 2**32 and self.Backend is not CTypesBackend): assert "double(__stdcall *)(double)" in str(ffi.typeof(m.sin)) else: assert "double(*)(double)" in str(ffi.typeof(m.sin)) x = m.sin(1.23) assert x == math.sin(1.23)
def test_issue200(): ffi = FFI() ffi.cdef(""" typedef void (function_t)(void*); void function(void *); """) lib = verify(ffi, 'test_issue200', """ static void function(void *p) { (void)p; } """) ffi.typeof('function_t*') lib.function(ffi.NULL)
def test_cannot_instantiate_manually(self): ffi = FFI() ct = type(ffi.typeof("void *")) py.test.raises(TypeError, ct) py.test.raises(TypeError, ct, ffi.NULL) for cd in [type(ffi.cast("void *", 0)), type(ffi.new("char[]", 3)), type(ffi.gc(ffi.NULL, lambda x: None))]: py.test.raises(TypeError, cd) py.test.raises(TypeError, cd, ffi.NULL) py.test.raises(TypeError, cd, ffi.typeof("void *"))
def test_struct_array_guess_length_3(): ffi = FFI() ffi.cdef("struct foo_s { int a[][...]; };") lib = verify(ffi, 'test_struct_array_guess_length_3', "struct foo_s { int x; int a[5][7]; int y; };") assert ffi.sizeof('struct foo_s') == 37 * ffi.sizeof('int') s = ffi.new("struct foo_s *") assert ffi.typeof(s.a) == ffi.typeof("int(*)[7]") assert s.a[4][6] == 0 py.test.raises(IndexError, 's.a[4][7]') assert ffi.typeof(s.a[0]) == ffi.typeof("int[7]")
def test_incomplete_struct_as_arg(): ffi = FFI() ffi.cdef("struct foo_s { int x; ...; }; int f(int, struct foo_s);") lib = verify(ffi, "test_incomplete_struct_as_arg", "struct foo_s { int a, x, z; };\n" "int f(int b, struct foo_s s) { return s.x * b; }") s = ffi.new("struct foo_s *", [21]) assert s.x == 21 assert ffi.sizeof(s[0]) == 12 assert ffi.offsetof(ffi.typeof(s), 'x') == 4 assert lib.f(2, s[0]) == 42 assert ffi.typeof(lib.f) == ffi.typeof("int(*)(int, struct foo_s)")
def test_ffi_new_allocator_3(self): ffi = FFI(backend=self.Backend()) seen = [] def myalloc(size): seen.append(size) return ffi.new("char[]", b"X" * size) alloc1 = ffi.new_allocator(myalloc) # no 'free' p1 = alloc1("int[10]") assert seen == [40] assert ffi.typeof(p1) == ffi.typeof("int[10]") assert ffi.sizeof(p1) == 40 assert p1[5] == 0
def test_name_of_unnamed_struct(): ffi = FFI() ffi.cdef("typedef struct { int x; } foo_t;\n" "typedef struct { int y; } *bar_p;\n" "typedef struct { int y; } **baz_pp;\n") verify(ffi, "test_name_of_unnamed_struct", "typedef struct { int x; } foo_t;\n" "typedef struct { int y; } *bar_p;\n" "typedef struct { int y; } **baz_pp;\n") assert repr(ffi.typeof("foo_t")) == "<ctype 'foo_t'>" assert repr(ffi.typeof("bar_p")) == "<ctype 'struct $1 *'>" assert repr(ffi.typeof("baz_pp")) == "<ctype 'struct $2 * *'>"
def test_explicit_cdecl_stdcall(self): if sys.platform != 'win32': py.test.skip("Windows-only test") if self.Backend is CTypesBackend: py.test.skip("not with the ctypes backend") win64 = (sys.maxsize > 2**32) # ffi = FFI(backend=self.Backend()) ffi.cdef(""" BOOL QueryPerformanceFrequency(LONGLONG *lpFrequency); """) m = ffi.dlopen("Kernel32.dll") tp = ffi.typeof(m.QueryPerformanceFrequency) assert str(tp) == "<ctype 'int(*)(long long *)'>" # ffi = FFI(backend=self.Backend()) ffi.cdef(""" BOOL __cdecl QueryPerformanceFrequency(LONGLONG *lpFrequency); """) m = ffi.dlopen("Kernel32.dll") tpc = ffi.typeof(m.QueryPerformanceFrequency) assert tpc is tp # ffi = FFI(backend=self.Backend()) ffi.cdef(""" BOOL WINAPI QueryPerformanceFrequency(LONGLONG *lpFrequency); """) m = ffi.dlopen("Kernel32.dll") tps = ffi.typeof(m.QueryPerformanceFrequency) if win64: assert tps is tpc else: assert tps is not tpc assert str(tps) == "<ctype 'int(__stdcall *)(long long *)'>" # ffi = FFI(backend=self.Backend()) ffi.cdef("typedef int (__cdecl *fnc_t)(int);") ffi.cdef("typedef int (__stdcall *fns_t)(int);") tpc = ffi.typeof("fnc_t") tps = ffi.typeof("fns_t") assert str(tpc) == "<ctype 'int(*)(int)'>" if win64: assert tps is tpc else: assert str(tps) == "<ctype 'int(__stdcall *)(int)'>" # fnc = ffi.cast("fnc_t", 0) fns = ffi.cast("fns_t", 0) ffi.new("fnc_t[]", [fnc]) if not win64: py.test.raises(TypeError, ffi.new, "fnc_t[]", [fns]) py.test.raises(TypeError, ffi.new, "fns_t[]", [fnc]) ffi.new("fns_t[]", [fns])
def test_include_3(): ffi1 = FFI() ffi1.cdef("typedef short sshort_t;") verify(ffi1, "test_include_3_parent", "typedef short sshort_t;") ffi = FFI() ffi.include(ffi1) ffi.cdef("sshort_t ff3(sshort_t);") lib = verify(ffi, "test_include_3", "typedef short sshort_t; //usually from a #include\n" "sshort_t ff3(sshort_t x) { return x + 42; }") assert lib.ff3(10) == 52 assert ffi.typeof(ffi.cast("sshort_t", 42)) is ffi.typeof("short") assert ffi1.typeof("sshort_t") is ffi.typeof("sshort_t")
def test_address_of_function_with_struct(): ffi = FFI() ffi.cdef("struct foo_s { int x; }; long myfunc(struct foo_s);") lib = verify(ffi, "test_addressof_function_with_struct", """ struct foo_s { int x; }; char myfunc(struct foo_s input) { return (char)(input.x + 42); } """) s = ffi.new("struct foo_s *", [5])[0] assert lib.myfunc(s) == 47 assert not isinstance(lib.myfunc, ffi.CData) assert ffi.typeof(lib.myfunc) == ffi.typeof("long(*)(struct foo_s)") addr = ffi.addressof(lib, 'myfunc') assert addr(s) == 47 assert isinstance(addr, ffi.CData) assert ffi.typeof(addr) == ffi.typeof("long(*)(struct foo_s)")
def test_address_of_function(): ffi = FFI() ffi.cdef("long myfunc(long x);") lib = verify(ffi, "test_addressof_function", """ char myfunc(char x) { return (char)(x + 42); } """) assert lib.myfunc(5) == 47 assert lib.myfunc(0xABC05) == 47 assert not isinstance(lib.myfunc, ffi.CData) assert ffi.typeof(lib.myfunc) == ffi.typeof("long(*)(long)") addr = ffi.addressof(lib, 'myfunc') assert addr(5) == 47 assert addr(0xABC05) == 47 assert isinstance(addr, ffi.CData) assert ffi.typeof(addr) == ffi.typeof("long(*)(long)")
def test_verify_enum(): ffi = FFI() ffi.cdef("""enum e1 { B1, A1, ... }; enum e2 { B2, A2, ... };""") lib = verify(ffi, 'test_verify_enum', "enum e1 { A1, B1, C1=%d };" % sys.maxsize + "enum e2 { A2, B2, C2 };") ffi.typeof("enum e1") ffi.typeof("enum e2") assert lib.A1 == 0 assert lib.B1 == 1 assert lib.A2 == 0 assert lib.B2 == 1 assert ffi.sizeof("enum e1") == ffi.sizeof("long") assert ffi.sizeof("enum e2") == ffi.sizeof("int") assert repr(ffi.cast("enum e1", 0)) == "<cdata 'enum e1' 0: A1>"
def test_verify_enum(): ffi = FFI() ffi.cdef("""enum e1 { B1, A1, ... }; enum e2 { B2, A2, ... };""") lib = verify( ffi, 'test_verify_enum', "enum e1 { A1, B1, C1=%d };" % sys.maxsize + "enum e2 { A2, B2, C2 };") ffi.typeof("enum e1") ffi.typeof("enum e2") assert lib.A1 == 0 assert lib.B1 == 1 assert lib.A2 == 0 assert lib.B2 == 1 assert ffi.sizeof("enum e1") == ffi.sizeof("long") assert ffi.sizeof("enum e2") == ffi.sizeof("int") assert repr(ffi.cast("enum e1", 0)) == "<cdata 'enum e1' 0: A1>"
def test_include_4(): ffi1 = FFI() ffi1.cdef("typedef struct { int x; } mystruct_t;") verify(ffi1, "test_include_4_parent", "typedef struct { int x; } mystruct_t;") ffi = FFI() ffi.include(ffi1) ffi.cdef("mystruct_t *ff4(mystruct_t *);") lib = verify(ffi, "test_include_4", "typedef struct {int x; } mystruct_t; //usually from a #include\n" "mystruct_t *ff4(mystruct_t *p) { p->x += 42; return p; }") p = ffi.new("mystruct_t *", [10]) q = lib.ff4(p) assert q == p assert p.x == 52 assert ffi1.typeof("mystruct_t") is ffi.typeof("mystruct_t")
def as_numeric_np_array(ffi: FFI, ptr: CffiData, size: int, shallow: bool = False) -> np.ndarray: """Convert if possible a cffi pointer to a C data array, into a numpy array. Args: ffi (FFI): FFI instance wrapping the native compilation module owning the native memory ptr (CffiData): cffi pointer (FFI.CData) size (int): array size shallow (bool): If true the array points directly to native data array. Defaults to False. Raises: RuntimeError: conversion is not supported Returns: np.ndarray: converted data """ t = ffi.typeof(ptr).cname # e.g. 'double *' if t not in _c2dtype: raise RuntimeError("Cannot create an array for element type: %s" % t) dtype = _c2dtype[t] buffer_size = size * dtype.itemsize res = np.frombuffer(ffi.buffer(ptr, buffer_size), dtype) if shallow: return res else: return res.copy()
def test_include_2(): ffi1 = FFI() ffi1.cdef("struct foo_s { int x, y; };") verify(ffi1, "test_include_2_parent", "struct foo_s { int x, y; };") ffi = FFI() ffi.include(ffi1) ffi.cdef("struct foo_s *ff2(struct foo_s *);") lib = verify(ffi, "test_include_2", "struct foo_s { int x, y; }; //usually from a #include\n" "struct foo_s *ff2(struct foo_s *p) { p->y++; return p; }") p = ffi.new("struct foo_s *") p.y = 41 q = lib.ff2(p) assert q == p assert p.y == 42 assert ffi1.typeof("struct foo_s") is ffi.typeof("struct foo_s")
def test_incomplete_struct_as_both(): ffi = FFI() ffi.cdef("struct foo_s { int x; ...; }; struct bar_s { int y; ...; };\n" "struct foo_s f(int, struct bar_s);") lib = verify(ffi, "test_incomplete_struct_as_both", "struct foo_s { int a, x, z; };\n" "struct bar_s { int b, c, y, d; };\n" "struct foo_s f(int x, struct bar_s b) {\n" " struct foo_s r; r.x = x * b.y; return r;\n" "}") b = ffi.new("struct bar_s *", [7]) s = lib.f(6, b[0]) assert s.x == 42 assert ffi.typeof(lib.f) == ffi.typeof( "struct foo_s(*)(int, struct bar_s)") s = lib.f(14, {'y': -3}) assert s.x == -42
def test_addressof_lib(self): if self.module is None: py.test.skip("fix the auto-generation of the tiny test lib") if self.Backend is CTypesBackend: py.test.skip("not implemented with the ctypes backend") ffi = FFI(backend=self.Backend()) ffi.cdef("long left; int test_getting_errno(void);") lib = ffi.dlopen(self.module) lib.left = 123456 p = ffi.addressof(lib, "left") assert ffi.typeof(p) == ffi.typeof("long *") assert p[0] == 123456 p[0] += 1 assert lib.left == 123457 pfn = ffi.addressof(lib, "test_getting_errno") assert ffi.typeof(pfn) == ffi.typeof("int(*)(void)") assert pfn == lib.test_getting_errno
def test_math_sin_type(): ffi = FFI() ffi.cdef("double sin(double);") lib = verify(ffi, 'test_math_sin_type', '#include <math.h>') # 'lib.sin' is typed as a <built-in method> object on lib assert ffi.typeof(lib.sin).cname == "double(*)(double)" # 'x' is another <built-in method> object on lib, made very indirectly x = type(lib).__dir__.__get__(lib) py.test.raises(TypeError, ffi.typeof, x)
def check(self, source, expected_ofs_y, expected_align, expected_size): # NOTE: 'expected_*' is the numbers expected from GCC. # The numbers expected from MSVC are not explicitly written # in this file, and will just be taken from the compiler. ffi = FFI() ffi.cdef("struct s1 { %s };" % source) ctype = ffi.typeof("struct s1") # verify the information with gcc ffi1 = FFI() ffi1.cdef( """ static const int Gofs_y, Galign, Gsize; struct s1 *try_with_value(int fieldnum, long long value); """ ) fnames = [name for name, cfield in ctype.fields if name and cfield.bitsize > 0] setters = ["case %d: s.%s = value; break;" % iname for iname in enumerate(fnames)] lib = ffi1.verify( """ struct s1 { %s }; struct sa { char a; struct s1 b; }; #define Gofs_y offsetof(struct s1, y) #define Galign offsetof(struct sa, b) #define Gsize sizeof(struct s1) struct s1 *try_with_value(int fieldnum, long long value) { static struct s1 s; memset(&s, 0, sizeof(s)); switch (fieldnum) { %s } return &s; } """ % (source, " ".join(setters)) ) if sys.platform == "win32": expected_ofs_y = lib.Gofs_y expected_align = lib.Galign expected_size = lib.Gsize else: assert (lib.Gofs_y, lib.Galign, lib.Gsize) == (expected_ofs_y, expected_align, expected_size) # the real test follows assert ffi.offsetof("struct s1", "y") == expected_ofs_y assert ffi.alignof("struct s1") == expected_align assert ffi.sizeof("struct s1") == expected_size # compare the actual storage of the two for name, cfield in ctype.fields: if cfield.bitsize < 0 or not name: continue if int(ffi.cast(cfield.type, -1)) == -1: # signed min_value = -(1 << (cfield.bitsize - 1)) max_value = (1 << (cfield.bitsize - 1)) - 1 else: min_value = 0 max_value = (1 << cfield.bitsize) - 1 for t in [1, 2, 4, 8, 16, 128, 2813, 89728, 981729, -1, -2, -4, -8, -16, -128, -2813, -89728, -981729]: if min_value <= t <= max_value: self._fieldcheck(ffi, lib, fnames, name, t)
def check(self, source, expected_ofs_y, expected_align, expected_size): # NOTE: 'expected_*' is the numbers expected from GCC. # The numbers expected from MSVC are not explicitly written # in this file, and will just be taken from the compiler. ffi = FFI() ffi.cdef("struct s1 { %s };" % source) ctype = ffi.typeof("struct s1") # verify the information with gcc ffi1 = FFI() ffi1.cdef(""" static const int Gofs_y, Galign, Gsize; struct s1 *try_with_value(int fieldnum, long long value); """) fnames = [name for name, cfield in ctype.fields if name and cfield.bitsize > 0] setters = ['case %d: s.%s = value; break;' % iname for iname in enumerate(fnames)] lib = ffi1.verify(""" struct s1 { %s }; struct sa { char a; struct s1 b; }; #define Gofs_y offsetof(struct s1, y) #define Galign offsetof(struct sa, b) #define Gsize sizeof(struct s1) struct s1 *try_with_value(int fieldnum, long long value) { static struct s1 s; memset(&s, 0, sizeof(s)); switch (fieldnum) { %s } return &s; } """ % (source, ' '.join(setters))) if sys.platform == 'win32': expected_ofs_y = lib.Gofs_y expected_align = lib.Galign expected_size = lib.Gsize else: assert (lib.Gofs_y, lib.Galign, lib.Gsize) == ( expected_ofs_y, expected_align, expected_size) # the real test follows assert ffi.offsetof("struct s1", "y") == expected_ofs_y assert ffi.alignof("struct s1") == expected_align assert ffi.sizeof("struct s1") == expected_size # compare the actual storage of the two for name, cfield in ctype.fields: if cfield.bitsize < 0 or not name: continue if int(ffi.cast(cfield.type, -1)) == -1: # signed min_value = -(1 << (cfield.bitsize-1)) max_value = (1 << (cfield.bitsize-1)) - 1 else: min_value = 0 max_value = (1 << cfield.bitsize) - 1 for t in [1, 2, 4, 8, 16, 128, 2813, 89728, 981729, -1,-2,-4,-8,-16,-128,-2813,-89728,-981729]: if min_value <= t <= max_value: self._fieldcheck(ffi, lib, fnames, name, t)
def test_typedef(): ffi = FFI(backend=FakeBackend()) ffi.cdef(""" typedef unsigned int UInt; typedef UInt UIntReally; UInt foo(void); """) C = ffi.dlopen(None) assert str(ffi.typeof("UIntReally")) == '<unsigned int>' assert C.foo.BType == '<func (), <unsigned int>, False>'
def test_introspect_typedef(self): ffi = FFI() ffi.cdef("typedef int foo_t;") assert ffi.list_types() == (['foo_t'], [], []) assert ffi.typeof('foo_t').kind == 'primitive' assert ffi.typeof('foo_t').cname == 'int' # ffi.cdef("typedef signed char a_t, c_t, g_t, b_t;") assert ffi.list_types() == (['a_t', 'b_t', 'c_t', 'foo_t', 'g_t'], [], [])
def test_struct_array_no_length(self): ffi = FFI() ffi.cdef("struct foo_s { int x; int a[]; };") p = ffi.new("struct foo_s *", [100, [200, 300, 400]]) assert p.x == 100 assert ffi.typeof(p.a) is ffi.typeof("int[]") assert len(p.a) == 3 # length recorded assert p.a[0] == 200 assert p.a[1] == 300 assert p.a[2] == 400 assert list(p.a) == [200, 300, 400] q = ffi.cast("struct foo_s *", p) assert q.x == 100 assert ffi.typeof(q.a) is ffi.typeof("int *") # no length recorded py.test.raises(TypeError, len, q.a) assert q.a[0] == 200 assert q.a[1] == 300 assert q.a[2] == 400 py.test.raises(TypeError, list, q.a)
def test_typedef_more_complex(): ffi = FFI(backend=FakeBackend()) ffi.cdef(""" typedef struct { int a, b; } foo_t, *foo_p; int foo(foo_p[]); """) C = ffi.dlopen(None) assert str(ffi.typeof("foo_t")) == '<int>a, <int>b' assert str(ffi.typeof("foo_p")) == '<pointer to <int>a, <int>b>' assert C.foo.BType == ('<func (<pointer to <pointer to ' '<int>a, <int>b>>), <int>, False>')