Libcxx.cpp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917
  1. /*
  2. * Copyright (C) 2011-2018 Intel Corporation. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in
  12. * the documentation and/or other materials provided with the
  13. * distribution.
  14. * * Neither the name of Intel Corporation nor the names of its
  15. * contributors may be used to endorse or promote products derived
  16. * from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. *
  30. */
  31. #include <string>
  32. #include <vector>
  33. #include <iterator>
  34. #include <typeinfo>
  35. #include <functional>
  36. #include <algorithm>
  37. #include <unordered_set>
  38. #include <unordered_map>
  39. #include <initializer_list>
  40. #include <tuple>
  41. #include <memory>
  42. #include <atomic>
  43. #include <mutex>
  44. #include <condition_variable>
  45. #include <map>
  46. #include "../Enclave.h"
  47. #include "Enclave_t.h"
  48. // Feature name : Lambda functions
  49. // Feature description : It is used to create a function object that can capture variables in scope.
  50. // Demo description : Shows lambda capture options and a some basic usages.
  51. void ecall_lambdas_demo()
  52. {
  53. // Lambdas capture options:
  54. int local_var = 0;
  55. [] { return true; }; // captures nothing
  56. [&] { return ++local_var; }; // captures all variable by reference
  57. [&local_var] { return ++local_var; }; // captures local_var by reference
  58. [&, local_var] { return local_var; }; // captures all by reference except local_var
  59. [=] { return local_var; }; // captures all variable by value
  60. [local_var] { return local_var; }; // captures local_var by value
  61. [=, &local_var] { return ++local_var; }; // captures all variable by value except local_var
  62. // Sample usages for lamdbas:
  63. std::vector< int> v { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  64. printf("[Lambdas] Initial array using lambdas: { ");
  65. // Print the elements in an array using lambdas
  66. std::for_each(std::begin(v), std::end(v), [](int elem) { printf("%d ", elem); }); //capture specification
  67. printf("}.\n");
  68. // Find the first odd number using lambda as an unary predicate when calling find_if.
  69. auto first_odd_element = std::find_if(std::begin(v), std::end(v), [=](int elem) { return elem % 2 == 1; });
  70. if (first_odd_element != std::end(v))
  71. printf("[Lambdas] First odd element in the array is %d. \n", *first_odd_element);
  72. else
  73. printf("[Lambdas] No odd element found in the array.\n");
  74. // Count the even numbers using a lambda function as an unary predicate when calling count_if.
  75. long long number_of_even_elements = std::count_if(std::begin(v), std::end(v), [=](int val) { return val % 2 == 0; });
  76. printf("[Lambdas] Number of even elements in the array is %lld.\n", number_of_even_elements);
  77. // Sort the elements of an array using lambdas
  78. std::sort(std::begin(v), std::end(v), [](int e1, int e2) {return e2 < e1; });
  79. // Print the elements in an array using lambdas
  80. printf("[Lambdas] Array after sort: { ");
  81. std::for_each(std::begin(v), std::end(v), [](int elem) { printf("%d ", elem); });
  82. printf("}. \n");
  83. printf("\n"); // end of demo
  84. }
  85. // Feature name : auto
  86. // Feature description : It is used for type deduction
  87. // Demo description : Shows basic usages of auto specifier with different types.
  88. // Helper function for ecall_auto_demo:
  89. void sample_func_auto_demo()
  90. {
  91. printf("[auto] Function sample_func_auto_demo is called. \n");
  92. }
  93. void ecall_auto_demo()
  94. {
  95. double local_var = 0.0;
  96. auto a = 7; // Type of variable a is deduced to be int
  97. printf("[auto] Type of a is int. typeid = %s.\n", typeid(a).name());
  98. const auto b1 = local_var, *b2 = &local_var; // auto can be used with modifiers like const or &.
  99. printf("[auto] Type of b1 is const double. typeid = %s.\n", typeid(b1).name());
  100. printf("[auto] Type of b2 is const double*. typeid = %s.\n", typeid(b2).name());
  101. (void)b1;
  102. (void)b2;
  103. auto c = 0, *d = &a; // multiple variable initialization if the deduced type does match
  104. printf("[auto] Type of c is int. typeid = %s.\n", typeid(c).name());
  105. printf("[auto] Type of d is int*. typeid = %s.\n", typeid(d).name());
  106. (void)c;
  107. (void)d;
  108. auto lambda = [] {}; // can be used to define lambdas
  109. printf("[auto] Type of lambda is [] {}. typeid = %s.\n", typeid(lambda).name());
  110. (void)lambda;
  111. auto func = sample_func_auto_demo; // can be used to deduce type of function
  112. printf("[auto] Type of func is void(__cdecl*)(void). typeid = %s.\n", typeid(func).name());
  113. func();
  114. printf("\n"); // end of demo
  115. }
  116. // Feature name : decltype
  117. // Feature description : It is used for type deduction
  118. // Demo description : Shows basic usages of decltype specifier with different types.
  119. void ecall_decltype_demo()
  120. {
  121. int a = 0 ;
  122. decltype(a) b = 0; // create an element of the same type as another element
  123. printf("[decltype] Type of b is int. typeid = %s.\n", typeid(b).name());
  124. double c = 0;
  125. decltype(a + c) sum = a + c; // deduce type of a sum of elements of different types and create an element of that type.
  126. // most usefull in templates.
  127. printf("[decltype] Type of sum is double. typeid = %s.\n", typeid(sum).name());
  128. (void)sum;
  129. (void)b;
  130. printf("\n"); // end of demo
  131. }
  132. // Feature name : enum classes
  133. // Feature description : A new type of enum that solves problems found in old enum like :
  134. // unscoping of enum values and the possibility to compare them with int
  135. // Demo description : Shows basic usages of enum classes.
  136. void ecall_strongly_typed_enum_demo()
  137. {
  138. // In enum class the underlying type can be set. In the case bellow it is char.
  139. enum class DaysOfWeek : char { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY };
  140. // initialization of variable of type DaysOfWeek
  141. DaysOfWeek random_day = DaysOfWeek::MONDAY;
  142. (void)random_day;
  143. // In is not mandatory to specify the underlying type.
  144. enum class Weekend { SATURDAY, SUNDAY };
  145. // The two enum classes above: days_of_week and weekend ilustrate that it is now possible to have two enum classes with the same values in them.
  146. // end of demo
  147. }
  148. // Feature name : Range based for loops
  149. // Feature description : Easy to read way of accessing elements in an container.
  150. // Demo description : Shows basic usage of range based for loop with c array and vector.
  151. void ecall_range_based_for_loops_demo()
  152. {
  153. char array_of_letters[] = { 'a','b','c','d' };
  154. std::vector<char> vector_of_letters = { 'a','b','c','d' };
  155. printf("[range_based_for_loops] Using range based for loops to print the content of an array: { ");
  156. for (auto elem : array_of_letters)
  157. printf("%c ", elem);
  158. printf("}. \n");
  159. printf("[range_based_for_loops] Using range based for loops to print the content of an vector: { ");
  160. for (auto elem : vector_of_letters)
  161. printf("%c ", elem);
  162. printf("}.\n");
  163. printf("\n"); // end of demo
  164. }
  165. // Feature name : static_assert
  166. // Feature description : It is used to make assertions at compile time.
  167. // Demo description : Shows basic usage of static_assert with compile time operation.
  168. void ecall_static_assert_demo()
  169. {
  170. static_assert(sizeof(int) < sizeof(double), "Error : sizeof(int) < sizeof(double) ");
  171. const int a = 0;
  172. static_assert(a == 0, "Error: value of a is not 0");
  173. // end of demo
  174. }
  175. // Feature name : New virtual function controls : override, final, default, and delete
  176. // Feature description : - delete : a deleted function cannot be inherited
  177. // - final : a final function cannot be overrided in the derived class
  178. // - default : intruction to the compiler to generate a default function
  179. // - override : ensures that a virtual function from derived class overrides a function from base
  180. // Demo description : Shows basic usage of new virtual function control.
  181. /* Helper class for ecall_virtual_function_control_demo.*/
  182. class Base
  183. {
  184. public:
  185. virtual void f_cannot_be_inherited() final {};
  186. Base(const Base &) = delete;
  187. Base() = default;
  188. virtual void f_must_be_overrided() {};
  189. };
  190. /* Helper class for ecall_virtual_function_control_demo.*/
  191. class Derived : Base
  192. {
  193. public:
  194. /* The code bellow in this comment does not compile.
  195. The function cannot be override because it is declared with keyword final in base
  196. virtual double f_cannot_be_inherited() {};
  197. */
  198. /*The keyword override assures that the function overrides a base class member*/
  199. virtual void f_must_be_overrided() override {};
  200. };
  201. void ecall_virtual_function_control_demo()
  202. {
  203. // The default constructor will be called generated by the compiler with explicit keyword default
  204. Base a;
  205. // Trying to use the copy contructor will generate code that does not compile because it is deleted
  206. // Base b = a;
  207. // end of demo
  208. }
  209. // Feature name : Delegating constructors
  210. // Feature description : A class constructors may have common code which can be delegated to a constructor to avoid code repetion
  211. // Demo description : Shows basic usage of delegating constructors
  212. // Helper class for ecall_delegating_constructors
  213. class DemoDelegatingConstructors
  214. {
  215. int a, b, c;
  216. public:
  217. DemoDelegatingConstructors(int param_a, int param_b, int param_c)
  218. {
  219. this->a = param_a;
  220. this->b = param_b;
  221. this->c = param_c;
  222. /*common initialization*/
  223. switch (c)
  224. {
  225. case 1:
  226. printf("[delegating constructors] Called from DemoDelegatingConstructors(int a, int b). \n");
  227. break;
  228. case 2:
  229. printf("[delegating constructors] Called from DemoDelegatingConstructors(int a). \n");
  230. break;
  231. default:
  232. printf("[delegating constructors] Called from DemoDelegatingConstructors(int a, int b, int c).\n");
  233. break;
  234. }
  235. }
  236. DemoDelegatingConstructors(int param_a, int param_b) : DemoDelegatingConstructors(param_a, param_b, 1) {}
  237. DemoDelegatingConstructors(int param_a) : DemoDelegatingConstructors(param_a, 0, 2) {}
  238. };
  239. void ecall_delegating_constructors_demo()
  240. {
  241. DemoDelegatingConstructors a(1, 2, 3);
  242. DemoDelegatingConstructors b(1, 2);
  243. DemoDelegatingConstructors c(1);
  244. printf("\n"); // end of demo
  245. }
  246. // Feature name : std::function
  247. // Feature description : It is used to store and invoke a callable
  248. // Demo description : Shows basic usage of std::function
  249. // Helper class for ecall_std_function_demo:
  250. void sample_std_function1()
  251. {
  252. printf("[std_function] calling sample_std_function1\n");
  253. }
  254. void ecall_std_function_demo()
  255. {
  256. // Example with functions
  257. std::function<void()> funct = sample_std_function1;
  258. funct();
  259. //Example with lambda
  260. std::function<void()> funct_lambda = [] { printf("[std_function] calling a lambda function\n"); };
  261. funct_lambda();
  262. printf("\n"); // end of demo
  263. }
  264. // Feature name : std::all_of, std::any_of, std::none_of
  265. // Feature description : New C++11 algorithms
  266. // Demo description : Shows basic usage of the std::all_of, std::any_of, std::none_of.
  267. void ecall_cxx11_algorithms_demo()
  268. {
  269. std::vector<int> v = { 0, 1, 2, 3, 4, 5 };
  270. bool are_all_of = all_of(begin(v), end(v), [](int e) { return e % 2 == 0; });
  271. printf("[cxx11_algorithms] All elements in { 0 1 2 3 4 5 } are even is %s. \n", are_all_of ? "true" : "false");
  272. bool are_any_of = any_of(begin(v), end(v), [](int e) { return e % 2 == 0; });
  273. printf("[cxx11_algorithms] Some elements in { 0 1 2 3 4 5 } are even is %s. \n", are_any_of ? "true" : "false");
  274. bool are_none_of = none_of(begin(v), end(v), [](int e) { return e % 2 == 0; });
  275. printf("[cxx11_algorithms] None elements in { 0 1 2 3 4 5 } are even is %s. \n", are_none_of ? "true" : "false");
  276. printf("\n"); // end of demo
  277. }
  278. // Feature name : variadic templates
  279. // Feature description : Templates that can have multiple arguments
  280. // Demo description : Shows basic usage of variadic templates
  281. // Helper template for ecall_variadic_templates_demo:
  282. template<typename T>
  283. T sum(T elem)
  284. {
  285. return elem;
  286. }
  287. template<typename T, typename... Args>
  288. T sum(T elem1, T elem2, Args... args)
  289. {
  290. return elem1 + elem2 + sum(args...);
  291. }
  292. void ecall_variadic_templates_demo()
  293. {
  294. int computed_sum = sum(1, 2, 3, 4, 5);
  295. printf("[variadic_templates] The sum of paramters (1, 2, 3, 4, 5) is %d. \n", computed_sum);
  296. printf("\n"); // end of demo
  297. }
  298. // Feature name : Substitution failure is not an error (SFINAE)
  299. // Feature description : Describes the case where a substitution error in templates does not cause errors
  300. // Demo description : Shows basic usage of SFINAE
  301. /*first candidate for substitution*/
  302. template <typename T> void f(typename T::A*) { printf("[sfinae] First candidate for substitution is matched.\n"); };
  303. /*second candidate for substitution*/
  304. template <typename T> void f(T) { printf("[sfinae] Second candidate for substitution is matched.\n"); }
  305. void ecall_SFINAE_demo()
  306. {
  307. f<int>(0x0); // even if the first canditate substition will fail, the second one will pass
  308. printf("\n"); // end of demo
  309. }
  310. //Feature name : Initializer lists
  311. //Feature description : An object of type std::initializer_list<T> is a lightweight proxy object that provides access to an array of objects of type const T.
  312. //Demo description : Demonstrates the usage of initializer list in the constructor of an object in enclave.
  313. class Number
  314. {
  315. public:
  316. Number(const std::initializer_list<int> &v) {
  317. for (auto i : v) {
  318. elements.push_back(i);
  319. }
  320. }
  321. void print_elements() {
  322. printf("[initializer_list] The elements of the vector are:");
  323. for (auto item : elements) {
  324. printf(" %d", item);
  325. }
  326. printf(".\n");
  327. }
  328. private:
  329. std::vector<int> elements;
  330. };
  331. void ecall_initializer_list_demo()
  332. {
  333. printf("[initializer_list] Using initializer list in the constructor. \n");
  334. Number m = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
  335. m.print_elements();
  336. printf("\n"); //end of demo
  337. }
  338. // Feature name : Rvalue references and move semantics;
  339. // Feature description : They are used for memory usage optimazation by eliminating copy operations
  340. // Demo description : Shows basic usage of rvalue, move constructor, and move operator
  341. // Helper class for ecall_rvalue_demo
  342. class DemoBuffer
  343. {
  344. public:
  345. unsigned int size = 100;
  346. char *buffer;
  347. DemoBuffer(int param_size)
  348. {
  349. this->size = param_size;
  350. buffer = new char[size];
  351. printf("[rvalue] Called constructor : DemoBuffer(int size).\n");
  352. }
  353. // A typical copy constructor needs to alocate memory for a new copy
  354. // Copying an big array is an expensive operation
  355. DemoBuffer(const DemoBuffer & rhs)
  356. {
  357. this->size = rhs.size;
  358. buffer = new char[rhs.size];
  359. memcpy(buffer, rhs.buffer, size);
  360. printf("[rvalue] Called copy constructor : DemoBuffer(const DemoBuffer & rhs).\n");
  361. }
  362. // A typical move constructor can reuse the memory pointed by the buffer
  363. DemoBuffer(DemoBuffer && rhs)
  364. {
  365. buffer = rhs.buffer;
  366. size = rhs.size;
  367. // reset state of rhs
  368. rhs.buffer = NULL;
  369. rhs.size = 0;
  370. printf("[rvalue] Called move constructor : DemoBuffer(DemoBuffer && rhs).\n");
  371. }
  372. ~DemoBuffer()
  373. {
  374. delete buffer;
  375. }
  376. };
  377. // Helper class for ecall_rvalue_demo
  378. DemoBuffer foobar(int a)
  379. {
  380. DemoBuffer x(100);
  381. DemoBuffer y(100);
  382. if (a > 0)
  383. return x;
  384. else
  385. return y;
  386. }
  387. void ecall_rvalue_demo()
  388. {
  389. // This will call the constructor
  390. printf("[rvalue] DemoBuffer a(100).\n");
  391. DemoBuffer a(100);
  392. printf("[rvalue] DemoBuffer foobar(100). \n");
  393. // Initializing variable d using a temporary object will result in a call to move constructor
  394. // This is usefull because it reduces the memory cost of the operation.
  395. DemoBuffer d(foobar(100));
  396. // This will call the copy constructor. State of a will not change.
  397. printf("[rvalue] DemoBuffer b(a).\n");
  398. DemoBuffer b(a);
  399. printf("[rvalue] DemoBuffer c(std::move(a)).\n");
  400. // explicitly cast a to an rvalue so that c will be created using move constructor.
  401. // State of a is going to be reseted.
  402. DemoBuffer c(std::move(a));
  403. printf("\n"); // end of demo
  404. }
  405. // Feature name : Nullptr
  406. // Feature description : Resolves the issues of converting NULL to integral types
  407. // Demo description : Shows basic usage of nullptr
  408. // overload candidate 1
  409. void nullptr_overload_candidate(int i) {
  410. (void)i;
  411. printf("[nullptr] called void nullptr_overload_candidate(int i).\n");
  412. }
  413. // overload candidate 2
  414. void nullptr_overload_candidate(int* ptr) {
  415. (void)ptr;
  416. printf("[nullptr] called void nullptr_overload_candidate(int* ptr).\n");
  417. }
  418. template<class F, class A>
  419. void Fwd(F f, A a)
  420. {
  421. f(a);
  422. }
  423. void g(int* i)
  424. {
  425. (void)i;
  426. printf("[nullptr] Function %s called\n", __FUNCTION__);
  427. }
  428. // Feature name :
  429. // Feature description :
  430. // Demo description :
  431. void ecall_nullptr_demo()
  432. {
  433. // NULL can be converted to integral types() like int and will call overload candidate 1
  434. nullptr_overload_candidate(NULL);
  435. // nullptr can't be converted to integral types() like int and will call overload candidate 2
  436. nullptr_overload_candidate(nullptr);
  437. g(NULL); // Fine
  438. g(0); // Fine
  439. Fwd(g, nullptr); // Fine
  440. //Fwd(g, NULL); // ERROR: No function g(int)
  441. printf("\n"); // end of demo
  442. }
  443. // Feature name : Scoped enums
  444. // Feature description :
  445. // Demo description :
  446. enum class Color { orange, brown, green = 30, blue, red };
  447. void ecall_enum_class_demo()
  448. {
  449. int n = 0;
  450. Color color1 = Color::brown;
  451. switch (color1)
  452. {
  453. case Color::orange: printf("[enum class] orange"); break;
  454. case Color::brown: printf("[enum class] brown"); break;
  455. case Color::green: printf("[enum class] green"); break;
  456. case Color::blue: printf("[enum class] blue"); break;
  457. case Color::red: printf("[enum class] red"); break;
  458. }
  459. // n = color1; // Not allowed: no scoped enum to int conversion
  460. n = static_cast<int>(color1); // OK, n = 1
  461. printf(" - int = %d\n", n);
  462. Color color2 = Color::red;
  463. switch (color2)
  464. {
  465. case Color::orange: printf("[enum class] orange"); break;
  466. case Color::brown: printf("[enum class] brown"); break;
  467. case Color::green: printf("[enum class] green"); break;
  468. case Color::blue: printf("[enum class] blue"); break;
  469. case Color::red: printf("[enum class] red"); break;
  470. }
  471. n = static_cast<int>(color2); // OK, n = 32
  472. printf(" - int = %d\n", n);
  473. Color color3 = Color::green;
  474. switch (color3)
  475. {
  476. case Color::orange: printf("[enum class] orange"); break;
  477. case Color::brown: printf("[enum class] brown"); break;
  478. case Color::green: printf("[enum class] green"); break;
  479. case Color::blue: printf("[enum class] blue"); break;
  480. case Color::red: printf("[enum class] red"); break;
  481. }
  482. n = static_cast<int>(color3); // OK, n = 30
  483. printf(" - int = %d\n", n);
  484. printf("\n");
  485. }
  486. // Feature name : new container classes
  487. // Feature description : unordered_set, unordered_map, unordered_multiset, and unordered_multimap
  488. // Demo description : Shows basic usage of new container classes
  489. void ecall_new_container_classes_demo()
  490. {
  491. // unordered_set
  492. // container used for fast acces that groups elements in buckets based on their hash
  493. std::unordered_set<int> set_of_numbers = { 0, 1, 2, 3, 4, 5 };
  494. const int searchVal = 3;
  495. std::unordered_set<int>::const_iterator got = set_of_numbers.find(searchVal);
  496. if (got != set_of_numbers.end())
  497. printf("[new_container_classes] unordered_set { 0, 1, 2, 3, 4, 5} has value 3.\n");
  498. else
  499. printf("[new_container_classes] unordered_set { 0, 1, 2, 3, 4, 5} does not have value 3.\n");
  500. // unordered_multiset
  501. // container used for fast acces that groups non unique elements in buckets based on their hash
  502. std::unordered_multiset<int> multiset_of_numbers = { 0, 1, 2, 3, 3, 3 };
  503. printf("[new_container_classes] multiset_set { 0, 1, 2, 3, 3, 3} has %d elements with value %d.\n",
  504. (int)multiset_of_numbers.count(searchVal), searchVal);
  505. // unordered_map
  506. std::unordered_map<std::string, int> grades{ { "A", 10 },{ "B", 8 },{ "C", 7 },{ "D", 5 },{ "E", 3 } };
  507. printf("[new_container_classes] unordered_map elements: {");
  508. for (auto pair : grades) {
  509. printf("[%s %d] ", pair.first.c_str(), pair.second);
  510. }
  511. printf("}.\n");
  512. // unordered_multimap
  513. std::unordered_multimap<std::string, int> multimap_grades{ { "A", 10 },{ "B", 8 },{ "B", 7 },{ "E", 5 },{ "E", 3 },{ "E",1 } };
  514. printf("[new_container_classes] unordered_multimap elements: {");
  515. for (auto pair : multimap_grades) {
  516. printf("[%s %d] ", pair.first.c_str(), pair.second);
  517. }
  518. printf("}.\n");
  519. printf("\n"); // end of demo
  520. }
  521. // Feature name : Tuple
  522. // Feature description : Objects that pack elements of multiple types which can be accessed by index
  523. // Demo description : Shows basic usage of tuple: creation and access
  524. void ecall_tuple_demo()
  525. {
  526. // Create tuple using std::make_tuple
  527. char array_of_letters[4] = {'A','B','C','D'};
  528. std::vector<char> vector_of_letters = { 'A','B','C','D' };
  529. std::map<char, char> map_of_letters = { {'B','b' } };
  530. // Creating a tuple using a tuple constructor
  531. std::tuple<int, std::string> tuple_sample_with_constructor(42, "Sample tuple");
  532. (void)tuple_sample_with_constructor;
  533. // Creating a tuple using std::make_tuple
  534. auto tuple_sample = std::make_tuple("<First element of TupleSample>", 1, 7.9, vector_of_letters, array_of_letters, map_of_letters);
  535. // Access the elements in tupleSample using std::get<index>
  536. printf("[tuple] show first element in TupleSample: %s. \n", std::get<0>(tuple_sample));
  537. printf("[tuple] show second element in TupleSample: %d. \n", std::get<1>(tuple_sample));
  538. printf("[tuple] show third element in TupleSample: %f. \n", std::get<2>(tuple_sample));
  539. // Getting vector from a tuple
  540. std::vector<char> temp_vector = std::get<3>(tuple_sample);
  541. (void)temp_vector;
  542. // Getting array from a tuple
  543. int first_elem_of_array = std::get<4>(tuple_sample)[0];
  544. (void)first_elem_of_array;
  545. // Getting map from a tuple
  546. std::map<char, char> temp_map = std::get<5>(tuple_sample);
  547. (void)temp_map;
  548. printf("\n"); // end of demo
  549. }
  550. // Feature name : new smart pointer
  551. // Feature description : shared_ptr and unique_ptr
  552. // Demo decription : Shows basic usage of smart pointers
  553. // Helper class for ecall_shared_ptr_demo
  554. class DemoSmartPtr
  555. {
  556. std::string smartPointerType;
  557. public:
  558. DemoSmartPtr(std::string param_smartPointerType)
  559. {
  560. printf("[smart_ptr] In construct of object demo_smart_ptr using %s. \n", param_smartPointerType.c_str());
  561. this->smartPointerType = param_smartPointerType;
  562. }
  563. ~DemoSmartPtr()
  564. {
  565. printf("[smart_ptr] In deconstructor of object demo_smart_ptr using %s. \n", smartPointerType.c_str());
  566. }
  567. };
  568. void ecall_shared_ptr_demo()
  569. {
  570. // std::shared_ptr is smart pointer that takes ownership of an object using a pointer
  571. // The object is freed when the last smart_pointer does not point to it.
  572. // Creating a shared pointer using std::make_shared
  573. auto shared_ptr = std::make_shared<DemoSmartPtr>("smart_ptr."); // The constructor of DemoSmartPtr will be called here
  574. printf("[smart_ptr] shared_ptr reference count = %ld. \n", shared_ptr.use_count());
  575. auto shared_ptr2 = shared_ptr;
  576. printf("[smart_ptr] shared_ptr reference count = %ld incresead after creating another shared pointer.\n", shared_ptr.use_count());
  577. shared_ptr2.reset();
  578. printf("[smart_ptr] shared_ptr reference count = %ld decresead after calling releasing ownership. \n", shared_ptr.use_count());
  579. // std::unique_ptr is smart pointer that takes ownership of an object using a pointer
  580. // it is different from smart_ptr in the sense that only one unique_ptr can take ownership
  581. std::unique_ptr<DemoSmartPtr> unique_ptr(new DemoSmartPtr("unique_ptr"));
  582. // When going out of scope both shared_ptr and unique_ptr release the objects they own
  583. // end of demo
  584. }
  585. //Feature name : atomic
  586. //Feature description: The atomic library provides components for fine-grained atomic operations allowing for lockless concurrent programming.
  587. // Each atomic operation is indivisible with regards to any other atomic operation that involves the same object.
  588. // Atomic objects are free of data races.
  589. //Demo description : Demonstrates the usage of atomic types, objects and functions in enclave.
  590. void ecall_atomic_demo()
  591. {
  592. printf("[atomic] Atomic types, objects and functions demo.\n");
  593. printf("[atomic_store] Defining an atomic_char object with an initial value of 5.\n");
  594. std::atomic_char atc(5);
  595. printf("[atomic_store] The current value stored in the atomic object is: %d\n", atc.load());
  596. printf("[atomic_store] Replacing the value of the atomic object with a non-atomic value of 3.\n");
  597. std::atomic_store<char>(&atc, 3);
  598. printf("[atomic_store] The new value of the atomic object is: %d.\n", atc.load());
  599. printf("\n");
  600. printf("[atomic_store_explicit] Defining an atomic_short object with an initial value of 5.\n");
  601. std::atomic_short ats(5);
  602. printf("[atomic_store_explicit] The current value stored in the atomic object is: %d.\n", ats.load());
  603. printf("[atomic_store_explicit] Replacing the value of the atomic object with a non-atomic value of 3.\n");
  604. std::atomic_store_explicit<short>(&ats, 3, std::memory_order_seq_cst);
  605. printf("[atomic_store] The new value of the atomic object is: %d.\n", ats.load());
  606. printf("\n");
  607. printf("[atomic_load] Defining an atomic_int object with an initial value of 4.\n");
  608. std::atomic_int ati1(4);
  609. printf("[atomic_load] Obtaining the value of the atomic object and saving it in a int variable.\n");
  610. int val = std::atomic_load(&ati1);
  611. printf("[atomic_load] The obtained value is %d.\n", val);
  612. printf("\n");
  613. printf("[atomic_load_explicit] Defining an atomic_int object with an initial value of 2.\n");
  614. std::atomic_int ati2(2);
  615. printf("[atomic_load_explicit] Obtaining the value of the atomic object and saving it in a int variable.\n");
  616. int val1 = std::atomic_load_explicit(&ati2, std::memory_order_seq_cst);
  617. printf("[atomic_load_explicit] The obtained value is %d.\n", val1);
  618. printf("\n");
  619. printf("[atomic_fetch_add] Defining an atomic_int object with an initial value of 7.\n");
  620. std::atomic_int ati(7);
  621. printf("[atomic_fetch_add] The current value stored in the atomic object is: %d.\n", ati.load());
  622. printf("[atomic_fetch_add] Adding a non-atomic value of 8 to the atomic object.\n");
  623. std::atomic_fetch_add(&ati, 8);
  624. printf("[atomic_fetch_add] The new value of the atomic object is: %d.\n", ati.load());
  625. printf("\n");
  626. printf("[atomic_fetch_add_explicit] Defining an atomic_uint object with an initial value of 7.\n");
  627. std::atomic_uint atui(7);
  628. printf("[atomic_fetch_add_explicit] The current value stored in the atomic object is: %u.\n", atui.load());
  629. printf("[atomic_fetch_add_explicit] Adding a non-atomic value of 8 to the atomic object.\n");
  630. std::atomic_fetch_add_explicit<unsigned int>(&atui, 8, std::memory_order_seq_cst);
  631. printf("[atomic_fetch_add_explicit] The new value of the atomic object is: %u.\n", atui.load());
  632. printf("\n");
  633. printf("[atomic_fetch_sub] Defining an atomic_long object with an initial value of 20.\n");
  634. std::atomic_long atl(20);
  635. printf("[atomic_fetch_sub] The current value stored in the atomic object is: %ld.\n", atl.load());
  636. printf("[atomic_fetch_sub] Substracting a non-atomic value of 8 from the value of the atomic object.\n");
  637. std::atomic_fetch_sub<long>(&atl, 8);
  638. printf("[atomic_fetch_sub] The new value of the atomic object is: %ld.\n", atl.load());
  639. printf("\n");
  640. printf("[atomic_fetch_sub_explicit] Defining an atomic_llong object with an initial value of 20.\n");
  641. std::atomic_llong atll(20);
  642. printf("[atomic_fetch_sub_explicit] The current value stored in the atomic object is: %lld.\n", atll.load());
  643. printf("[atomic_fetch_sub_explicit] Substracting a non-atomic value of 8 from the value of the atomic object.\n");
  644. std::atomic_fetch_sub_explicit<long long>(&atll, 8, std::memory_order_seq_cst);
  645. printf("[atomic_fetch_sub_explicit] The new value of the atomic object is: %lld.\n", atll.load());
  646. printf("\n"); // end of demo
  647. }
  648. //Feature name : mutex
  649. //Feature description : The mutex class is a synchronization primitive that can be used to protect shared data
  650. // from being simultaneously accessed by multiple threads.
  651. //Demo description : Demonstrates mutex protection when incrementing values in multiple threads.
  652. //Structure used in mutex demo to show the behavior without using a mutex
  653. struct CounterWithoutMutex {
  654. int value;
  655. CounterWithoutMutex() : value(0) {}
  656. void increment() {
  657. ++value;
  658. }
  659. };
  660. CounterWithoutMutex counter_without_protection;
  661. //E-call used by mutex demo to perform the incrementation using a counter without mutex protection
  662. void ecall_mutex_demo_no_protection()
  663. {
  664. for (int i = 0; i < 100000; ++i) {
  665. counter_without_protection.increment();
  666. }
  667. }
  668. //E-call used by mutex demo to get the final value of the counter from enclave
  669. void ecall_print_final_value_no_protection()
  670. {
  671. printf("[mutex] Incrementing values in three threads without mutex protection, using a 100000 times loop. \n[mutex]Expected value is 300000. The final value is %d.\n", counter_without_protection.value);
  672. }
  673. //Structure used in mutex demo
  674. struct CounterProtectedByMutex {
  675. std::mutex mutex;
  676. int value;
  677. CounterProtectedByMutex() : value(0) {}
  678. void increment() {
  679. //locking the mutex to avoid simultaneous incrementation in different threads
  680. mutex.lock();
  681. ++value;
  682. //unlocking the mutex
  683. mutex.unlock();
  684. }
  685. };
  686. CounterProtectedByMutex counter_with_protection;
  687. //E-call used by mutex demo to perform the actual incrementation
  688. void ecall_mutex_demo()
  689. {
  690. for (int i = 0; i < 100000; ++i) {
  691. counter_with_protection.increment();
  692. }
  693. }
  694. //E-call used by mutex demo to get the final value of the counter from enclave
  695. void ecall_print_final_value_mutex_demo()
  696. {
  697. printf("[mutex] Mutex protection when incrementing a value in 3 threads, using a 100000 times loop. \n[mutex]Expected value is 300000. The final value is %d.\n", counter_with_protection.value);
  698. }
  699. //Feature name : condition_variable
  700. //Feature description: The condition_variable class is a synchronization primitive that can be used to block a thread,
  701. // or multiple threads at the same time, until another thread both modifies a shared variable (the condition),
  702. // and notifies the condition_variable.
  703. //Demo description : Demonstrates condition_variable usage in a two threads environment. One thread is used for loading the data and
  704. // the other processes the loaded data. The thread for processing the data waits untill the data is loaded in the
  705. // other thread and gets notified when loading is completed.
  706. //This class is used by condition variable demo
  707. class DemoConditionVariable
  708. {
  709. std::mutex mtx;
  710. std::condition_variable cond_var;
  711. bool data_loaded;
  712. public:
  713. DemoConditionVariable()
  714. {
  715. data_loaded = false;
  716. }
  717. void load_data()
  718. {
  719. //Simulating loading of the data
  720. printf("[condition_variable] Loading Data...\n");
  721. {
  722. // Locking the data structure
  723. std::lock_guard<std::mutex> guard(mtx);
  724. // Setting the flag to true to signal load data completion
  725. data_loaded = true;
  726. }
  727. // Notify to unblock the waiting thread
  728. cond_var.notify_one();
  729. }
  730. bool is_data_loaded()
  731. {
  732. return data_loaded;
  733. }
  734. void main_task()
  735. {
  736. printf("\n");
  737. printf("[condition_variable] Running condition variable demo.\n");
  738. // Acquire the lock
  739. std::unique_lock<std::mutex> lck(mtx);
  740. printf("[condition_variable] Waiting for the data to be loaded in the other thread.\n");
  741. cond_var.wait(lck, std::bind(&DemoConditionVariable::is_data_loaded, this));
  742. printf("[condition_variable] Processing the loaded data.\n");
  743. printf("[condition_variable] Done.\n");
  744. }
  745. };
  746. DemoConditionVariable app;
  747. //E-call used by condition_variable demo - processing thread
  748. void ecall_condition_variable_run()
  749. {
  750. app.main_task();
  751. }
  752. //E-call used by condifion_variable demo - loader thread
  753. void ecall_condition_variable_load()
  754. {
  755. app.load_data();
  756. }