main.cc 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. //main.cc - A short driver full of examples of how to use the read.h header library
  2. //There is an explanation of what each line does and the benefits of it
  3. //by ShakaUVM
  4. #include "read.h"
  5. #include <vector>
  6. #include <cstdlib>
  7. #include <cmath>
  8. #include <iomanip>
  9. using namespace std;
  10. //Use high resolution clock if C++11 or better, otherwise use clock()
  11. #if __cplusplus >= 201103L
  12. #include <chrono>
  13. using namespace chrono;
  14. using hrc = high_resolution_clock;
  15. #else
  16. #include <ctime>
  17. #endif
  18. //The library works on user defined types with operator>> as well as all primitive types
  19. struct Tester{ int x; float f; };
  20. istream &operator>>(istream &ins, Tester &t) { t.x = read(ins); t.f = read(ins); return ins; }
  21. int main() {
  22. //Example 1 - reading using a function instead of cin >>
  23. //Will clear errors and reprompt if the user doesn't type in an int
  24. //If you have C++14 or above, you can use a simpler version
  25. int green_apples = read("Please enter how many green apples you want to buy: "); //Reads an int from the standard in
  26. //You can specify the type in angle brackets.
  27. //The prompt is optional, in which case it works just like cin >> but can appear on the right hand side
  28. #if __cplusplus >= 201103L
  29. auto red_apples = read<int>("Please enter how many red apples you want to buy: "); //Reads an int from the standard in
  30. #else
  31. int red_apples = read<int>("Please enter how many red apples you want to buy: "); //Auto not available prior to C++11
  32. #endif
  33. //By making input on the right hand side, you can use const and/or auto with input
  34. //Const and auto are popular these days, so it makes sense for input to be assignable
  35. #if __cplusplus >= 201103L
  36. const auto price = read<double>("Please enter the price per apple: "); //Reads a double, stores it in a const
  37. #else
  38. const double price = read<double>("Please enter the price per apple: "); //C++98 equivalent code
  39. #endif
  40. cout << "Your total bill is " << (red_apples + green_apples) * price << endl;
  41. //Example 2 - can mix and match cin >> and getline without issue
  42. //This solves a persistent problem with iostreams
  43. //On the downside, you can't just hit enter to enter an empty string now
  44. string filename = readline("Please enter a file to read ints from (shuf.txt is the default): ");
  45. cout << "Attempting to open " << filename << " now...\n";
  46. //Example 3 - Works with files as well
  47. //Note there is no prompt when reading from a file, since that doesn't make sense
  48. ifstream ins(filename.c_str()); //Shuf.txt Holds the numbers from 1 to 1M, shuffled
  49. if (!ins) {
  50. cout << "Error: Couldn't open " << filename << endl;
  51. exit(EXIT_FAILURE);
  52. }
  53. cout << "The first int in the file is: " << read<int>(ins) << endl; // You can embed input in output
  54. //Example 4 - time how long it takes to read 1M numbers from a file
  55. vector<int> vec;
  56. vec.reserve(1000000);
  57. //Start the timer, using either modern or old C++
  58. #if __cplusplus >= 201103L
  59. hrc::time_point start = hrc::now(); //Start timer
  60. #else
  61. clock_t start = clock(); //Start timer the old way
  62. #endif
  63. while (true) {
  64. #ifdef ORIG
  65. //Compile with -DORIG to time the old way
  66. int x = 0;
  67. ins >> x;
  68. if (!ins) break;
  69. vec.push_back(x);
  70. #else
  71. //The new way is more compact
  72. int x = read(ins);
  73. if (!ins) break;
  74. vec.push_back(x);
  75. #endif
  76. }
  77. //End the timer using either modern or old C++
  78. #if __cplusplus >= 201103L
  79. hrc::time_point end = hrc::now(); //End timer
  80. cerr << "Time to read 1M ints: " << fixed << setprecision(3) << duration_cast<duration<double>>(end - start).count() << "s\n";
  81. #else
  82. clock_t end = clock();
  83. cerr << "Time to read 1M ints: " << fixed << setprecision(3) << double(end - start)/CLOCKS_PER_SEC << "s\n";
  84. #endif
  85. //Example 5 - The library works with any type for which there is a default constructor and operator>> defined
  86. //So anything that you could cin >> before you can read() now
  87. Tester t = read("Please enter an int and a float:\n");
  88. //With C++14+ you could do the simpler version:
  89. //Tester t = read("Please enter an int and a float:\n");
  90. cout << "t.x = " << t.x << " t.f = " << t.f << endl;
  91. //Using the read_opt function requires C++17 and above
  92. #if __cplusplus >= 201703L
  93. //Example 6 - If you don't want to silently discard errors, use read_opt instead, which will allow you to see if the read was successful
  94. //It returns an optional, which you can check to see if it actually has a value
  95. optional<unsigned int> height_cm = read_opt<unsigned int>("Please enter your height (in cm):\n");
  96. if (!height_cm) {
  97. cout << "You did not enter an unsigned int when asked for your height. Quitting...\n";
  98. exit(EXIT_FAILURE);
  99. }
  100. //I prefer auto for brevity
  101. auto weight_kg = read_opt<unsigned int>("Please enter your weight (in kg):\n");
  102. if (!weight_kg) {
  103. cout << "You did not enter an unsigned int when asked for your weight. Quitting...\n";
  104. exit(EXIT_FAILURE);
  105. }
  106. //Optionals work like pointers, kinda, so you get the value from them like this -
  107. double height_m = *height_cm / 100.0; //Convert from cm to m
  108. //Compute BMI (as a side note, BMI is kind of nonsense)
  109. cout << "Your BMI is: " << *weight_kg / (height_m*height_m) << endl;
  110. //Example 7 - read_opt from a file, count how many bad reads there are
  111. cout << "Opening foo.txt...\n";
  112. ins.clear();
  113. ins.close();
  114. ins.open("foo.txt");
  115. if (!ins) {
  116. cout << "Couldn't open file.\n";
  117. exit(EXIT_FAILURE);
  118. }
  119. int valid_count = 0, invalid_count = 0;
  120. while (true) {
  121. auto num = read_opt<int>(ins);
  122. if (ins.eof()) break;
  123. if (!num) {
  124. invalid_count++;
  125. string s = read<string>(ins);
  126. if (ins.eof()) break;
  127. cout << s << endl;
  128. }
  129. else {
  130. cout << *num << endl;
  131. valid_count++;
  132. }
  133. }
  134. cout << "There were " << valid_count << " valid ints in the file and " << invalid_count << " invalid tokens in the file.\n";
  135. #else
  136. cout << "Skipping read_opt examples due to being compiled with a version of C++ prior to C++17.\n";
  137. #endif
  138. }