tsizeof.nim 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. discard """
  2. output: "OK"
  3. """
  4. type
  5. TMyEnum = enum
  6. tmOne, tmTwo, tmThree, tmFour
  7. TMyArray1 = array[3, uint8]
  8. TMyArray2 = array[1..3, int32]
  9. TMyArray3 = array[TMyEnum, float64]
  10. var failed = false
  11. const
  12. mysize1 = sizeof(TMyArray1)
  13. mysize2 = sizeof(TMyArray2)
  14. mysize3 = sizeof(TMyArray3)
  15. doAssert mysize1 == 3
  16. doAssert mysize2 == 12
  17. doAssert mysize3 == 32
  18. import macros, typetraits
  19. macro testSizeAlignOf(args: varargs[untyped]): untyped =
  20. result = newStmtList()
  21. for arg in args:
  22. result.add quote do:
  23. let
  24. c_size = c_sizeof(`arg`)
  25. nim_size = sizeof(`arg`)
  26. c_align = c_alignof(type(`arg`))
  27. nim_align = alignof(`arg`)
  28. if nim_size != c_size or nim_align != c_align:
  29. var msg = strAlign(`arg`.type.name & ": ")
  30. if nim_size != c_size:
  31. msg.add " size(got, expected): " & $nim_size & " != " & $c_size
  32. if nim_align != c_align:
  33. msg.add " align(get, expected): " & $nim_align & " != " & $c_align
  34. echo msg
  35. failed = true
  36. macro testOffsetOf(a, b: untyped): untyped =
  37. let typeName = newLit(a.repr)
  38. let member = newLit(b.repr)
  39. result = quote do:
  40. let
  41. c_offset = c_offsetof(`a`,`b`)
  42. nim_offset = offsetof(`a`,`b`)
  43. if c_offset != nim_offset:
  44. echo `typeName`, ".", `member`, " offsetError, C: ", c_offset, " nim: ", nim_offset
  45. failed = true
  46. proc strAlign(arg: string): string =
  47. const minLen = 22
  48. result = arg
  49. for i in 0 ..< minLen - arg.len:
  50. result &= ' '
  51. macro c_offsetof(a: typed, b: untyped): int32 =
  52. ## Buffet proof implementation that works on actual offsetof operator
  53. ## in the c backend. Assuming of course this implementation is
  54. ## correct.
  55. let bliteral =
  56. if b.kind == nnkStrLit:
  57. b
  58. else:
  59. newLit(repr(b))
  60. result = quote do:
  61. var res: int32
  62. {.emit: [res, " = offsetof(", `a`, ", ", `bliteral`, ");"] .}
  63. res
  64. macro c_sizeof(a: typed): int32 =
  65. ## Buffet proof implementation that works using the sizeof operator
  66. ## in the c backend. Assuming of course this implementation is
  67. ## correct.
  68. result = quote do:
  69. var res: int32
  70. {.emit: [res, " = sizeof(", `a`, ");"] .}
  71. res
  72. macro c_alignof(arg: untyped): untyped =
  73. ## Buffet proof implementation that works on actual alignment
  74. ## behavior measured at runtime.
  75. let typeSym = genSym(nskType, "AlignTestType"&arg.repr)
  76. result = quote do:
  77. type
  78. `typeSym` = object
  79. causeAlign: byte
  80. member: `arg`
  81. c_offsetof(`typeSym`, member)
  82. macro testAlign(arg:untyped):untyped =
  83. let prefix = newLit(arg.lineinfo & " alignof " & arg.repr & " ")
  84. result = quote do:
  85. let cAlign = c_alignof(`arg`)
  86. let nimAlign = alignof(`arg`)
  87. if cAlign != nimAlign:
  88. echo `prefix`, cAlign, " != ", nimAlign
  89. failed = true
  90. macro testSize(arg:untyped):untyped =
  91. let prefix = newLit(arg.lineinfo & " sizeof " & arg.repr & " ")
  92. result = quote do:
  93. let cSize = c_sizeof(`arg`)
  94. let nimSize = sizeof(`arg`)
  95. if cSize != nimSize:
  96. echo `prefix`, cSize, " != ", nimSize
  97. failed = true
  98. type
  99. MyEnum {.pure.} = enum
  100. ValueA
  101. ValueB
  102. ValueC
  103. OtherEnum {.pure, size: 8.} = enum
  104. ValueA
  105. ValueB
  106. Enum1 {.pure, size: 1.} = enum
  107. ValueA
  108. ValueB
  109. Enum2 {.pure, size: 2.} = enum
  110. ValueA
  111. ValueB
  112. Enum4 {.pure, size: 4.} = enum
  113. ValueA
  114. ValueB
  115. Enum8 {.pure, size: 8.} = enum
  116. ValueA
  117. ValueB
  118. template testinstance(body: untyped): untyped =
  119. block:
  120. {.pragma: objectconfig.}
  121. body
  122. block:
  123. {.pragma: objectconfig, packed.}
  124. body
  125. proc testPrimitiveTypes(): void =
  126. testAlign(pointer)
  127. testAlign(int)
  128. testAlign(uint)
  129. testAlign(int8)
  130. testAlign(int16)
  131. testAlign(int32)
  132. testAlign(int64)
  133. testAlign(uint8)
  134. testAlign(uint16)
  135. testAlign(uint32)
  136. testAlign(uint64)
  137. testAlign(float)
  138. testAlign(float32)
  139. testAlign(float64)
  140. testAlign(MyEnum)
  141. testAlign(OtherEnum)
  142. testAlign(Enum1)
  143. testAlign(Enum2)
  144. testAlign(Enum4)
  145. testAlign(Enum8)
  146. testPrimitiveTypes()
  147. testinstance:
  148. type
  149. EnumObjectA {.objectconfig.} = object
  150. a : Enum1
  151. b : Enum2
  152. c : Enum4
  153. d : Enum8
  154. EnumObjectB {.objectconfig.} = object
  155. a : Enum8
  156. b : Enum4
  157. c : Enum2
  158. d : Enum1
  159. TrivialType {.objectconfig.} = object
  160. x,y,z: int8
  161. SimpleAlignment {.objectconfig.} = object
  162. # behaves differently on 32bit Windows and 32bit Linux
  163. a,b: int8
  164. c: int64
  165. AlignAtEnd {.objectconfig.} = object
  166. a: int64
  167. b,c: int8
  168. SimpleBranch {.objectconfig.} = object
  169. case kind: MyEnum
  170. of MyEnum.ValueA:
  171. a: int16
  172. of MyEnum.ValueB:
  173. b: int32
  174. of MyEnum.ValueC:
  175. c: int64
  176. PaddingBeforeBranchA {.objectconfig.} = object
  177. cause: int8
  178. case kind: MyEnum
  179. of MyEnum.ValueA:
  180. a: int16
  181. of MyEnum.ValueB:
  182. b: int32
  183. of MyEnum.ValueC:
  184. c: int64
  185. PaddingBeforeBranchB {.objectconfig.} = object
  186. cause: int8
  187. case kind: MyEnum
  188. of MyEnum.ValueA:
  189. a: int8
  190. of MyEnum.ValueB:
  191. b: int16
  192. of MyEnum.ValueC:
  193. c: int32
  194. PaddingAfterBranch {.objectconfig.} = object
  195. case kind: MyEnum
  196. of MyEnum.ValueA:
  197. a: int8
  198. of MyEnum.ValueB:
  199. b: int16
  200. of MyEnum.ValueC:
  201. c: int32
  202. cause: int64
  203. RecursiveStuff {.objectconfig.} = object
  204. case kind: MyEnum # packedOffset: 0
  205. of MyEnum.ValueA: # packedOffset:
  206. a: int16 # packedOffset: 1
  207. of MyEnum.ValueB: # packedOffset:
  208. b: int32 # packedOffset: 1
  209. of MyEnum.ValueC: # packedOffset:
  210. case kind2: MyEnum # packedOffset: 1
  211. of MyEnum.ValueA: # packedOffset:
  212. ca1: int8
  213. ca2: int32
  214. of MyEnum.ValueB: # packedOffset:
  215. cb: int32 # packedOffset: 2
  216. of MyEnum.ValueC: # packedOffset:
  217. cc: int64 # packedOffset: 2
  218. d1: int8
  219. d2: int64
  220. Foobar {.objectconfig.} = object
  221. case kind: OtherEnum
  222. of OtherEnum.ValueA:
  223. a: uint8
  224. of OtherEnum.ValueB:
  225. b: int8
  226. c: int8
  227. Bazing {.objectconfig.} = object of RootObj
  228. a: int64
  229. # TODO test on 32 bit system
  230. # only there the object header is smaller than the first member
  231. InheritanceA {.objectconfig.} = object of RootObj
  232. a: char
  233. InheritanceB {.objectconfig.} = object of InheritanceA
  234. b: char
  235. InheritanceC {.objectconfig.} = object of InheritanceB
  236. c: char
  237. #Float128Test = object
  238. # a: byte
  239. # b: float128
  240. #Bazang = object of RootObj
  241. # a: float128
  242. const trivialSize = sizeof(TrivialType) # needs to be able to evaluate at compile time
  243. proc main(): void =
  244. var t : TrivialType
  245. var a : SimpleAlignment
  246. var b : AlignAtEnd
  247. var c : SimpleBranch
  248. var d : PaddingBeforeBranchA
  249. var e : PaddingBeforeBranchB
  250. var f : PaddingAfterBranch
  251. var g : RecursiveStuff
  252. var ro : RootObj
  253. var
  254. e1: Enum1
  255. e2: Enum2
  256. e4: Enum4
  257. e8: Enum8
  258. var
  259. eoa: EnumObjectA
  260. eob: EnumObjectB
  261. testAlign(SimpleAlignment)
  262. testSizeAlignOf(t,a,b,c,d,e,f,g,ro, e1, e2, e4, e8, eoa, eob)
  263. when not defined(cpp):
  264. type
  265. WithBitsize {.objectconfig.} = object
  266. bitfieldA {.bitsize: 16.}: uint32
  267. bitfieldB {.bitsize: 16.}: uint32
  268. var wbs: WithBitsize
  269. testSize(wbs)
  270. testOffsetOf(TrivialType, x)
  271. testOffsetOf(TrivialType, y)
  272. testOffsetOf(TrivialType, z)
  273. testOffsetOf(SimpleAlignment, a)
  274. testOffsetOf(SimpleAlignment, b)
  275. testOffsetOf(SimpleAlignment, c)
  276. testOffsetOf(AlignAtEnd, a)
  277. testOffsetOf(AlignAtEnd, b)
  278. testOffsetOf(AlignAtEnd, c)
  279. testOffsetOf(SimpleBranch, a)
  280. testOffsetOf(SimpleBranch, b)
  281. testOffsetOf(SimpleBranch, c)
  282. testOffsetOf(PaddingBeforeBranchA, cause)
  283. testOffsetOf(PaddingBeforeBranchA, a)
  284. testOffsetOf(PaddingBeforeBranchB, cause)
  285. testOffsetOf(PaddingBeforeBranchB, a)
  286. testOffsetOf(PaddingAfterBranch, a)
  287. testOffsetOf(PaddingAfterBranch, cause)
  288. testOffsetOf(Foobar, c)
  289. when not defined(cpp):
  290. testOffsetOf(Bazing, a)
  291. testOffsetOf(InheritanceA, a)
  292. testOffsetOf(InheritanceB, b)
  293. testOffsetOf(InheritanceC, c)
  294. testOffsetOf(EnumObjectA, a)
  295. testOffsetOf(EnumObjectA, b)
  296. testOffsetOf(EnumObjectA, c)
  297. testOffsetOf(EnumObjectA, d)
  298. testOffsetOf(EnumObjectB, a)
  299. testOffsetOf(EnumObjectB, b)
  300. testOffsetOf(EnumObjectB, c)
  301. testOffsetOf(EnumObjectB, d)
  302. testOffsetOf(RecursiveStuff, kind)
  303. testOffsetOf(RecursiveStuff, a)
  304. testOffsetOf(RecursiveStuff, b)
  305. testOffsetOf(RecursiveStuff, kind2)
  306. testOffsetOf(RecursiveStuff, ca1)
  307. testOffsetOf(RecursiveStuff, ca2)
  308. testOffsetOf(RecursiveStuff, cb)
  309. testOffsetOf(RecursiveStuff, cc)
  310. testOffsetOf(RecursiveStuff, d1)
  311. testOffsetOf(RecursiveStuff, d2)
  312. main()
  313. {.emit: """/*TYPESECTION*/
  314. typedef struct{
  315. float a; float b;
  316. } Foo;
  317. """.}
  318. type
  319. Foo {.importc.} = object
  320. Bar = object
  321. b: byte
  322. foo: Foo
  323. assert sizeof(Bar) == 12
  324. # bug #10082
  325. type
  326. A = int8 # change to int16 and get sizeof(C)==6
  327. B = int16
  328. C = object {.packed.}
  329. d {.bitsize: 1.}: A
  330. e {.bitsize: 7.}: A
  331. f {.bitsize: 16.}: B
  332. assert sizeof(C) == 3
  333. if failed:
  334. quit("FAIL")
  335. else:
  336. echo "OK"