array.cpp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419
  1. /*
  2. * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
  3. */
  4. #if __GNUC__
  5. # pragma GCC diagnostic ignored "-Wfloat-equal"
  6. # pragma GCC diagnostic ignored "-Wdouble-promotion"
  7. #endif
  8. #include <gtest/gtest.h>
  9. #include <uavcan/marshal/types.hpp>
  10. #include <uavcan/transport/transfer_buffer.hpp>
  11. using uavcan::Array;
  12. using uavcan::ArrayModeDynamic;
  13. using uavcan::ArrayModeStatic;
  14. using uavcan::IntegerSpec;
  15. using uavcan::FloatSpec;
  16. using uavcan::SignednessSigned;
  17. using uavcan::SignednessUnsigned;
  18. using uavcan::CastModeSaturate;
  19. using uavcan::CastModeTruncate;
  20. struct CustomType
  21. {
  22. typedef uavcan::IntegerSpec<8, uavcan::SignednessSigned, uavcan::CastModeTruncate> A;
  23. typedef uavcan::FloatSpec<16, uavcan::CastModeSaturate> B;
  24. // Dynamic array of max len 5 --> 3 bits for len, 5 bits for data --> 1 byte max len
  25. typedef uavcan::Array<uavcan::IntegerSpec<1, uavcan::SignednessUnsigned, uavcan::CastModeSaturate>,
  26. uavcan::ArrayModeDynamic, 5> C;
  27. enum { MinBitLen = A::MinBitLen + B::MinBitLen + C::MinBitLen };
  28. enum { MaxBitLen = A::MaxBitLen + B::MaxBitLen + C::MaxBitLen };
  29. typename uavcan::StorageType<A>::Type a;
  30. typename uavcan::StorageType<B>::Type b;
  31. typename uavcan::StorageType<C>::Type c;
  32. CustomType()
  33. : a()
  34. , b()
  35. , c()
  36. { }
  37. bool operator==(const CustomType& rhs) const
  38. {
  39. return a == rhs.a &&
  40. uavcan::areFloatsExactlyEqual(b, rhs.b) &&
  41. c == rhs.c;
  42. }
  43. static int encode(const CustomType& obj, uavcan::ScalarCodec& codec,
  44. uavcan::TailArrayOptimizationMode tao_mode = uavcan::TailArrayOptEnabled)
  45. {
  46. int res = 0;
  47. res = A::encode(obj.a, codec, uavcan::TailArrayOptDisabled);
  48. if (res <= 0)
  49. {
  50. return res;
  51. }
  52. res = B::encode(obj.b, codec, uavcan::TailArrayOptDisabled);
  53. if (res <= 0)
  54. {
  55. return res;
  56. }
  57. res = C::encode(obj.c, codec, tao_mode);
  58. if (res <= 0)
  59. {
  60. return res;
  61. }
  62. return 1;
  63. }
  64. static int decode(CustomType& obj, uavcan::ScalarCodec& codec,
  65. uavcan::TailArrayOptimizationMode tao_mode = uavcan::TailArrayOptEnabled)
  66. {
  67. int res = 0;
  68. res = A::decode(obj.a, codec, uavcan::TailArrayOptDisabled);
  69. if (res <= 0)
  70. {
  71. return res;
  72. }
  73. res = B::decode(obj.b, codec, uavcan::TailArrayOptDisabled);
  74. if (res <= 0)
  75. {
  76. return res;
  77. }
  78. res = C::decode(obj.c, codec, tao_mode);
  79. if (res <= 0)
  80. {
  81. return res;
  82. }
  83. return 1;
  84. }
  85. };
  86. TEST(Array, Basic)
  87. {
  88. typedef Array<IntegerSpec<8, SignednessSigned, CastModeTruncate>, ArrayModeStatic, 4> A1;
  89. typedef Array<FloatSpec<16, CastModeSaturate>, ArrayModeStatic, 2> A2;
  90. typedef Array<CustomType, ArrayModeStatic, 2> A3;
  91. A1 a1;
  92. A2 a2;
  93. A3 a3;
  94. ASSERT_EQ(1, A3::ValueType::C::RawValueType::BitLen);
  95. ASSERT_EQ(8 * 4, A1::MaxBitLen);
  96. ASSERT_EQ(16 * 2, A2::MaxBitLen);
  97. ASSERT_EQ((8 + 16 + 5 + 3) * 2, A3::MaxBitLen);
  98. /*
  99. * Zero initialization check
  100. */
  101. ASSERT_FALSE(a1.empty());
  102. for (A1::const_iterator it = a1.begin(); it != a1.end(); ++it)
  103. {
  104. ASSERT_EQ(0, *it);
  105. }
  106. ASSERT_FALSE(a2.empty());
  107. for (A2::const_iterator it = a2.begin(); it != a2.end(); ++it)
  108. {
  109. ASSERT_EQ(0, *it);
  110. }
  111. for (A3::const_iterator it = a3.begin(); it != a3.end(); ++it)
  112. {
  113. ASSERT_EQ(0, it->a);
  114. ASSERT_EQ(0, it->b);
  115. ASSERT_EQ(0, it->c.size());
  116. ASSERT_TRUE(it->c.empty());
  117. }
  118. /*
  119. * Modification with known values; array lengths are hard coded.
  120. */
  121. for (uint8_t i = 0; i < 4; i++)
  122. {
  123. a1.at(i) = int8_t(i);
  124. }
  125. for (uint8_t i = 0; i < 2; i++)
  126. {
  127. a2.at(i) = i;
  128. }
  129. for (uint8_t i = 0; i < 2; i++)
  130. {
  131. a3[i].a = int8_t(i);
  132. a3[i].b = i;
  133. for (uint8_t i2 = 0; i2 < 5; i2++)
  134. {
  135. a3[i].c.push_back(i2 & 1);
  136. }
  137. ASSERT_EQ(5, a3[i].c.size());
  138. ASSERT_FALSE(a3[i].c.empty());
  139. }
  140. /*
  141. * Representation check
  142. * Note that TAO in A3 is not possible because A3::C has less than one byte per item
  143. */
  144. uavcan::StaticTransferBuffer<16> buf;
  145. uavcan::BitStream bs_wr(buf);
  146. uavcan::ScalarCodec sc_wr(bs_wr);
  147. ASSERT_EQ(1, A1::encode(a1, sc_wr, uavcan::TailArrayOptDisabled));
  148. ASSERT_EQ(1, A2::encode(a2, sc_wr, uavcan::TailArrayOptDisabled));
  149. ASSERT_EQ(1, A3::encode(a3, sc_wr, uavcan::TailArrayOptEnabled));
  150. ASSERT_EQ(0, A3::encode(a3, sc_wr, uavcan::TailArrayOptEnabled)); // Out of buffer space
  151. static const std::string Reference =
  152. "00000000 00000001 00000010 00000011 " // A1 (0, 1, 2, 3)
  153. "00000000 00000000 00000000 00111100 " // A2 (0, 1)
  154. "00000000 00000000 00000000 10101010 " // A3[0] (0, 0, bool[5])
  155. "00000001 00000000 00111100 10101010"; // A3[1] (1, 1, bool[5])
  156. ASSERT_EQ(Reference, bs_wr.toString());
  157. /*
  158. * Read back
  159. */
  160. uavcan::BitStream bs_rd(buf);
  161. uavcan::ScalarCodec sc_rd(bs_rd);
  162. A1 a1_;
  163. A2 a2_;
  164. A3 a3_;
  165. ASSERT_EQ(1, A1::decode(a1_, sc_rd, uavcan::TailArrayOptDisabled));
  166. ASSERT_EQ(1, A2::decode(a2_, sc_rd, uavcan::TailArrayOptDisabled));
  167. ASSERT_EQ(1, A3::decode(a3_, sc_rd, uavcan::TailArrayOptEnabled));
  168. ASSERT_EQ(a1_, a1);
  169. ASSERT_EQ(a2_, a2);
  170. ASSERT_EQ(a3_, a3);
  171. for (uint8_t i = 0; i < 4; i++)
  172. {
  173. ASSERT_EQ(a1[i], a1_[i]);
  174. }
  175. for (uint8_t i = 0; i < 2; i++)
  176. {
  177. ASSERT_EQ(a2[i], a2_[i]);
  178. }
  179. for (uint8_t i = 0; i < 2; i++)
  180. {
  181. ASSERT_EQ(a3[i].a, a3_[i].a);
  182. ASSERT_EQ(a3[i].b, a3_[i].b);
  183. ASSERT_EQ(a3[i].c, a3_[i].c);
  184. }
  185. ASSERT_EQ(0, A3::decode(a3_, sc_rd, uavcan::TailArrayOptEnabled)); // Out of buffer space
  186. /*
  187. * STL compatibility
  188. */
  189. std::vector<int> v1;
  190. v1.push_back(0);
  191. v1.push_back(1);
  192. v1.push_back(2);
  193. v1.push_back(3);
  194. ASSERT_TRUE(a1 == v1);
  195. ASSERT_FALSE(a1 != v1);
  196. ASSERT_TRUE(v1 == a1);
  197. ASSERT_FALSE(v1 != a1);
  198. ASSERT_FALSE(a1 < v1);
  199. v1[0] = 9000;
  200. ASSERT_FALSE(a1 == v1);
  201. ASSERT_TRUE(a1 != v1);
  202. ASSERT_TRUE(a1 < v1);
  203. ASSERT_EQ(0, a1.front());
  204. ASSERT_EQ(3, a1.back());
  205. // Boolean vector
  206. std::vector<bool> v2;
  207. v2.push_back(false);
  208. v2.push_back(true);
  209. v2.push_back(false);
  210. v2.push_back(true);
  211. v2.push_back(false);
  212. ASSERT_TRUE(a3[0].c == v2);
  213. ASSERT_FALSE(a3[0].c == v1);
  214. ASSERT_FALSE(a3[0].c != v2);
  215. ASSERT_TRUE(a3[0].c != v1);
  216. v2[0] = true;
  217. ASSERT_TRUE(a3[0].c != v2);
  218. ASSERT_FALSE(a3[0].c == v2);
  219. }
  220. TEST(Array, Dynamic)
  221. {
  222. typedef Array<IntegerSpec<1, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 5> A;
  223. typedef Array<IntegerSpec<8, SignednessSigned, CastModeSaturate>, ArrayModeDynamic, 255> B;
  224. A a;
  225. B b;
  226. B b2;
  227. ASSERT_EQ(3 + 5, A::MaxBitLen);
  228. ASSERT_EQ(8 + 255 * 8, B::MaxBitLen);
  229. ASSERT_TRUE(a.empty());
  230. ASSERT_TRUE(b.empty());
  231. ASSERT_TRUE(b2.empty());
  232. {
  233. uavcan::StaticTransferBuffer<16> buf;
  234. uavcan::BitStream bs_wr(buf);
  235. uavcan::ScalarCodec sc_wr(bs_wr);
  236. ASSERT_EQ(1, A::encode(a, sc_wr, uavcan::TailArrayOptDisabled));
  237. ASSERT_EQ(1, B::encode(b, sc_wr, uavcan::TailArrayOptDisabled));
  238. ASSERT_EQ(1, B::encode(b2, sc_wr, uavcan::TailArrayOptEnabled));
  239. ASSERT_EQ("000" "00000 000" "00000", bs_wr.toString()); // Last array was optimized away completely
  240. uavcan::BitStream bs_rd(buf);
  241. uavcan::ScalarCodec sc_rd(bs_rd);
  242. ASSERT_EQ(1, A::decode(a, sc_rd, uavcan::TailArrayOptDisabled));
  243. ASSERT_EQ(1, B::decode(b, sc_rd, uavcan::TailArrayOptDisabled));
  244. ASSERT_EQ(1, B::decode(b2, sc_rd, uavcan::TailArrayOptEnabled));
  245. ASSERT_TRUE(a.empty());
  246. ASSERT_TRUE(b.empty());
  247. ASSERT_TRUE(b2.empty());
  248. }
  249. a.push_back(true);
  250. a.push_back(false);
  251. a.push_back(true);
  252. a.push_back(false);
  253. a.push_back(true);
  254. b.push_back(42);
  255. b.push_back(-42);
  256. b2.push_back(123);
  257. b2.push_back(72);
  258. {
  259. uavcan::StaticTransferBuffer<16> buf;
  260. uavcan::BitStream bs_wr(buf);
  261. uavcan::ScalarCodec sc_wr(bs_wr);
  262. ASSERT_EQ(1, A::encode(a, sc_wr, uavcan::TailArrayOptDisabled));
  263. ASSERT_EQ(1, B::encode(b, sc_wr, uavcan::TailArrayOptDisabled));
  264. ASSERT_EQ(1, B::encode(b2, sc_wr, uavcan::TailArrayOptEnabled)); // No length field
  265. // A B len B[0] B[1] B2[0] B2[1]
  266. ASSERT_EQ("10110101 00000010 00101010 11010110 01111011 01001000", bs_wr.toString());
  267. uavcan::BitStream bs_rd(buf);
  268. uavcan::ScalarCodec sc_rd(bs_rd);
  269. a.clear();
  270. b.clear();
  271. b2.clear();
  272. ASSERT_TRUE(a.empty());
  273. ASSERT_TRUE(b.empty());
  274. ASSERT_TRUE(b2.empty());
  275. ASSERT_EQ(1, A::decode(a, sc_rd, uavcan::TailArrayOptDisabled));
  276. ASSERT_EQ(1, B::decode(b, sc_rd, uavcan::TailArrayOptDisabled));
  277. ASSERT_EQ(1, B::decode(b2, sc_rd, uavcan::TailArrayOptEnabled));
  278. ASSERT_EQ(5, a.size());
  279. ASSERT_EQ(2, b.size());
  280. ASSERT_EQ(2, b2.size());
  281. ASSERT_TRUE(a[0]);
  282. ASSERT_FALSE(a[1]);
  283. ASSERT_TRUE(a[2]);
  284. ASSERT_FALSE(a[3]);
  285. ASSERT_TRUE(a[4]);
  286. ASSERT_EQ(42, b[0]);
  287. ASSERT_EQ(-42, b[1]);
  288. ASSERT_EQ(123, b2[0]);
  289. ASSERT_EQ(72, b2[1]);
  290. }
  291. ASSERT_FALSE(a == b);
  292. ASSERT_FALSE(b == a);
  293. ASSERT_TRUE(a != b);
  294. ASSERT_TRUE(b != a);
  295. a.resize(0);
  296. b.resize(0);
  297. ASSERT_TRUE(a.empty());
  298. ASSERT_TRUE(b.empty());
  299. a.resize(5, true);
  300. b.resize(255, 72);
  301. ASSERT_EQ(5, a.size());
  302. ASSERT_EQ(255, b.size());
  303. for (uint8_t i = 0; i < 5; i++)
  304. {
  305. ASSERT_TRUE(a[i]);
  306. }
  307. for (uint8_t i = 0; i < 255; i++)
  308. {
  309. ASSERT_EQ(72, b[i]);
  310. }
  311. }
  312. template <typename B>
  313. struct CustomType2
  314. {
  315. typedef uavcan::FloatSpec<16, uavcan::CastModeSaturate> A;
  316. enum { MinBitLen = A::MinBitLen + B::MinBitLen };
  317. enum { MaxBitLen = A::MaxBitLen + B::MaxBitLen };
  318. typename uavcan::StorageType<A>::Type a;
  319. typename uavcan::StorageType<B>::Type b;
  320. CustomType2()
  321. : a()
  322. , b()
  323. { }
  324. bool operator==(const CustomType2& rhs) const
  325. {
  326. return uavcan::areFloatsExactlyEqual(a, rhs.a) &&
  327. b == rhs.b;
  328. }
  329. static int encode(const CustomType2& obj, uavcan::ScalarCodec& codec,
  330. uavcan::TailArrayOptimizationMode tao_mode = uavcan::TailArrayOptEnabled)
  331. {
  332. int res = 0;
  333. res = A::encode(obj.a, codec, uavcan::TailArrayOptDisabled);
  334. if (res <= 0)
  335. {
  336. return res;
  337. }
  338. res = B::encode(obj.b, codec, tao_mode);
  339. if (res <= 0)
  340. {
  341. return res;
  342. }
  343. return 1;
  344. }
  345. static int decode(CustomType2& obj, uavcan::ScalarCodec& codec,
  346. uavcan::TailArrayOptimizationMode tao_mode = uavcan::TailArrayOptEnabled)
  347. {
  348. int res = 0;
  349. res = A::decode(obj.a, codec, uavcan::TailArrayOptDisabled);
  350. if (res <= 0)
  351. {
  352. return res;
  353. }
  354. res = B::decode(obj.b, codec, tao_mode);
  355. if (res <= 0)
  356. {
  357. return res;
  358. }
  359. return 1;
  360. }
  361. };
  362. template <typename T>
  363. static std::string runEncodeDecode(const typename uavcan::StorageType<T>::Type& value,
  364. const uavcan::TailArrayOptimizationMode tao_mode)
  365. {
  366. uavcan::StaticTransferBuffer<(T::MaxBitLen + 7) / 8> buf;
  367. uavcan::BitStream bs_wr(buf);
  368. uavcan::ScalarCodec sc_wr(bs_wr);
  369. EXPECT_EQ(1, T::encode(value, sc_wr, tao_mode));
  370. typename uavcan::StorageType<T>::Type value2 = typename uavcan::StorageType<T>::Type();
  371. // Decode multiple times to make sure that the decoded type is being correctly de-initialized
  372. for (int i = 0; i < 3; i++)
  373. {
  374. uavcan::BitStream bs_rd(buf);
  375. uavcan::ScalarCodec sc_rd(bs_rd);
  376. EXPECT_EQ(1, T::decode(value2, sc_rd, tao_mode));
  377. EXPECT_EQ(value, value2);
  378. }
  379. return bs_wr.toString();
  380. }
  381. TEST(Array, TailArrayOptimization)
  382. {
  383. typedef Array<IntegerSpec<1, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 5> OneBitArray;
  384. typedef Array<IntegerSpec<8, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 255> EightBitArray;
  385. typedef CustomType2<Array<OneBitArray, ArrayModeDynamic, 255> > A;
  386. typedef CustomType2<Array<EightBitArray, ArrayModeDynamic, 255> > B;
  387. typedef CustomType2<EightBitArray> C;
  388. A a;
  389. B b;
  390. C c;
  391. /*
  392. * Empty
  393. */
  394. // a LSB a MSB b len
  395. ASSERT_EQ("00000000 00000000 00000000", runEncodeDecode<A>(a, uavcan::TailArrayOptEnabled));
  396. ASSERT_EQ("00000000 00000000 00000000", runEncodeDecode<A>(a, uavcan::TailArrayOptDisabled));
  397. // a LSB a MSB b len
  398. ASSERT_EQ("00000000 00000000 00000000", runEncodeDecode<B>(b, uavcan::TailArrayOptEnabled));
  399. ASSERT_EQ("00000000 00000000 00000000", runEncodeDecode<B>(b, uavcan::TailArrayOptDisabled));
  400. // a LSB a MSB
  401. ASSERT_EQ("00000000 00000000", runEncodeDecode<C>(c, uavcan::TailArrayOptEnabled));
  402. ASSERT_EQ("00000000 00000000 00000000", runEncodeDecode<C>(c, uavcan::TailArrayOptDisabled));
  403. /*
  404. * A
  405. */
  406. a.b.resize(2);
  407. a.b[0].push_back(true);
  408. a.b[0].push_back(false);
  409. // a.b[1] remains empty
  410. // a LSB a MSB b len b: len(2), 1, 0, len(0)
  411. ASSERT_EQ("00000000 00000000 00000010 01010000", runEncodeDecode<A>(a, uavcan::TailArrayOptEnabled));
  412. ASSERT_EQ("00000000 00000000 00000010 01010000", runEncodeDecode<A>(a, uavcan::TailArrayOptDisabled));
  413. /*
  414. * B
  415. */
  416. b.b.resize(3);
  417. b.b[0].push_back(42);
  418. b.b[0].push_back(72);
  419. // b.b[1] remains empty
  420. b.b[2].push_back(123);
  421. b.b[2].push_back(99);
  422. // a LSB a MSB b len b[0]len 42 72 b[1]len 123 99 (b[2] len optimized out)
  423. ASSERT_EQ("00000000 00000000 00000011 00000010 00101010 01001000 00000000 01111011 01100011",
  424. runEncodeDecode<B>(b, uavcan::TailArrayOptEnabled));
  425. // Same as above, but b[2] len is present v here v
  426. ASSERT_EQ("00000000 00000000 00000011 00000010 00101010 01001000 00000000 00000010 01111011 01100011",
  427. runEncodeDecode<B>(b, uavcan::TailArrayOptDisabled));
  428. /*
  429. * C
  430. */
  431. c.a = 1;
  432. c.b.push_back(1);
  433. c.b.push_back(2);
  434. c.b.push_back(3);
  435. // a LSB a MSB 1 2 3
  436. ASSERT_EQ("00000000 00111100 00000001 00000010 00000011",
  437. runEncodeDecode<C>(c, uavcan::TailArrayOptEnabled));
  438. // a LSB a MSB b len 1 2 3
  439. ASSERT_EQ("00000000 00111100 00000011 00000001 00000010 00000011",
  440. runEncodeDecode<C>(c, uavcan::TailArrayOptDisabled));
  441. }
  442. TEST(Array, TailArrayOptimizationErrors)
  443. {
  444. typedef Array<IntegerSpec<8, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 5> A;
  445. A a;
  446. ASSERT_TRUE(a.empty());
  447. ASSERT_EQ("", runEncodeDecode<A>(a, uavcan::TailArrayOptEnabled));
  448. ASSERT_EQ("00000000", runEncodeDecode<A>(a, uavcan::TailArrayOptDisabled));
  449. // Correct decode/encode
  450. a.push_back(1);
  451. a.push_back(126);
  452. a.push_back(5);
  453. ASSERT_FALSE(a.empty());
  454. ASSERT_EQ("00000001 01111110 00000101", runEncodeDecode<A>(a, uavcan::TailArrayOptEnabled));
  455. ASSERT_EQ("01100000 00101111 11000000 10100000", runEncodeDecode<A>(a, uavcan::TailArrayOptDisabled));
  456. // Invalid decode - length field is out of range
  457. uavcan::StaticTransferBuffer<7> buf;
  458. uavcan::BitStream bs_wr(buf);
  459. uavcan::ScalarCodec sc_wr(bs_wr);
  460. ASSERT_EQ(1, sc_wr.encode<3>(uint8_t(6))); // Length - more than 5 items, error
  461. ASSERT_EQ(1, sc_wr.encode<8>(uint8_t(42)));
  462. ASSERT_EQ(1, sc_wr.encode<8>(uint8_t(72)));
  463. ASSERT_EQ(1, sc_wr.encode<8>(uint8_t(126)));
  464. ASSERT_EQ(1, sc_wr.encode<8>(uint8_t(1)));
  465. ASSERT_EQ(1, sc_wr.encode<8>(uint8_t(2)));
  466. ASSERT_EQ(1, sc_wr.encode<8>(uint8_t(3))); // Out of range - only 5 items allowed
  467. // 197 73 15 192 32 ...
  468. ASSERT_EQ("11000101 01001001 00001111 11000000 00100000 01000000 01100000", bs_wr.toString());
  469. {
  470. uavcan::BitStream bs_rd(buf);
  471. uavcan::ScalarCodec sc_rd(bs_rd);
  472. A a2;
  473. a2.push_back(56); // Garbage
  474. ASSERT_EQ(1, a2.size());
  475. // Will fail - declared length is more than 5 items
  476. ASSERT_GT(0, A::decode(a2, sc_rd, uavcan::TailArrayOptDisabled));
  477. // Must be cleared
  478. ASSERT_TRUE(a2.empty());
  479. }
  480. {
  481. uavcan::BitStream bs_rd(buf);
  482. uavcan::ScalarCodec sc_rd(bs_rd);
  483. A a2;
  484. a2.push_back(56); // Garbage
  485. ASSERT_EQ(1, a2.size());
  486. // Will fail - no length field, but the stream is too long
  487. ASSERT_GT(0, A::decode(a2, sc_rd, uavcan::TailArrayOptEnabled));
  488. // Will contain some garbage
  489. ASSERT_EQ(5, a2.size());
  490. // Interpreted stream - see the values above
  491. ASSERT_EQ(197, a2[0]);
  492. ASSERT_EQ(73, a2[1]);
  493. ASSERT_EQ(15, a2[2]);
  494. ASSERT_EQ(192, a2[3]);
  495. ASSERT_EQ(32, a2[4]);
  496. }
  497. }
  498. TEST(Array, DynamicEncodeDecodeErrors)
  499. {
  500. typedef CustomType2<Array<Array<IntegerSpec<8, SignednessUnsigned, CastModeSaturate>,
  501. ArrayModeDynamic, 255>,
  502. ArrayModeDynamic, 255> > A;
  503. A a;
  504. a.b.resize(2);
  505. a.b[0].push_back(55);
  506. a.b[0].push_back(66);
  507. {
  508. uavcan::StaticTransferBuffer<4> buf;
  509. uavcan::BitStream bs_wr(buf);
  510. uavcan::ScalarCodec sc_wr(bs_wr);
  511. ASSERT_EQ(0, A::encode(a, sc_wr, uavcan::TailArrayOptEnabled)); // Not enough buffer space
  512. uavcan::BitStream bs_rd(buf);
  513. uavcan::ScalarCodec sc_rd(bs_rd);
  514. ASSERT_EQ(0, A::decode(a, sc_rd, uavcan::TailArrayOptEnabled));
  515. }
  516. {
  517. uavcan::StaticTransferBuffer<4> buf;
  518. uavcan::BitStream bs_wr(buf);
  519. uavcan::ScalarCodec sc_wr(bs_wr);
  520. ASSERT_EQ(0, A::encode(a, sc_wr, uavcan::TailArrayOptDisabled)); // Not enough buffer space
  521. uavcan::BitStream bs_rd(buf);
  522. uavcan::ScalarCodec sc_rd(bs_rd);
  523. ASSERT_EQ(0, A::decode(a, sc_rd, uavcan::TailArrayOptDisabled));
  524. }
  525. }
  526. TEST(Array, StaticEncodeDecodeErrors)
  527. {
  528. typedef CustomType2<Array<Array<IntegerSpec<8, SignednessUnsigned, CastModeSaturate>,
  529. ArrayModeStatic, 2>,
  530. ArrayModeStatic, 2> > A;
  531. A a;
  532. a.a = 1.0;
  533. a.b[0][0] = 0x11;
  534. a.b[0][1] = 0x22;
  535. a.b[1][0] = 0x33;
  536. a.b[1][1] = 0x44;
  537. { // Just enough buffer space - 6 bytes
  538. uavcan::StaticTransferBuffer<6> buf;
  539. uavcan::BitStream bs_wr(buf);
  540. uavcan::ScalarCodec sc_wr(bs_wr);
  541. ASSERT_EQ(1, A::encode(a, sc_wr, uavcan::TailArrayOptDisabled));
  542. ASSERT_EQ("00000000 00111100 00010001 00100010 00110011 01000100", bs_wr.toString());
  543. uavcan::BitStream bs_rd(buf);
  544. uavcan::ScalarCodec sc_rd(bs_rd);
  545. ASSERT_EQ(1, A::decode(a, sc_rd, uavcan::TailArrayOptEnabled));
  546. }
  547. { // Not enough space
  548. uavcan::StaticTransferBuffer<5> buf;
  549. uavcan::BitStream bs_wr(buf);
  550. uavcan::ScalarCodec sc_wr(bs_wr);
  551. ASSERT_EQ(0, A::encode(a, sc_wr, uavcan::TailArrayOptDisabled));
  552. ASSERT_EQ("00000000 00111100 00010001 00100010 00110011", bs_wr.toString());
  553. uavcan::BitStream bs_rd(buf);
  554. uavcan::ScalarCodec sc_rd(bs_rd);
  555. ASSERT_EQ(0, A::decode(a, sc_rd, uavcan::TailArrayOptEnabled));
  556. }
  557. }
  558. TEST(Array, Copyability)
  559. {
  560. typedef Array<IntegerSpec<1, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 5> OneBitArray;
  561. typedef Array<IntegerSpec<8, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 255> EightBitArray;
  562. typedef Array<OneBitArray, ArrayModeDynamic, 255> A;
  563. typedef Array<EightBitArray, ArrayModeDynamic, 255> B;
  564. typedef EightBitArray C;
  565. A a;
  566. B b;
  567. C c;
  568. A a2 = a;
  569. B b2 = b;
  570. C c2 = c;
  571. ASSERT_TRUE(a == a2);
  572. ASSERT_TRUE(b == b2);
  573. ASSERT_TRUE(c == c2);
  574. a.push_back(OneBitArray());
  575. b.push_back(EightBitArray());
  576. c.push_back(42);
  577. ASSERT_TRUE(a != a2);
  578. ASSERT_TRUE(b != b2);
  579. ASSERT_TRUE(c != c2);
  580. a2 = a;
  581. b2 = b;
  582. c2 = c;
  583. ASSERT_TRUE(a2 == a);
  584. ASSERT_TRUE(b2 == b);
  585. ASSERT_TRUE(c2 == c);
  586. }
  587. TEST(Array, Appending)
  588. {
  589. typedef Array<FloatSpec<16, CastModeSaturate>, ArrayModeDynamic, 2> A;
  590. typedef Array<FloatSpec<16, CastModeSaturate>, ArrayModeDynamic, 257> B;
  591. A a;
  592. B b;
  593. a.push_back(1);
  594. a.push_back(2);
  595. a += b;
  596. ASSERT_EQ(2, a.size());
  597. ASSERT_EQ(1, a[0]);
  598. ASSERT_EQ(2, a[1]);
  599. b += a;
  600. ASSERT_TRUE(b == a);
  601. b += a;
  602. ASSERT_EQ(4, b.size());
  603. ASSERT_EQ(1, b[0]);
  604. ASSERT_EQ(2, b[1]);
  605. ASSERT_EQ(1, b[2]);
  606. ASSERT_EQ(2, b[3]);
  607. }
  608. TEST(Array, Strings)
  609. {
  610. typedef Array<IntegerSpec<8, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 32> A8;
  611. typedef Array<IntegerSpec<7, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 32> A7;
  612. A8 a8;
  613. A8 a8_2;
  614. A7 a7;
  615. ASSERT_TRUE(a8 == a7);
  616. // cppcheck-suppress duplicateExpression
  617. ASSERT_TRUE(a8 == a8);
  618. // cppcheck-suppress duplicateExpression
  619. ASSERT_TRUE(a7 == a7);
  620. ASSERT_TRUE(a8 == "");
  621. ASSERT_TRUE(a7 == "");
  622. a8 = "Hello world!";
  623. a7 = "123";
  624. ASSERT_TRUE(a8 == "Hello world!");
  625. ASSERT_TRUE(a7 == "123");
  626. a8 = "Our sun is dying.";
  627. a7 = "456";
  628. ASSERT_TRUE("Our sun is dying." == a8);
  629. ASSERT_TRUE("456" == a7);
  630. a8 += " 123456";
  631. a8 += "-789";
  632. ASSERT_TRUE("Our sun is dying. 123456-789" == a8);
  633. ASSERT_TRUE(a8_2 == "");
  634. ASSERT_TRUE(a8_2.empty());
  635. ASSERT_TRUE(a8_2 != a8);
  636. a8_2 = a8;
  637. ASSERT_TRUE(a8_2 == "Our sun is dying. 123456-789");
  638. ASSERT_TRUE(a8_2 == a8);
  639. /*
  640. * c_str()
  641. */
  642. ASSERT_STREQ("", A8().c_str());
  643. ASSERT_STREQ("", A7().c_str());
  644. ASSERT_STREQ("Our sun is dying. 123456-789", a8_2.c_str());
  645. ASSERT_STREQ("Our sun is dying. 123456-789", a8.c_str());
  646. ASSERT_STREQ("456", a7.c_str());
  647. /*
  648. * String constructor
  649. */
  650. A8 a8_3("123");
  651. A7 a7_3 = "456";
  652. ASSERT_EQ(3, a8_3.size());
  653. ASSERT_EQ(3, a7_3.size());
  654. ASSERT_STREQ("123", a8_3.c_str());
  655. ASSERT_STREQ("456", a7_3.c_str());
  656. }
  657. TEST(Array, AppendFormatted)
  658. {
  659. typedef Array<IntegerSpec<8, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 45> A8;
  660. A8 a;
  661. ASSERT_TRUE("" == a);
  662. a.appendFormatted("%4.1f", 12.3); // 4
  663. a += " "; // 1
  664. a.appendFormatted("%li", -123456789L); // 10
  665. a.appendFormatted("%s", " TOTAL PERSPECTIVE VORTEX "); // 26
  666. a.appendFormatted("0x%X", 0xDEADBEEF); // 10 --> 4
  667. ASSERT_STREQ("12.3 -123456789 TOTAL PERSPECTIVE VORTEX 0xDE", a.c_str());
  668. }
  669. TEST(Array, FlatStreaming)
  670. {
  671. typedef Array<IntegerSpec<8, SignednessUnsigned, CastModeSaturate>, ArrayModeDynamic, 32> A8D;
  672. typedef Array<FloatSpec<16, CastModeSaturate>, ArrayModeDynamic, 16> AF16D;
  673. typedef Array<FloatSpec<16, CastModeSaturate>, ArrayModeStatic, 3> AF16S;
  674. A8D a1;
  675. a1 = "12\n3\x44\xa5\xde\xad\x79";
  676. uavcan::YamlStreamer<A8D>::stream(std::cout, a1, 0);
  677. std::cout << std::endl;
  678. A8D a2;
  679. a2 = "Hello";
  680. uavcan::YamlStreamer<A8D>::stream(std::cout, a2, 0);
  681. std::cout << std::endl;
  682. AF16D af16d1;
  683. af16d1.push_back(1.23F);
  684. af16d1.push_back(4.56F);
  685. uavcan::YamlStreamer<AF16D>::stream(std::cout, af16d1, 0);
  686. std::cout << std::endl;
  687. AF16D af16d2;
  688. uavcan::YamlStreamer<AF16D>::stream(std::cout, af16d2, 0);
  689. std::cout << std::endl;
  690. AF16S af16s;
  691. uavcan::YamlStreamer<AF16S>::stream(std::cout, af16s, 0);
  692. std::cout << std::endl;
  693. }
  694. TEST(Array, MultidimensionalStreaming)
  695. {
  696. typedef Array<FloatSpec<16, CastModeSaturate>, ArrayModeDynamic, 16> Float16Array;
  697. typedef Array<Float16Array, ArrayModeDynamic, 8> TwoDimensional;
  698. typedef Array<TwoDimensional, ArrayModeDynamic, 4> ThreeDimensional;
  699. ThreeDimensional threedee;
  700. threedee.resize(3);
  701. for (uint8_t x = 0; x < threedee.size(); x++)
  702. {
  703. threedee[x].resize(3);
  704. for (uint8_t y = 0; y < threedee[x].size(); y++)
  705. {
  706. threedee[x][y].resize(3);
  707. for (uint8_t z = 0; z < threedee[x][y].size(); z++)
  708. {
  709. threedee[x][y][z] = 1.0F / (float(x + y + z) + 1.0F);
  710. }
  711. }
  712. }
  713. uavcan::YamlStreamer<ThreeDimensional>::stream(std::cout, threedee, 0);
  714. std::cout << std::endl;
  715. }
  716. TEST(Array, SquareMatrixPacking)
  717. {
  718. Array<FloatSpec<16, CastModeSaturate>, ArrayModeDynamic, 9> m3x3s;
  719. Array<FloatSpec<32, CastModeSaturate>, ArrayModeDynamic, 4> m2x2f;
  720. Array<FloatSpec<64, CastModeSaturate>, ArrayModeDynamic, 36> m6x6d;
  721. // NAN will be reduced to empty array
  722. {
  723. const double nans3x3[] =
  724. {
  725. NAN, NAN, NAN,
  726. NAN, NAN, NAN,
  727. NAN, NAN, NAN
  728. };
  729. m3x3s.packSquareMatrix(nans3x3);
  730. ASSERT_EQ(0, m3x3s.size());
  731. // Empty array will be decoded as zero matrix
  732. double nans3x3_out[9];
  733. m3x3s.unpackSquareMatrix(nans3x3_out);
  734. for (uint8_t i = 0; i < 9; i++)
  735. {
  736. ASSERT_DOUBLE_EQ(0, nans3x3_out[i]);
  737. }
  738. }
  739. {
  740. std::vector<double> empty;
  741. m3x3s.packSquareMatrix(empty);
  742. ASSERT_EQ(0, m3x3s.size());
  743. empty.resize(9);
  744. m3x3s.unpackSquareMatrix(empty);
  745. for (uint8_t i = 0; i < 9; i++)
  746. {
  747. ASSERT_DOUBLE_EQ(0, empty.at(i));
  748. }
  749. }
  750. // Scalar matrix will be reduced to a single value
  751. {
  752. std::vector<float> scalar2x2(4);
  753. scalar2x2[0] = scalar2x2[3] = 3.14F;
  754. m2x2f.packSquareMatrix(scalar2x2);
  755. ASSERT_EQ(1, m2x2f.size());
  756. ASSERT_FLOAT_EQ(3.14F, m2x2f[0]);
  757. m2x2f.unpackSquareMatrix(scalar2x2);
  758. const float reference[] =
  759. {
  760. 3.14F, 0.0F,
  761. 0.0F, 3.14F
  762. };
  763. ASSERT_TRUE(std::equal(scalar2x2.begin(), scalar2x2.end(), reference));
  764. }
  765. {
  766. const float scalar6x6[] =
  767. {
  768. -18, 0, 0, 0, 0, 0,
  769. 0, -18, 0, 0, 0, 0,
  770. 0, 0, -18, 0, 0, 0,
  771. 0, 0, 0, -18, 0, 0,
  772. 0, 0, 0, 0, -18, 0,
  773. 0, 0, 0, 0, 0, -18
  774. };
  775. m6x6d.packSquareMatrix(scalar6x6);
  776. ASSERT_EQ(1, m6x6d.size());
  777. ASSERT_DOUBLE_EQ(-18, m6x6d[0]);
  778. std::vector<long double> output(36);
  779. m6x6d.unpackSquareMatrix(output);
  780. ASSERT_TRUE(std::equal(output.begin(), output.end(), scalar6x6));
  781. }
  782. // Diagonal matrix will be reduced to an array of length Width
  783. {
  784. const float diagonal6x6[] =
  785. {
  786. 1, 0, 0, 0, 0, 0,
  787. 0, -2, 0, 0, 0, 0,
  788. 0, 0, 3, 0, 0, 0,
  789. 0, 0, 0, -4, 0, 0,
  790. 0, 0, 0, 0, 5, 0,
  791. 0, 0, 0, 0, 0, -6
  792. };
  793. m6x6d.packSquareMatrix(diagonal6x6);
  794. ASSERT_EQ(6, m6x6d.size());
  795. ASSERT_DOUBLE_EQ(1, m6x6d[0]);
  796. ASSERT_DOUBLE_EQ(-2, m6x6d[1]);
  797. ASSERT_DOUBLE_EQ(3, m6x6d[2]);
  798. ASSERT_DOUBLE_EQ(-4, m6x6d[3]);
  799. ASSERT_DOUBLE_EQ(5, m6x6d[4]);
  800. ASSERT_DOUBLE_EQ(-6, m6x6d[5]);
  801. std::vector<long double> output(36);
  802. m6x6d.unpackSquareMatrix(output);
  803. ASSERT_TRUE(std::equal(output.begin(), output.end(), diagonal6x6));
  804. }
  805. // A matrix filled with random values will not be compressed
  806. {
  807. std::vector<float> full3x3(9);
  808. for (uint8_t i = 0; i < 9; i++)
  809. {
  810. full3x3[i] = float(i);
  811. }
  812. m3x3s.packSquareMatrix(full3x3);
  813. ASSERT_EQ(9, m3x3s.size());
  814. for (uint8_t i = 0; i < 9; i++)
  815. {
  816. ASSERT_FLOAT_EQ(float(i), m3x3s[i]);
  817. }
  818. long output[9];
  819. m3x3s.unpackSquareMatrix(output);
  820. ASSERT_TRUE(std::equal(full3x3.begin(), full3x3.end(), output));
  821. }
  822. // This will be represented as diagonal - NANs are exceptional
  823. {
  824. const double scalarnan3x3[] =
  825. {
  826. NAN, 0, 0,
  827. 0, NAN, 0,
  828. 0, 0, NAN
  829. };
  830. m3x3s.packSquareMatrix(scalarnan3x3);
  831. ASSERT_EQ(3, m3x3s.size());
  832. ASSERT_FALSE(m3x3s[0] <= m3x3s[0]); // NAN
  833. ASSERT_FALSE(m3x3s[1] <= m3x3s[1]); // NAN
  834. ASSERT_FALSE(m3x3s[2] <= m3x3s[2]); // NAN
  835. float output[9];
  836. m3x3s.unpackSquareMatrix(output);
  837. ASSERT_FALSE(output[0] <= output[0]); // NAN
  838. ASSERT_EQ(0, output[1]);
  839. ASSERT_EQ(0, output[2]);
  840. ASSERT_EQ(0, output[3]);
  841. ASSERT_FALSE(output[4] <= output[4]); // NAN
  842. ASSERT_EQ(0, output[5]);
  843. ASSERT_EQ(0, output[6]);
  844. ASSERT_EQ(0, output[7]);
  845. ASSERT_FALSE(output[8] <= output[8]); // NAN
  846. }
  847. // This is a full matrix too (notice the NAN)
  848. {
  849. const float full2x2[] =
  850. {
  851. 1, NAN,
  852. 0, -2
  853. };
  854. m2x2f.packSquareMatrix(full2x2);
  855. ASSERT_EQ(4, m2x2f.size());
  856. ASSERT_FLOAT_EQ(1, m2x2f[0]);
  857. ASSERT_FALSE(m2x2f[1] <= m2x2f[1]); // NAN
  858. ASSERT_FLOAT_EQ(0, m2x2f[2]);
  859. ASSERT_FLOAT_EQ(-2, m2x2f[3]);
  860. float output[4];
  861. m2x2f.unpackSquareMatrix(output);
  862. ASSERT_EQ(1, output[0]);
  863. ASSERT_FALSE(output[1] <= output[1]); // NAN
  864. ASSERT_EQ(0, output[2]);
  865. ASSERT_EQ(-2, output[3]);
  866. }
  867. // Zero matrix will be represented as scalar matrix
  868. {
  869. const float zero2x2[] =
  870. {
  871. 0, 0,
  872. 0, 0
  873. };
  874. m2x2f.packSquareMatrix(zero2x2);
  875. ASSERT_EQ(1, m2x2f.size());
  876. ASSERT_FLOAT_EQ(0, m2x2f[0]);
  877. }
  878. // Symmetric matrix will contain only upper-right triangle
  879. {
  880. const float sym2x2[] =
  881. {
  882. 1, 2,
  883. 2, 1
  884. };
  885. m2x2f.packSquareMatrix(sym2x2);
  886. ASSERT_EQ(3, m2x2f.size());
  887. float sym2x2_out[4];
  888. m2x2f.unpackSquareMatrix(sym2x2_out);
  889. ASSERT_FLOAT_EQ(1, sym2x2_out[0]);
  890. ASSERT_FLOAT_EQ(2, sym2x2_out[1]);
  891. ASSERT_FLOAT_EQ(2, sym2x2_out[2]);
  892. ASSERT_FLOAT_EQ(1, sym2x2_out[3]);
  893. }
  894. {
  895. const float sym3x3[] =
  896. {
  897. 1, 2, 3,
  898. 2, 4, 5,
  899. 3, 5, 6
  900. };
  901. m3x3s.packSquareMatrix(sym3x3);
  902. ASSERT_EQ(6, m3x3s.size());
  903. ASSERT_EQ(1, m3x3s[0]);
  904. ASSERT_EQ(2, m3x3s[1]);
  905. ASSERT_EQ(3, m3x3s[2]);
  906. ASSERT_EQ(4, m3x3s[3]);
  907. ASSERT_EQ(5, m3x3s[4]);
  908. ASSERT_EQ(6, m3x3s[5]);
  909. float sym3x3_out[9];
  910. m3x3s.unpackSquareMatrix(sym3x3_out);
  911. for (int i = 0; i < 9; i++)
  912. {
  913. ASSERT_FLOAT_EQ(sym3x3[i], sym3x3_out[i]);
  914. }
  915. }
  916. {
  917. const double sym6x6[] =
  918. {
  919. 1, 2, 3, 4, 5, 6,
  920. 2, 7, 8, 9, 10, 11,
  921. 3, 8, 12, 13, 14, 15,
  922. 4, 9, 13, 16, 17, 18,
  923. 5, 10, 14, 17, 19, 20,
  924. 6, 11, 15, 18, 20, 21
  925. };
  926. m6x6d.packSquareMatrix(sym6x6);
  927. ASSERT_EQ(21, m6x6d.size());
  928. for (uavcan::uint8_t i = 0; i < 21; i++)
  929. {
  930. ASSERT_DOUBLE_EQ(double(i + 1), m6x6d[i]);
  931. }
  932. double sym6x6_out[36];
  933. m6x6d.unpackSquareMatrix(sym6x6_out);
  934. for (int i = 0; i < 36; i++)
  935. {
  936. ASSERT_DOUBLE_EQ(sym6x6[i], sym6x6_out[i]);
  937. }
  938. }
  939. }
  940. TEST(Array, FuzzySquareMatrixPacking)
  941. {
  942. Array<FloatSpec<64, CastModeSaturate>, ArrayModeDynamic, 36> m6x6d;
  943. // Diagonal matrix will be reduced to an array of length Width
  944. {
  945. float diagonal6x6[] =
  946. {
  947. 1, 0, 0, 0, 0, 0,
  948. 0, -2, 0, 0, 0, 0,
  949. 0, 0, 3, 0, 0, 0,
  950. 0, 0, 0, -4, 0, 0,
  951. 0, 0, 0, 0, 5, 0,
  952. 0, 0, 0, 0, 0, -6
  953. };
  954. // Some almost-zeroes
  955. diagonal6x6[1] = std::numeric_limits<float>::epsilon();
  956. diagonal6x6[4] = -std::numeric_limits<float>::epsilon();
  957. diagonal6x6[34] = -std::numeric_limits<float>::epsilon();
  958. m6x6d.packSquareMatrix(diagonal6x6);
  959. ASSERT_EQ(6, m6x6d.size());
  960. ASSERT_DOUBLE_EQ(1, m6x6d[0]);
  961. ASSERT_DOUBLE_EQ(-2, m6x6d[1]);
  962. ASSERT_DOUBLE_EQ(3, m6x6d[2]);
  963. ASSERT_DOUBLE_EQ(-4, m6x6d[3]);
  964. ASSERT_DOUBLE_EQ(5, m6x6d[4]);
  965. ASSERT_DOUBLE_EQ(-6, m6x6d[5]);
  966. std::vector<long double> output(36);
  967. m6x6d.unpackSquareMatrix(output);
  968. // This comparison will fail because epsilons
  969. ASSERT_FALSE(std::equal(output.begin(), output.end(), diagonal6x6));
  970. // This comparison will be ok
  971. ASSERT_TRUE(std::equal(output.begin(), output.end(), diagonal6x6, &uavcan::areClose<float, float>));
  972. }
  973. }
  974. TEST(Array, SquareMatrixPackingIntegers)
  975. {
  976. Array<IntegerSpec<30, SignednessSigned, CastModeSaturate>, ArrayModeDynamic, 9> m3x3int;
  977. {
  978. const long scalar[] =
  979. {
  980. 42, 0, 0,
  981. 0, 42, 0,
  982. 0, 0, 42
  983. };
  984. m3x3int.packSquareMatrix(scalar);
  985. ASSERT_EQ(1, m3x3int.size());
  986. ASSERT_EQ(42, m3x3int[0]);
  987. std::vector<int> output(9);
  988. m3x3int.unpackSquareMatrix(output);
  989. ASSERT_TRUE(std::equal(output.begin(), output.end(), scalar));
  990. }
  991. {
  992. std::vector<short> diagonal(9);
  993. diagonal[0] = 6;
  994. diagonal[4] = -57;
  995. diagonal[8] = 1139;
  996. m3x3int.packSquareMatrix(diagonal);
  997. ASSERT_EQ(3, m3x3int.size());
  998. ASSERT_EQ(6, m3x3int[0]);
  999. ASSERT_EQ(-57, m3x3int[1]);
  1000. ASSERT_EQ(1139, m3x3int[2]);
  1001. }
  1002. {
  1003. std::vector<long double> full(9);
  1004. for (uint8_t i = 0; i < 9; i++)
  1005. {
  1006. full[i] = i;
  1007. }
  1008. m3x3int.packSquareMatrix(full);
  1009. ASSERT_EQ(9, m3x3int.size());
  1010. for (uint8_t i = 0; i < 9; i++)
  1011. {
  1012. ASSERT_EQ(i, m3x3int[i]);
  1013. }
  1014. }
  1015. }
  1016. #if UAVCAN_EXCEPTIONS
  1017. TEST(Array, SquareMatrixPackingErrors)
  1018. {
  1019. Array<FloatSpec<16, CastModeSaturate>, ArrayModeDynamic, 9> m3x3s;
  1020. std::vector<float> ill_formed_row_major(8);
  1021. ASSERT_THROW(m3x3s.packSquareMatrix(ill_formed_row_major), std::out_of_range);
  1022. ASSERT_THROW(m3x3s.unpackSquareMatrix(ill_formed_row_major), std::out_of_range);
  1023. }
  1024. #endif
  1025. TEST(Array, SquareMatrixPackingInPlace)
  1026. {
  1027. Array<FloatSpec<16, CastModeSaturate>, ArrayModeDynamic, 9> m3x3s;
  1028. // Will do nothing - matrix is empty
  1029. m3x3s.packSquareMatrix();
  1030. ASSERT_TRUE(m3x3s.empty());
  1031. // Will fill with zeros - matrix is empty
  1032. m3x3s.unpackSquareMatrix();
  1033. ASSERT_EQ(9, m3x3s.size());
  1034. for (uint8_t i = 0; i < 9; i++)
  1035. {
  1036. ASSERT_EQ(0, m3x3s[i]);
  1037. }
  1038. // Fill an unpackaple matrix
  1039. m3x3s.clear();
  1040. m3x3s.push_back(11);
  1041. m3x3s.push_back(12);
  1042. m3x3s.push_back(13);
  1043. #if UAVCAN_EXCEPTIONS
  1044. // Shall throw - matrix is ill-formed
  1045. ASSERT_THROW(m3x3s.packSquareMatrix(), std::out_of_range);
  1046. #endif
  1047. m3x3s.push_back(21);
  1048. m3x3s.push_back(22);
  1049. m3x3s.push_back(23);
  1050. m3x3s.push_back(31);
  1051. m3x3s.push_back(32);
  1052. m3x3s.push_back(33);
  1053. // Will pack/unpack successfully
  1054. ASSERT_EQ(9, m3x3s.size());
  1055. m3x3s.packSquareMatrix();
  1056. ASSERT_EQ(9, m3x3s.size());
  1057. m3x3s.unpackSquareMatrix();
  1058. // Make sure it was unpacked properly
  1059. ASSERT_EQ(11, m3x3s[0]);
  1060. ASSERT_EQ(12, m3x3s[1]);
  1061. ASSERT_EQ(13, m3x3s[2]);
  1062. ASSERT_EQ(21, m3x3s[3]);
  1063. ASSERT_EQ(22, m3x3s[4]);
  1064. ASSERT_EQ(23, m3x3s[5]);
  1065. ASSERT_EQ(31, m3x3s[6]);
  1066. ASSERT_EQ(32, m3x3s[7]);
  1067. ASSERT_EQ(33, m3x3s[8]);
  1068. // Try again with a scalar matrix
  1069. m3x3s.clear();
  1070. for (unsigned i = 0; i < 9; i++)
  1071. {
  1072. const bool diagonal = (i == 0) || (i == 4) || (i == 8);
  1073. m3x3s.push_back(diagonal ? 123 : 0);
  1074. }
  1075. ASSERT_EQ(9, m3x3s.size());
  1076. m3x3s.packSquareMatrix();
  1077. ASSERT_EQ(1, m3x3s.size());
  1078. m3x3s.unpackSquareMatrix();
  1079. ASSERT_EQ(9, m3x3s.size());
  1080. for (uint8_t i = 0; i < 9; i++)
  1081. {
  1082. const bool diagonal = (i == 0) || (i == 4) || (i == 8);
  1083. ASSERT_EQ((diagonal ? 123 : 0), m3x3s[i]);
  1084. }
  1085. // Try again with symmetric matrix
  1086. /*
  1087. * Full matrix:
  1088. * 1 2 3
  1089. * 2 4 5
  1090. * 3 5 6
  1091. * Compressed triangle:
  1092. * 1 2 3
  1093. * 4 5
  1094. * 6
  1095. */
  1096. m3x3s.clear();
  1097. m3x3s.push_back(1);
  1098. m3x3s.push_back(2);
  1099. m3x3s.push_back(3);
  1100. m3x3s.push_back(4);
  1101. m3x3s.push_back(5);
  1102. m3x3s.push_back(6);
  1103. // Unpacking
  1104. ASSERT_EQ(6, m3x3s.size());
  1105. m3x3s.unpackSquareMatrix();
  1106. ASSERT_EQ(9, m3x3s.size());
  1107. // Validating
  1108. ASSERT_EQ(1, m3x3s[0]);
  1109. ASSERT_EQ(2, m3x3s[1]);
  1110. ASSERT_EQ(3, m3x3s[2]);
  1111. ASSERT_EQ(2, m3x3s[3]);
  1112. ASSERT_EQ(4, m3x3s[4]);
  1113. ASSERT_EQ(5, m3x3s[5]);
  1114. ASSERT_EQ(3, m3x3s[6]);
  1115. ASSERT_EQ(5, m3x3s[7]);
  1116. ASSERT_EQ(6, m3x3s[8]);
  1117. // Packing back
  1118. m3x3s.packSquareMatrix();
  1119. ASSERT_EQ(6, m3x3s.size());
  1120. // Validating
  1121. ASSERT_EQ(1, m3x3s[0]);
  1122. ASSERT_EQ(2, m3x3s[1]);
  1123. ASSERT_EQ(3, m3x3s[2]);
  1124. ASSERT_EQ(4, m3x3s[3]);
  1125. ASSERT_EQ(5, m3x3s[4]);
  1126. ASSERT_EQ(6, m3x3s[5]);
  1127. }
  1128. TEST(Array, FuzzyComparison)
  1129. {
  1130. typedef Array<Array<Array<FloatSpec<32, CastModeSaturate>, ArrayModeStatic, 2>,
  1131. ArrayModeStatic, 2>,
  1132. ArrayModeStatic, 2> ArrayStatic32;
  1133. typedef Array<Array<Array<FloatSpec<64, CastModeSaturate>, ArrayModeDynamic, 2>,
  1134. ArrayModeDynamic, 2>,
  1135. ArrayModeDynamic, 2> ArrayDynamic64;
  1136. ArrayStatic32 array_s32;
  1137. ArrayDynamic64 array_d64;
  1138. array_d64.resize(2);
  1139. array_d64[0].resize(2);
  1140. array_d64[1].resize(2);
  1141. array_d64[0][0].resize(2);
  1142. array_d64[0][1].resize(2);
  1143. array_d64[1][0].resize(2);
  1144. array_d64[1][1].resize(2);
  1145. std::cout << "One:";
  1146. uavcan::YamlStreamer<ArrayStatic32>::stream(std::cout, array_s32, 0);
  1147. std::cout << std::endl << "------";
  1148. uavcan::YamlStreamer<ArrayDynamic64>::stream(std::cout, array_d64, 0);
  1149. std::cout << std::endl;
  1150. // Both are equal right now
  1151. ASSERT_TRUE(array_d64 == array_s32);
  1152. ASSERT_TRUE(array_d64.isClose(array_s32));
  1153. ASSERT_TRUE(array_s32.isClose(array_d64));
  1154. // Slightly modifying - still close enough
  1155. array_s32[0][0][0] = 123.456F + uavcan::NumericTraits<float>::epsilon() * 123.0F;
  1156. array_s32[0][0][1] = uavcan::NumericTraits<float>::infinity();
  1157. array_s32[0][1][0] = uavcan::NumericTraits<float>::epsilon();
  1158. array_s32[0][1][1] = -uavcan::NumericTraits<float>::epsilon();
  1159. array_d64[0][0][0] = 123.456;
  1160. array_d64[0][0][1] = uavcan::NumericTraits<double>::infinity();
  1161. array_d64[0][1][0] = -uavcan::NumericTraits<double>::epsilon(); // Note that the sign is inverted
  1162. array_d64[0][1][1] = uavcan::NumericTraits<double>::epsilon();
  1163. std::cout << "Two:";
  1164. uavcan::YamlStreamer<ArrayStatic32>::stream(std::cout, array_s32, 0);
  1165. std::cout << std::endl << "------";
  1166. uavcan::YamlStreamer<ArrayDynamic64>::stream(std::cout, array_d64, 0);
  1167. std::cout << std::endl;
  1168. // They are close bot not exactly equal
  1169. ASSERT_FALSE(array_d64 == array_s32);
  1170. ASSERT_TRUE(array_d64.isClose(array_s32));
  1171. ASSERT_TRUE(array_s32.isClose(array_d64));
  1172. // Not close
  1173. array_d64[0][0][0] = 123.457;
  1174. ASSERT_FALSE(array_d64 == array_s32);
  1175. ASSERT_FALSE(array_d64.isClose(array_s32));
  1176. ASSERT_FALSE(array_s32.isClose(array_d64));
  1177. // Values are close, but lengths differ
  1178. array_d64[0][0][0] = 123.456;
  1179. ASSERT_FALSE(array_d64 == array_s32);
  1180. ASSERT_TRUE(array_d64.isClose(array_s32));
  1181. ASSERT_TRUE(array_s32.isClose(array_d64));
  1182. array_d64[0][0].resize(1);
  1183. ASSERT_FALSE(array_d64 == array_s32);
  1184. ASSERT_FALSE(array_d64.isClose(array_s32));
  1185. ASSERT_FALSE(array_s32.isClose(array_d64));
  1186. std::cout << "Three:";
  1187. uavcan::YamlStreamer<ArrayStatic32>::stream(std::cout, array_s32, 0);
  1188. std::cout << std::endl << "------";
  1189. uavcan::YamlStreamer<ArrayDynamic64>::stream(std::cout, array_d64, 0);
  1190. std::cout << std::endl;
  1191. }
  1192. TEST(Array, CaseConversion)
  1193. {
  1194. Array<IntegerSpec<8, SignednessUnsigned, CastModeTruncate>, ArrayModeDynamic, 30> str;
  1195. str.convertToLowerCaseASCII();
  1196. str.convertToUpperCaseASCII();
  1197. ASSERT_STREQ("", str.c_str());
  1198. str = "Hello World!";
  1199. ASSERT_STREQ("Hello World!", str.c_str());
  1200. str.convertToLowerCaseASCII();
  1201. ASSERT_STREQ("hello world!", str.c_str());
  1202. str.convertToUpperCaseASCII();
  1203. ASSERT_STREQ("HELLO WORLD!", str.c_str());
  1204. }