├── .github └── workflows │ └── main_ci.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── CMakePresets.json ├── LICENSE ├── README.md ├── benchmark ├── CMakeLists.txt ├── benchmark.h ├── chapter_01_math │ ├── CMakeLists.txt │ ├── benchmark.h │ ├── problem_008_armstrong_numbers.cpp │ ├── problem_008_armstrong_numbers.h │ ├── problem_011_converting_numerical_values_to_roman.cpp │ ├── problem_011_converting_numerical_values_to_roman.h │ ├── problem_012_longest_collatz_sequence.cpp │ └── problem_012_longest_collatz_sequence.h ├── chapter_07_concurrency │ ├── CMakeLists.txt │ ├── benchmark.h │ ├── parallel_minmax.h │ ├── problem_061_parallel_transform_algorithm.cpp │ ├── problem_061_parallel_transform_algorithm.h │ ├── problem_062_parallel_minmax_with_threads.cpp │ ├── problem_062_parallel_minmax_with_threads.h │ ├── problem_063_parallel_minmax_with_async.cpp │ ├── problem_063_parallel_minmax_with_async.h │ ├── problem_064_parallel_sort_algorithm.cpp │ └── problem_064_parallel_sort_algorithm.h └── main.cpp ├── include └── the_modern_c++_challenge │ ├── chapter_01_math │ ├── digits.h │ ├── math.h │ ├── problem_001_sum_of_naturals_divisible_by_3_or_5.h │ ├── problem_002_greatest_common_divisor.h │ ├── problem_003_least_common_multiple.h │ ├── problem_004_largest_prime_smaller_than_given_number.h │ ├── problem_005_sexy_prime_pairs.h │ ├── problem_006_abundant_numbers.h │ ├── problem_007_amicable_numbers.h │ ├── problem_008_armstrong_numbers.h │ ├── problem_009_prime_factors.h │ ├── problem_010_gray_code.h │ ├── problem_011_converting_numerical_values_to_roman.h │ ├── problem_012_longest_collatz_sequence.h │ ├── problem_013_computing_the_value_of_pi.h │ ├── problem_014_validating_isbns.h │ ├── problems.h │ └── roman.h │ ├── chapter_02_language_features │ ├── array_2d.h │ ├── ipv4.h │ ├── ipv4_range.h │ ├── problem_015_ipv4_data_type.h │ ├── problem_016_enumerating_ipv4_addresses_in_a_range.h │ ├── problem_017_array_2d.h │ ├── problem_018_variadic_minimum_function.h │ ├── problem_019_adding_a_range_of_values_to_a_container.h │ ├── problem_020_contains_any_all_or_none_from_a_range.h │ ├── problem_021_system_handle_wrapper.h │ ├── problem_022_temperature_scales_literals.h │ ├── problems.h │ ├── temperature │ │ ├── v1 │ │ │ └── temperature.h │ │ └── v2 │ │ │ └── temperature.h │ └── unique_hdl.h │ ├── chapter_03_strings_and_regular_expressions │ ├── problem_023_binary_to_string_conversion.h │ ├── problem_024_string_to_binary_conversion.h │ ├── problem_025_capitalizing_an_article_title.h │ ├── problem_026_joining_strings_with_delimiter.h │ ├── problem_027_splitting_a_string_into_tokens.h │ ├── problem_028_longest_palindromic_substring.h │ ├── problem_029_license_plate_validation.h │ ├── problem_030_extracting_url_parts.h │ ├── problem_031_transforming_dates_in_strings.h │ ├── problems.h │ └── url.h │ ├── chapter_04_streams_and_filesystems │ ├── logger.h │ ├── problem_032_pascal_triangle.h │ ├── problem_033_tabular_printing_of_a_list_of_processes.h │ ├── problem_034_removing_empty_lines_from_a_text_file.h │ ├── problem_035_computing_the_size_of_a_directory.h │ ├── problem_036_deleting_files_older_than_a_given_date.h │ ├── problem_037_regex_find_files_in_a_directory.h │ ├── problem_038_temporary_log_files.h │ └── problems.h │ ├── chapter_05_date_and_time │ ├── problem_039_measuring_function_execution_time.h │ ├── problem_040_number_of_days_between_two_dates.h │ ├── problem_041_day_of_the_week.h │ ├── problem_042_day_and_week_of_the_year.h │ ├── problem_043_meeting_time_for_multiple_time_zones.h │ ├── problem_044_monthly_calendar.h │ └── problems.h │ ├── chapter_06_algorithms_and_data_structures │ ├── circular_buffer.h │ ├── double_buffer.h │ ├── graph.h │ ├── phone_numbers.h │ ├── priority_queue.h │ ├── problem_045_priority_queue.h │ ├── problem_046_circular_buffer.h │ ├── problem_047_double_buffer.h │ ├── problem_048_most_frequent_element_in_a_range.h │ ├── problem_049_text_histogram.h │ ├── problem_050_filtering_a_list_of_phone_numbers.h │ ├── problem_051_transforming_a_list_of_phone_numbers.h │ ├── problem_052_generating_all_the_permutations_of_a_string.h │ ├── problem_053_average_rating_of_movies.h │ ├── problem_054_pairwise_algorithm.h │ ├── problem_055_zip_algorithm.h │ ├── problem_056_select_algorithm.h │ ├── problem_057_quicksort.h │ ├── problem_058_shortest_path_between_two_nodes.h │ ├── problem_059_weasel_program.h │ ├── problem_060_game_of_life.h │ └── problems.h │ ├── chapter_07_concurrency │ ├── logger.h │ ├── problem_061_parallel_transform_algorithm.h │ ├── problem_062_parallel_minmax_with_threads.h │ ├── problem_063_parallel_minmax_with_async.h │ ├── problem_064_parallel_sort_algorithm.h │ ├── problem_065_thread_safe_logging.h │ ├── problem_066_customer_service_system.h │ ├── problems.h │ └── quicksort.h │ ├── chapter_08_design_patterns │ ├── problem_067_validating_passwords.h │ ├── problem_068_generating_random_passwords.h │ ├── problem_069_generating_social_security_numbers.h │ ├── problem_070_approval_system.h │ ├── problem_071_observable_vector_container.h │ ├── problem_072_computing_order_price_with_discounts.h │ └── problems.h │ ├── chapter_09_data_serialization │ ├── json │ │ └── movies.h │ ├── movies.h │ ├── movies │ │ └── samples.h │ ├── pdf │ │ ├── doc.h │ │ ├── image_list_layouter.h │ │ ├── images_doc.h │ │ ├── layouter.h │ │ ├── movies_doc.h │ │ ├── pdf_writer_wrapper.h │ │ └── text_list_layouter.h │ ├── problem_073_xml_serialization.h │ ├── problem_074_using_xpath.h │ ├── problem_075_json_serialization.h │ ├── problem_076_json_deserialization.h │ ├── problem_077_printing_a_list_of_movies_to_a_pdf.h │ ├── problem_078_creating_a_pdf_from_a_collection_of_images.h │ ├── problems.h │ └── xml │ │ ├── movies.h │ │ └── pugixml_wrapper.h │ ├── chapter_10_archives_images_and_databases │ ├── command_line │ │ └── movies.h │ ├── console │ │ └── movies.h │ ├── ean_13 │ │ ├── barcode.h │ │ └── barcode_png_generator.h │ ├── file │ │ └── movies.h │ ├── png │ │ └── png_writer_wrapper.h │ ├── problem_079_finding_files_in_a_zip_archive.h │ ├── problem_080_zip_compression.h │ ├── problem_081_zip_compression_with_password.h │ ├── problem_082_national_flag_png.h │ ├── problem_083_verification_text_png.h │ ├── problem_084_ean_13_barcode_generator.h │ ├── problem_085_reading_from_an_sqlite_db.h │ ├── problem_086_inserting_into_an_sqlite_db.h │ ├── problem_087_handling_images_in_an_sqlite_db.h │ ├── problems.h │ ├── sql │ │ └── movies.h │ └── zip │ │ └── zip_lib_wrapper.h │ ├── chapter_11_cryptography │ ├── base64.h │ ├── caesar.h │ ├── crypt.h │ ├── problem_088_caesar_cipher.h │ ├── problem_089_vigenere_cipher.h │ ├── problem_090_base64_encoding.h │ ├── problem_091_validating_user_credentials.h │ ├── problem_092_computing_file_hashes.h │ ├── problem_093_aes_encryption.h │ ├── problem_094_file_signing.h │ ├── problems.h │ └── vigenere.h │ ├── chapter_12_networking_and_services │ ├── bitcoin.h │ ├── bitcoin │ │ ├── connection.h │ │ └── samples.h │ ├── face_detection.h │ ├── face_detection │ │ └── samples.h │ ├── faces.h │ ├── fizz_buzz.h │ ├── imap │ │ └── connection.h │ ├── json │ │ ├── bitcoin.h │ │ └── faces.h │ ├── problem_095_finding_the_ip_address_of_a_host.h │ ├── problem_096_fizz_buzz_client_server_application.h │ ├── problem_097_bitcoin_exchange_rates.h │ ├── problem_098_fetching_emails_using_imap.h │ ├── problem_099_translating_text.h │ ├── problem_100_detecting_faces_in_a_picture.h │ ├── problems.h │ ├── tcp │ │ ├── connection.h │ │ └── resolver.h │ ├── text_translation.h │ └── text_translation │ │ └── samples.h │ ├── console.h │ ├── env.h │ └── timer.h ├── res ├── crypto │ ├── private_key.txt │ ├── public_key.txt │ └── signature.txt ├── db │ ├── city.jpg │ ├── new_movies.txt │ └── poster.png ├── faces.jpg ├── fonts │ ├── calibri.ttf │ ├── calibrib.ttf │ ├── calibrii.ttf │ ├── calibril.ttf │ ├── calibrili.ttf │ ├── calibriz.ttf │ └── pala.ttf ├── images │ ├── img_01.png │ ├── img_02.png │ ├── img_03.png │ ├── img_04.png │ ├── img_05.png │ ├── img_06.png │ ├── img_07.png │ ├── img_08.png │ ├── img_09.png │ ├── img_10.png │ └── masters │ │ ├── 2407014001944.png │ │ └── romania_flag.png ├── problem_034_input.txt ├── problem_034_output.txt ├── sample_file.txt ├── sample_folder.zip ├── sample_folder │ ├── dilbert.jpg │ ├── guinness.jpg │ ├── john_mccarthy.jpg │ ├── multi_page_2.pdf │ ├── multi_page_3.docx │ └── sample_subfolder └── sample_subfolder │ └── use_your_illussion_ii.jpg ├── src ├── CMakeLists.txt ├── chapter_01_math │ ├── CMakeLists.txt │ ├── problem_001_sum_of_naturals_divisible_by_3_or_5.cpp │ ├── problem_002_greatest_common_divisor.cpp │ ├── problem_003_least_common_multiple.cpp │ ├── problem_004_largest_prime_smaller_than_given_number.cpp │ ├── problem_005_sexy_prime_pairs.cpp │ ├── problem_006_abundant_numbers.cpp │ ├── problem_007_amicable_numbers.cpp │ ├── problem_008_armstrong_numbers.cpp │ ├── problem_009_prime_factors.cpp │ ├── problem_010_gray_code.cpp │ ├── problem_011_converting_numerical_values_to_roman.cpp │ ├── problem_012_longest_collatz_sequence.cpp │ ├── problem_013_computing_the_value_of_pi.cpp │ └── problem_014_validating_isbns.cpp ├── chapter_02_language_features │ ├── CMakeLists.txt │ ├── problem_015_ipv4_data_type.cpp │ ├── problem_016_enumerating_ipv4_addresses_in_a_range.cpp │ ├── problem_017_array_2d.cpp │ ├── problem_018_variadic_minimum_function.cpp │ ├── problem_019_adding_a_range_of_values_to_a_container.cpp │ ├── problem_020_contains_any_all_or_none_from_a_range.cpp │ ├── problem_021_system_handle_wrapper.cpp │ └── problem_022_temperature_scales_literals.cpp ├── chapter_03_strings_and_regular_expressions │ ├── CMakeLists.txt │ ├── problem_023_binary_to_string_conversion.cpp │ ├── problem_024_string_to_binary_conversion.cpp │ ├── problem_025_capitalizing_an_article_title.cpp │ ├── problem_026_joining_strings_with_delimiter.cpp │ ├── problem_027_splitting_a_string_into_tokens.cpp │ ├── problem_028_longest_palindromic_substring.cpp │ ├── problem_029_license_plate_validation.cpp │ ├── problem_030_extracting_url_parts.cpp │ └── problem_031_transforming_dates_in_strings.cpp ├── chapter_04_streams_and_filesystems │ ├── CMakeLists.txt │ ├── problem_032_pascal_triangle.cpp │ ├── problem_033_tabular_printing_of_a_list_of_processes.cpp │ ├── problem_034_removing_empty_lines_from_a_text_file.cpp │ ├── problem_035_computing_the_size_of_a_directory.cpp │ ├── problem_036_deleting_files_older_than_a_given_date.cpp │ ├── problem_037_regex_find_files_in_a_directory.cpp │ └── problem_038_temporary_log_files.cpp ├── chapter_05_date_and_time │ ├── CMakeLists.txt │ ├── problem_039_measuring_function_execution_time.cpp │ ├── problem_040_number_of_days_between_two_dates.cpp │ ├── problem_041_day_of_the_week.cpp │ ├── problem_042_day_and_week_of_the_year.cpp │ ├── problem_043_meeting_time_for_multiple_time_zones.cpp │ └── problem_044_monthly_calendar.cpp ├── chapter_06_algorithms_and_data_structures │ ├── CMakeLists.txt │ ├── problem_045_priority_queue.cpp │ ├── problem_046_circular_buffer.cpp │ ├── problem_047_double_buffer.cpp │ ├── problem_048_most_frequent_element_in_a_range.cpp │ ├── problem_049_text_histogram.cpp │ ├── problem_050_filtering_a_list_of_phone_numbers.cpp │ ├── problem_051_transforming_a_list_of_phone_numbers.cpp │ ├── problem_052_generating_all_the_permutations_of_a_string.cpp │ ├── problem_053_average_rating_of_movies.cpp │ ├── problem_054_pairwise_algorithm.cpp │ ├── problem_055_zip_algorithm.cpp │ ├── problem_056_select_algorithm.cpp │ ├── problem_057_quicksort.cpp │ ├── problem_058_shortest_path_between_two_nodes.cpp │ ├── problem_059_weasel_program.cpp │ └── problem_060_game_of_life.cpp ├── chapter_07_concurrency │ ├── CMakeLists.txt │ ├── parallel_minmax.h │ ├── problem_061_parallel_transform_algorithm.cpp │ ├── problem_062_parallel_minmax_with_threads.cpp │ ├── problem_063_parallel_minmax_with_async.cpp │ ├── problem_064_parallel_sort_algorithm.cpp │ ├── problem_065_thread_safe_logging.cpp │ └── problem_066_customer_service_system.cpp ├── chapter_08_design_patterns │ ├── CMakeLists.txt │ ├── problem_067_validating_passwords.cpp │ ├── problem_068_generating_random_passwords.cpp │ ├── problem_069_generating_social_security_numbers.cpp │ ├── problem_070_approval_system.cpp │ ├── problem_071_observable_vector_container.cpp │ └── problem_072_computing_order_price_with_discounts.cpp ├── chapter_09_data_serialization │ ├── CMakeLists.txt │ ├── problem_073_xml_serialization.cpp │ ├── problem_074_using_xpath.cpp │ ├── problem_075_json_serialization.cpp │ ├── problem_076_json_deserialization.cpp │ ├── problem_077_printing_a_list_of_movies_to_a_pdf.cpp │ └── problem_078_creating_a_pdf_from_a_collection_of_images.cpp ├── chapter_10_archives_images_and_databases │ ├── CMakeLists.txt │ ├── problem_079_finding_files_in_a_zip_archive.cpp │ ├── problem_080_zip_compression.cpp │ ├── problem_081_zip_compression_with_password.cpp │ ├── problem_082_national_flag_png.cpp │ ├── problem_083_verification_text_png.cpp │ ├── problem_084_ean_13_barcode_generator.cpp │ ├── problem_085_reading_from_an_sqlite_db.cpp │ ├── problem_086_inserting_into_an_sqlite_db.cpp │ └── problem_087_handling_images_in_an_sqlite_db.cpp ├── chapter_11_cryptography │ ├── CMakeLists.txt │ ├── problem_088_caesar_cipher.cpp │ ├── problem_089_vigenere_cipher.cpp │ ├── problem_090_base64_encoding.cpp │ ├── problem_091_validating_user_credentials.cpp │ ├── problem_092_computing_file_hashes.cpp │ ├── problem_093_aes_encryption.cpp │ ├── problem_094_file_signing.cpp │ └── vigenere.cpp ├── chapter_12_networking_and_services │ ├── CMakeLists.txt │ ├── problem_095_finding_the_ip_address_of_a_host.cpp │ ├── problem_096_fizz_buzz_client_server_application.cpp │ ├── problem_097_bitcoin_exchange_rates.cpp │ ├── problem_098_fetching_emails_using_imap.cpp │ ├── problem_099_translating_text.cpp │ └── problem_100_detecting_faces_in_a_picture.cpp ├── main.cpp └── problems.h ├── test ├── CMakeLists.txt ├── chapter_01_math │ ├── CMakeLists.txt │ ├── digits.cpp │ ├── math.cpp │ ├── problem_001_sum_of_naturals_divisible_by_3_or_5.cpp │ ├── problem_002_greatest_common_divisor.cpp │ ├── problem_003_least_common_multiple.cpp │ ├── problem_004_largest_prime_smaller_than_given_number.cpp │ ├── problem_005_sexy_prime_pairs.cpp │ ├── problem_006_abundant_numbers.cpp │ ├── problem_007_amicable_numbers.cpp │ ├── problem_008_armstrong_numbers.cpp │ ├── problem_009_prime_factors.cpp │ ├── problem_010_gray_code.cpp │ ├── problem_011_converting_numerical_values_to_roman.cpp │ ├── problem_012_longest_collatz_sequence.cpp │ ├── problem_013_computing_the_value_of_pi.cpp │ ├── problem_014_validating_isbns.cpp │ └── roman.cpp ├── chapter_02_language_features │ ├── CMakeLists.txt │ ├── array_2d.cpp │ ├── ipv4.cpp │ ├── ipv4_range.cpp │ ├── problem_015_ipv4_data_type.cpp │ ├── problem_016_enumerating_ipv4_addresses_in_a_range.cpp │ ├── problem_017_array_2d.cpp │ ├── problem_018_variadic_minimum_function.cpp │ ├── problem_019_adding_a_range_of_values_to_a_container.cpp │ ├── problem_020_contains_any_all_or_none_from_a_range.cpp │ ├── problem_021_system_handle_wrapper.cpp │ ├── problem_022_temperature_scales_literals.cpp │ ├── temperature │ │ ├── CMakeLists.txt │ │ ├── v1 │ │ │ ├── CMakeLists.txt │ │ │ └── temperature.cpp │ │ └── v2 │ │ │ ├── CMakeLists.txt │ │ │ └── temperature.cpp │ └── unique_hdl.cpp ├── chapter_03_strings_and_regular_expressions │ ├── CMakeLists.txt │ ├── problem_023_binary_to_string_conversion.cpp │ ├── problem_024_string_to_binary_conversion.cpp │ ├── problem_025_capitalizing_an_article_title.cpp │ ├── problem_026_joining_strings_with_delimiter.cpp │ ├── problem_027_splitting_a_string_into_tokens.cpp │ ├── problem_028_longest_palindromic_substring.cpp │ ├── problem_029_license_plate_validation.cpp │ ├── problem_030_extracting_url_parts.cpp │ ├── problem_031_transforming_dates_in_strings.cpp │ └── url.cpp ├── chapter_04_streams_and_filesystems │ ├── CMakeLists.txt │ ├── logger.cpp │ ├── problem_032_pascal_triangle.cpp │ ├── problem_033_tabular_printing_of_a_list_of_processes.cpp │ ├── problem_034_removing_empty_lines_from_a_text_file.cpp │ ├── problem_035_computing_the_size_of_a_directory.cpp │ ├── problem_036_deleting_files_older_than_a_given_date.cpp │ ├── problem_037_regex_find_files_in_a_directory.cpp │ └── problem_038_temporary_log_files.cpp ├── chapter_05_date_and_time │ ├── CMakeLists.txt │ ├── problem_039_measuring_function_execution_time.cpp │ ├── problem_040_number_of_days_between_two_dates.cpp │ ├── problem_041_day_of_the_week.cpp │ ├── problem_042_day_and_week_of_the_year.cpp │ ├── problem_043_meeting_time_for_multiple_time_zones.cpp │ └── problem_044_monthly_calendar.cpp ├── chapter_06_algorithms_and_data_structures │ ├── CMakeLists.txt │ ├── circular_buffer.cpp │ ├── double_buffer.cpp │ ├── graph.cpp │ ├── phone_numbers.cpp │ ├── priority_queue.cpp │ ├── problem_045_priority_queue.cpp │ ├── problem_046_circular_buffer.cpp │ ├── problem_047_double_buffer.cpp │ ├── problem_048_most_frequent_element_in_a_range.cpp │ ├── problem_049_text_histogram.cpp │ ├── problem_050_filtering_a_list_of_phone_numbers.cpp │ ├── problem_051_transforming_a_list_of_phone_numbers.cpp │ ├── problem_052_generating_all_the_permutations_of_a_string.cpp │ ├── problem_053_average_rating_of_movies.cpp │ ├── problem_054_pairwise_algorithm.cpp │ ├── problem_055_zip_algorithm.cpp │ ├── problem_056_select_algorithm.cpp │ ├── problem_057_quicksort.cpp │ ├── problem_058_shortest_path_between_two_nodes.cpp │ ├── problem_059_weasel_program.cpp │ └── problem_060_game_of_life.cpp ├── chapter_07_concurrency │ ├── CMakeLists.txt │ ├── logger.cpp │ ├── problem_061_parallel_transform_algorithm.cpp │ ├── problem_062_parallel_minmax_with_threads.cpp │ ├── problem_063_parallel_minmax_with_async.cpp │ ├── problem_064_parallel_sort_algorithm.cpp │ ├── problem_065_thread_safe_logging.cpp │ ├── problem_066_customer_service_system.cpp │ └── quicksort.cpp ├── chapter_08_design_patterns │ ├── CMakeLists.txt │ ├── problem_067_validating_passwords.cpp │ ├── problem_068_generating_random_passwords.cpp │ ├── problem_069_generating_social_security_numbers.cpp │ ├── problem_070_approval_system.cpp │ ├── problem_071_observable_vector_container.cpp │ └── problem_072_computing_order_price_with_discounts.cpp ├── chapter_09_data_serialization │ ├── CMakeLists.txt │ ├── json │ │ ├── CMakeLists.txt │ │ └── movies.cpp │ ├── movies.cpp │ ├── pdf │ │ ├── CMakeLists.txt │ │ ├── images.cpp │ │ └── movies.cpp │ ├── problem_073_xml_serialization.cpp │ ├── problem_074_using_xpath.cpp │ ├── problem_075_json_serialization.cpp │ ├── problem_076_json_deserialization.cpp │ ├── problem_077_printing_a_list_of_movies_to_a_pdf.cpp │ ├── problem_078_creating_a_pdf_from_a_collection_of_images.cpp │ └── xml │ │ ├── CMakeLists.txt │ │ └── movies.cpp ├── chapter_10_archives_images_and_databases │ ├── CMakeLists.txt │ ├── console │ │ ├── CMakeLists.txt │ │ └── movies.cpp │ ├── ean_13 │ │ ├── CMakeLists.txt │ │ ├── barcode.cpp │ │ └── barcode_png_generator.cpp │ ├── file │ │ ├── CMakeLists.txt │ │ └── movies.cpp │ ├── png │ │ ├── CMakeLists.txt │ │ └── png_writer_wrapper.cpp │ ├── problem_079_finding_files_in_a_zip_archive.cpp │ ├── problem_080_zip_compression.cpp │ ├── problem_081_zip_compression_with_password.cpp │ ├── problem_082_national_flag_png.cpp │ ├── problem_083_verification_text_png.cpp │ ├── problem_084_ean_13_barcode_generator.cpp │ ├── problem_085_reading_from_an_sqlite_db.cpp │ ├── problem_086_inserting_into_an_sqlite_db.cpp │ ├── problem_087_handling_images_in_an_sqlite_db.cpp │ ├── sql │ │ ├── CMakeLists.txt │ │ └── movies.cpp │ └── zip │ │ ├── CMakeLists.txt │ │ └── zip_lib_wrapper.cpp ├── chapter_11_cryptography │ ├── CMakeLists.txt │ ├── base64.cpp │ ├── caesar.cpp │ ├── problem_088_caesar_cipher.cpp │ ├── problem_089_vigenere_cipher.cpp │ ├── problem_090_base64_encoding.cpp │ ├── problem_091_validating_user_credentials.cpp │ ├── problem_092_computing_file_hashes.cpp │ ├── problem_093_aes_encryption.cpp │ ├── problem_094_file_signing.cpp │ └── vigenere.cpp ├── chapter_12_networking_and_services │ ├── CMakeLists.txt │ ├── bitcoin.cpp │ ├── bitcoin │ │ ├── CMakeLists.txt │ │ ├── connection.cpp │ │ ├── mock.h │ │ └── samples.h │ ├── face_detection.cpp │ ├── face_detection │ │ ├── mock.h │ │ └── samples.h │ ├── faces.cpp │ ├── fizz_buzz.cpp │ ├── imap │ │ ├── CMakeLists.txt │ │ ├── connection.cpp │ │ ├── mock.h │ │ └── samples.h │ ├── json │ │ ├── CMakeLists.txt │ │ ├── bitcoin.cpp │ │ └── faces.cpp │ ├── problem_095_finding_the_ip_address_of_a_host.cpp │ ├── problem_096_fizz_buzz_client_server_application.cpp │ ├── problem_097_bitcoin_exchange_rates.cpp │ ├── problem_098_fetching_emails_using_imap.cpp │ ├── problem_099_translating_text.cpp │ ├── problem_100_detecting_faces_in_a_picture.cpp │ ├── tcp │ │ └── mock.h │ ├── text_translation.cpp │ └── text_translation │ │ ├── mock.h │ │ └── samples.h ├── console │ └── fake.h ├── main.cpp └── timer │ └── fake.h └── vcpkg.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Others 35 | /.idea 36 | /.vs 37 | /CMakeSettings.json 38 | /out/build 39 | /Testing/Temporary 40 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vcpkg"] 2 | path = vcpkg 3 | url = https://github.com/microsoft/vcpkg.git 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 rturrado 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /benchmark/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Packages 2 | include(FetchContent) 3 | set(BENCHMARK_ENABLE_TESTING NO) 4 | FetchContent_Declare(googlebenchmark 5 | GIT_REPOSITORY https://github.com/google/benchmark.git 6 | GIT_TAG "60b16f11a30146ac825b7d99be0b9887c24b254a" 7 | ) 8 | FetchContent_MakeAvailable( 9 | googlebenchmark 10 | ) 11 | find_package(Threads REQUIRED) 12 | 13 | 14 | # Subdirectories 15 | add_subdirectory(chapter_01_math) 16 | add_subdirectory(chapter_07_concurrency) 17 | 18 | 19 | # Benchmark sources 20 | set(benchmark_sources 21 | ${chapter_01_benchmark_sources} 22 | ${chapter_07_benchmark_sources} 23 | ) 24 | 25 | 26 | # Benchmark executable 27 | add_executable(${PROJECT_NAME}_benchmark main.cpp benchmark.h ${benchmark_sources}) 28 | target_compile_features(${PROJECT_NAME}_benchmark PRIVATE cxx_std_23) 29 | target_link_libraries(${PROJECT_NAME}_benchmark lib_${PROJECT_NAME} benchmark::benchmark Threads::Threads) 30 | if(MSVC) 31 | target_compile_options(${PROJECT_NAME}_benchmark PRIVATE 32 | /W3 /WX /w34996 33 | /D_CONSOLE /DCONSOLE 34 | /D_UNICODE /DUNICODE 35 | /diagnostics:column /EHsc /FC /fp:precise /Gd /GS /MP /sdl /utf-8 /Zc:inline 36 | ) 37 | elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") 38 | target_compile_options(${PROJECT_NAME}_benchmark PRIVATE 39 | -pedantic-errors -Werror -Wall -Wextra 40 | -Wl,-z,defs 41 | -Wno-deprecated 42 | # -Wconversion -Wsign-conversion -Wno-sign-conversion # do not sort flags; order matters 43 | ) 44 | endif() 45 | -------------------------------------------------------------------------------- /benchmark/benchmark.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "chapter_01_math/benchmark.h" 4 | #include "chapter_07_concurrency/benchmark.h" 5 | -------------------------------------------------------------------------------- /benchmark/chapter_01_math/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_01_benchmark_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_008_armstrong_numbers.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_011_converting_numerical_values_to_roman.cpp" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_012_longest_collatz_sequence.cpp" 5 | PARENT_SCOPE 6 | ) 7 | -------------------------------------------------------------------------------- /benchmark/chapter_01_math/benchmark.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "problem_008_armstrong_numbers.h" 4 | #include "problem_011_converting_numerical_values_to_roman.h" 5 | #include "problem_012_longest_collatz_sequence.h" 6 | -------------------------------------------------------------------------------- /benchmark/chapter_01_math/problem_008_armstrong_numbers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void cb_armstrong_numbers_up_to_a_limit(); 4 | -------------------------------------------------------------------------------- /benchmark/chapter_01_math/problem_011_converting_numerical_values_to_roman.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void cb_to_roman(); 4 | -------------------------------------------------------------------------------- /benchmark/chapter_01_math/problem_012_longest_collatz_sequence.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_01_math/problem_012_longest_collatz_sequence.h" 2 | 3 | #include // google benchmark 4 | #include // duration, milli 5 | #include 6 | #include 7 | #include // function_timer 8 | 9 | using namespace tmcppc::problem_12; 10 | 11 | 12 | constinit const size_t limit{ 1'000'000 }; 13 | 14 | 15 | // Custom benchmark 16 | // 17 | void cb_get_longest_collatz_sequence() { 18 | using namespace rtc::timer; 19 | 20 | fmt::print("[get_longest_collatz_sequence custom benchmark]\n\n"); 21 | fmt::print("Calling get_longest_collatz_sequence({}):\n", limit); 22 | auto t1 = function_timer<>::duration( 23 | []() { 24 | get_longest_collatz_sequence_v1(limit); 25 | }); 26 | fmt::print("\tv1: {}\n", std::chrono::duration(t1)); 27 | 28 | auto t2 = function_timer<>::duration( 29 | []() { 30 | get_longest_collatz_sequence_v2(limit); 31 | }); 32 | fmt::print("\tv2: {}\n\n", std::chrono::duration(t2)); 33 | } 34 | 35 | 36 | // Google benchmark 37 | // 38 | static void gb_get_longest_collatz_sequence_v1(benchmark::State& state) { 39 | while (state.KeepRunning()) { 40 | get_longest_collatz_sequence_v1(limit); 41 | } 42 | } 43 | 44 | static void gb_get_longest_collatz_sequence_v2(benchmark::State& state) { 45 | while (state.KeepRunning()) { 46 | get_longest_collatz_sequence_v2(limit); 47 | } 48 | } 49 | 50 | BENCHMARK(gb_get_longest_collatz_sequence_v1); 51 | BENCHMARK(gb_get_longest_collatz_sequence_v2); 52 | -------------------------------------------------------------------------------- /benchmark/chapter_01_math/problem_012_longest_collatz_sequence.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void cb_get_longest_collatz_sequence(); 4 | -------------------------------------------------------------------------------- /benchmark/chapter_07_concurrency/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_07_benchmark_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_061_parallel_transform_algorithm.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_062_parallel_minmax_with_threads.cpp" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_063_parallel_minmax_with_async.cpp" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_064_parallel_sort_algorithm.cpp" 6 | PARENT_SCOPE 7 | ) 8 | -------------------------------------------------------------------------------- /benchmark/chapter_07_concurrency/benchmark.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "problem_061_parallel_transform_algorithm.h" 4 | #include "problem_062_parallel_minmax_with_threads.h" 5 | #include "problem_063_parallel_minmax_with_async.h" 6 | #include "problem_064_parallel_sort_algorithm.h" 7 | -------------------------------------------------------------------------------- /benchmark/chapter_07_concurrency/problem_061_parallel_transform_algorithm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void cb_parallel_transform(); 4 | -------------------------------------------------------------------------------- /benchmark/chapter_07_concurrency/problem_062_parallel_minmax_with_threads.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void cb_parallel_minmax_with_threads(); 4 | -------------------------------------------------------------------------------- /benchmark/chapter_07_concurrency/problem_063_parallel_minmax_with_async.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_07_concurrency/problem_063_parallel_minmax_with_async.h" 2 | #include "parallel_minmax.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | // Custom benchmark 10 | // 11 | void cb_parallel_minmax_with_async() { 12 | fmt::print("[parallel_minmax_with_async custom benchmark]\n\n"); 13 | 14 | cb_parallel_minmax( 15 | [](auto&& rng, auto thread_pool_size, auto block_size) { 16 | return tmcppc::algorithm::async::parallel_min(rng, thread_pool_size, block_size); 17 | }, 18 | [](auto&& rng, auto thread_pool_size, auto block_size) { 19 | return tmcppc::algorithm::async::parallel_max(rng, thread_pool_size, block_size); 20 | } 21 | ); 22 | } 23 | 24 | 25 | // Google benchmark 26 | // 27 | BENCHMARK_CAPTURE(gb_parallel_minmax_int, parallel_min_with_async_int, 28 | [](auto&& rng, auto thread_pool_size, auto block_size) { 29 | return tmcppc::algorithm::async::parallel_min(rng, thread_pool_size, block_size); 30 | } 31 | )->ArgsProduct({ {4, 8, 16}, {1'000, 10'000, 100'000} }); 32 | BENCHMARK_CAPTURE(gb_parallel_minmax_int64_t, parallel_min_with_async_int64_t, 33 | [](auto&& rng, auto thread_pool_size, auto block_size) { 34 | return tmcppc::algorithm::async::parallel_min(rng, thread_pool_size, block_size); 35 | } 36 | )->ArgsProduct({ { 4, 8, 16 }, { 1'000, 10'000, 100'000 } }); 37 | -------------------------------------------------------------------------------- /benchmark/chapter_07_concurrency/problem_063_parallel_minmax_with_async.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void cb_parallel_minmax_with_async(); 4 | -------------------------------------------------------------------------------- /benchmark/chapter_07_concurrency/problem_064_parallel_sort_algorithm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void cb_sort_algorithm(); 4 | -------------------------------------------------------------------------------- /benchmark/main.cpp: -------------------------------------------------------------------------------- 1 | #include "benchmark.h" // custom benchmark 2 | 3 | #include // google benchmark 4 | #include 5 | 6 | 7 | void run_custom_benchmarks() { 8 | cb_armstrong_numbers_up_to_a_limit(); // problem 8 9 | cb_to_roman(); // problem 11 10 | cb_get_longest_collatz_sequence(); // problem 12 11 | cb_parallel_transform(); // problem 61 12 | cb_parallel_minmax_with_threads(); // problem 62 13 | cb_parallel_minmax_with_async(); // problem 63 14 | cb_sort_algorithm(); // problem 64 15 | } 16 | 17 | 18 | void run_google_benchmarks() { 19 | fmt::print("[google benchmark]\n\n"); 20 | ::benchmark::RunSpecifiedBenchmarks(); 21 | } 22 | 23 | 24 | int main() { 25 | run_custom_benchmarks(); 26 | fmt::print("\n"); 27 | run_google_benchmarks(); 28 | } 29 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_01_math/problem_001_sum_of_naturals_divisible_by_3_or_5.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | namespace tmcppc::problem_1 { 8 | std::vector naturals_divisible_by_3_or_5_up_to_limit_v1(size_t limit); 9 | std::vector naturals_divisible_by_3_or_5_up_to_limit_v2(size_t limit); 10 | } // namespace tmcppc::problem_1 11 | 12 | 13 | void problem_1_main(std::istream& is, std::ostream& os); 14 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_01_math/problem_002_greatest_common_divisor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | namespace tmcppc::problem_2 { 7 | int gcd(int m, int n); 8 | } // namespace tmcppc::problem_2 9 | 10 | 11 | void problem_2_main(std::istream& is, std::ostream& os); 12 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_01_math/problem_003_least_common_multiple.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | namespace tmcppc::problem_3 { 8 | long lcm(std::vector v); 9 | } // namespace tmcppc::problem_3 10 | 11 | 12 | void problem_3_main(std::istream& is, std::ostream& os); 13 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_01_math/problem_004_largest_prime_smaller_than_given_number.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | namespace tmcppc::problem_4 { 7 | size_t biggest_prime_smaller_than(size_t n); 8 | } // namespace tmcppc::problem_4 9 | 10 | 11 | void problem_4_main(std::istream& is, std::ostream& os); 12 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_01_math/problem_005_sexy_prime_pairs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include // pair 5 | #include 6 | 7 | 8 | namespace tmcppc::problem_5 { 9 | std::vector> sexy_prime_pairs_up_to(size_t limit); 10 | } // namespace tmcppc::problem_5 11 | 12 | 13 | void problem_5_main(std::istream& is, std::ostream& os); 14 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_01_math/problem_006_abundant_numbers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | namespace tmcppc::problem_6 { 8 | struct AbundantNumberResult { 9 | size_t number{}; 10 | size_t abundance{}; 11 | std::vector divisors{}; 12 | 13 | auto operator<=>(const AbundantNumberResult& other) const = default; 14 | }; 15 | 16 | std::vector abundant_numbers_up_to(size_t limit); 17 | } // namespace tmcppc::problem_6 18 | 19 | 20 | void problem_6_main(std::istream& is, std::ostream& os); 21 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_01_math/problem_007_amicable_numbers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include // pair 5 | #include 6 | 7 | 8 | namespace tmcppc::problem_7 { 9 | std::vector> amicable_numbers_up_to(size_t limit); 10 | } // namespace tmcppc::problem_7 11 | 12 | 13 | void problem_7_main(std::ostream& os); 14 | 15 | void playing_with_tmp(std::ostream& os); 16 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_01_math/problem_008_armstrong_numbers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | namespace tmcppc::problem_8 { 8 | std::vector armstrong_numbers_up_to_a_limit_v1(size_t n); 9 | std::vector armstrong_numbers_up_to_a_limit_v2(size_t n); 10 | std::vector armstrong_numbers_up_to_a_limit_v3(int n); 11 | 12 | std::vector armstrong_numbers_with_three_digits(); 13 | } // namespace tmcppc::problem_8 14 | 15 | 16 | void problem_8_main(std::ostream& os); 17 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_01_math/problem_009_prime_factors.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_9_main(std::istream& is, std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_01_math/problem_010_gray_code.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | namespace tmcppc::problem_10 { 7 | size_t binary_to_gray(size_t binary); 8 | size_t gray_to_binary(size_t gray); 9 | } // namespace tmcppc::problem_10 10 | 11 | 12 | void problem_10_main(std::ostream& os); 13 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_01_math/problem_011_converting_numerical_values_to_roman.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_11_main(std::istream& is, std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_01_math/problem_012_longest_collatz_sequence.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include // pair 5 | #include 6 | 7 | 8 | namespace tmcppc::problem_12 { 9 | size_t get_collatz_sequence_size(size_t n); 10 | std::vector get_collatz_sequence(size_t n); 11 | 12 | std::pair get_longest_collatz_sequence_v1(size_t limit); 13 | std::pair get_longest_collatz_sequence_v2(size_t limit); 14 | } // namespace tmcppc::problem_12 15 | 16 | 17 | void problem_12_main(std::ostream& os); 18 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_01_math/problem_013_computing_the_value_of_pi.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | namespace tmcppc::problem_13 { 7 | double compute_pi(size_t number_of_iterations); 8 | } // namespace tmcppc::problem_13 9 | 10 | void problem_13_main(std::ostream& os); 11 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_01_math/problem_014_validating_isbns.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "console.h" 4 | 5 | #include 6 | #include 7 | 8 | 9 | namespace tmcppc::problem_14 { 10 | std::string read_n_digit_isbn(std::istream& is, std::ostream& os, const tmcppc::system::console& console, size_t n); 11 | 12 | bool validate_10_digit_isbn(const std::string& str); 13 | bool validate_13_digit_isbn(const std::string& str); 14 | } // namespace tmcppc::problem_14 15 | 16 | 17 | void problem_14_main(std::istream& is, std::ostream& os, const tmcppc::system::console& console); 18 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_01_math/problems.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "problem_001_sum_of_naturals_divisible_by_3_or_5.h" 4 | #include "problem_002_greatest_common_divisor.h" 5 | #include "problem_003_least_common_multiple.h" 6 | #include "problem_004_largest_prime_smaller_than_given_number.h" 7 | #include "problem_005_sexy_prime_pairs.h" 8 | #include "problem_006_abundant_numbers.h" 9 | #include "problem_007_amicable_numbers.h" 10 | #include "problem_008_armstrong_numbers.h" 11 | #include "problem_009_prime_factors.h" 12 | #include "problem_010_gray_code.h" 13 | #include "problem_011_converting_numerical_values_to_roman.h" 14 | #include "problem_012_longest_collatz_sequence.h" 15 | #include "problem_013_computing_the_value_of_pi.h" 16 | #include "problem_014_validating_isbns.h" 17 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_02_language_features/problem_015_ipv4_data_type.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_15_main(std::istream& is, std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_02_language_features/problem_016_enumerating_ipv4_addresses_in_a_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "console.h" 4 | 5 | #include 6 | 7 | 8 | void problem_16_main(std::istream& is, std::ostream& os, const tmcppc::system::console& console); 9 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_02_language_features/problem_017_array_2d.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_17_main(std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_02_language_features/problem_019_adding_a_range_of_values_to_a_container.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include // forward 5 | 6 | 7 | namespace tmcppc::problem_19 { 8 | template 9 | concept ContainerWithPushBack = requires (C c, T t) { c.push_back(t); }; 10 | 11 | template 12 | void push_back_list(ContainerWithPushBack& c, T&& t) { 13 | c.push_back(std::forward(t)); 14 | } 15 | 16 | template 17 | void push_back_list(ContainerWithPushBack& c, T&& t, Args&&... args) { 18 | c.push_back(std::forward(t)); 19 | push_back_list(c, std::forward(args)...); 20 | } 21 | 22 | // Using a fold expression as in the book 23 | template 24 | void push_back_list_v2(ContainerWithPushBack& c, Args... args) { 25 | (c.push_back(args), ...); 26 | } 27 | } // namespace tmcppc::problem_19 28 | 29 | 30 | void problem_19_main(std::ostream& os); 31 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_02_language_features/problem_020_contains_any_all_or_none_from_a_range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // find 4 | #include 5 | #include 6 | 7 | 8 | namespace tmcppc::problem_20 { 9 | template 10 | bool contains_any(R&& r, Args&&... args) { 11 | return (... or (std::ranges::find(r, std::forward(args)) != r.end())); 12 | } 13 | 14 | template 15 | bool contains_all(R&& r, Args&&... args) { 16 | return (... and (std::ranges::find(r, std::forward(args)) != r.end())); 17 | } 18 | 19 | template 20 | bool contains_none(R&& r, Args&&... args) { 21 | return (... and (std::ranges::find(r, std::forward(args)) == r.end())); 22 | } 23 | } // namespace tmcppc::problem_20 24 | 25 | 26 | void problem_20_main(std::ostream& os); 27 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_02_language_features/problem_021_system_handle_wrapper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_21_main(std::wostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_02_language_features/problem_022_temperature_scales_literals.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_22_main(std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_02_language_features/problems.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "problem_015_ipv4_data_type.h" 4 | #include "problem_016_enumerating_ipv4_addresses_in_a_range.h" 5 | #include "problem_017_array_2d.h" 6 | #include "problem_018_variadic_minimum_function.h" 7 | #include "problem_019_adding_a_range_of_values_to_a_container.h" 8 | #include "problem_020_contains_any_all_or_none_from_a_range.h" 9 | #include "problem_021_system_handle_wrapper.h" 10 | #include "problem_022_temperature_scales_literals.h" 11 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_03_strings_and_regular_expressions/problem_023_binary_to_string_conversion.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // for_each 4 | #include 5 | #include 6 | #include // ostringstream 7 | #include 8 | #include // is_same_v 9 | 10 | 11 | namespace tmcppc::problem_23 { 12 | template 13 | requires (std::is_same_v) 14 | std::string to_hex_string(const Container& container) { 15 | std::ostringstream oss{}; 16 | std::ranges::for_each(container, [&oss](auto c) { 17 | fmt::print(oss, "{:02x}", static_cast(c)); 18 | }); 19 | return oss.str(); 20 | } 21 | } // namespace tmcppc::problem_23 22 | 23 | 24 | void problem_23_main(std::ostream& os); 25 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_03_strings_and_regular_expressions/problem_024_string_to_binary_conversion.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include // runtime_error 7 | #include 8 | #include 9 | 10 | 11 | namespace tmcppc::problem_24 { 12 | struct from_hex_char_error : public std::runtime_error { 13 | explicit from_hex_char_error(char c) : std::runtime_error{ fmt::format("'{}' is not a valid hex char", c) } {} 14 | }; 15 | 16 | struct from_hex_string_parse_error : public std::runtime_error { 17 | explicit from_hex_string_parse_error(const std::string& message) : std::runtime_error{ message } {} 18 | }; 19 | 20 | // Char to uint8_t 21 | uint8_t from_hex_char(char c); 22 | 23 | // Two chars to uint8_t 24 | uint8_t from_hex_chars(char c1, char c2); 25 | 26 | // String of hexadecimal characters to vector of uint8_t's 27 | std::vector from_hex_string(std::string s); 28 | 29 | // String of hexadecimal characters, separated by a given string delimiter, to vector of uint8_t's 30 | std::vector from_hex_string(std::string s, const std::string& delimiter); 31 | } // namespace tmcppc::problem_24 32 | 33 | 34 | void problem_24_main(std::ostream& os); 35 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_03_strings_and_regular_expressions/problem_025_capitalizing_an_article_title.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | namespace tmcppc::problem_25 { 9 | std::string capitalize(std::string_view s); 10 | } // namespace tmcppc::problem_25 11 | 12 | 13 | void problem_25_main(std::ostream& os); 14 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_03_strings_and_regular_expressions/problem_026_joining_strings_with_delimiter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // for_each 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include // is_convertible_v 9 | 10 | 11 | namespace tmcppc::problem_26 { 12 | template 13 | requires std::is_convertible_v 14 | std::string join(const C& c, std::string_view delimiter) { 15 | std::string ret{}; 16 | std::ranges::for_each(c, [first = true, &ret, &delimiter](std::string_view s) mutable { 17 | ret += (first ? "" : delimiter); 18 | first = false; 19 | ret += s; 20 | }); 21 | return ret; 22 | } 23 | } // namespace tmcppc::problem_26 24 | 25 | 26 | void problem_26_main(std::ostream& os); 27 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_03_strings_and_regular_expressions/problem_027_splitting_a_string_into_tokens.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | namespace tmcppc::problem_27 { 9 | std::vector split(const std::string& s, const std::string& delimiters); 10 | } // namespace tmcppc::problem_27 11 | 12 | 13 | void problem_27_main(std::ostream& os); 14 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_03_strings_and_regular_expressions/problem_028_longest_palindromic_substring.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | namespace tmcppc::problem_28 { 8 | bool is_palindrome(std::string_view s); 9 | 10 | std::string_view get_longest_palindromic_substring(std::string_view s); 11 | } // namespace tmcppc::problem_28 12 | 13 | 14 | void problem_28_main(std::ostream& os); 15 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_03_strings_and_regular_expressions/problem_029_license_plate_validation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | namespace tmcppc::problem_29 { 10 | inline const std::regex pattern{ R"([[:upper:]]{3}-[[:upper:]]{2} [[:digit:]]{3,4})" }; 11 | 12 | bool validate_license_plate(const std::string& s); 13 | 14 | std::vector extract_all_license_plates(const std::string& s); 15 | } // namespace tmcppc::problem_29 16 | 17 | 18 | void problem_29_main(std::ostream& os); 19 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_03_strings_and_regular_expressions/problem_030_extracting_url_parts.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_30_main(std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_03_strings_and_regular_expressions/problem_031_transforming_dates_in_strings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | namespace tmcppc::problem_31 { 10 | struct invalid_date_format_error : public std::exception { 11 | explicit invalid_date_format_error(const std::string& date) noexcept { message_ += "\"" + date + "\""; } 12 | [[nodiscard]] const char* what() const noexcept override { return message_.c_str(); } 13 | private: 14 | std::string message_{ "invalid date format: " }; 15 | }; 16 | 17 | std::string format_date_v1(const std::string& s); 18 | 19 | std::string format_date_v2(std::string_view s); 20 | } // namespace tmcppc::problem_31 21 | 22 | 23 | void problem_31_main(std::ostream& os); 24 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_03_strings_and_regular_expressions/problems.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "problem_023_binary_to_string_conversion.h" 4 | #include "problem_024_string_to_binary_conversion.h" 5 | #include "problem_025_capitalizing_an_article_title.h" 6 | #include "problem_026_joining_strings_with_delimiter.h" 7 | #include "problem_027_splitting_a_string_into_tokens.h" 8 | #include "problem_028_longest_palindromic_substring.h" 9 | #include "problem_029_license_plate_validation.h" 10 | #include "problem_030_extracting_url_parts.h" 11 | #include "problem_031_transforming_dates_in_strings.h" 12 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_04_streams_and_filesystems/problem_032_pascal_triangle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // uint32_t 4 | #include 5 | #include 6 | 7 | 8 | namespace tmcppc::problem_32 { 9 | using pascal_triangle_t = std::vector>; 10 | 11 | pascal_triangle_t pascal_triangle(size_t n); 12 | } // namespace tmcppc::problem_32 13 | 14 | void problem_32_main(std::ostream& os); 15 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_04_streams_and_filesystems/problem_034_removing_empty_lines_from_a_text_file.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | namespace tmcppc::problem_34 { 8 | std::filesystem::path remove_empty_lines(std::ostream& os, const std::filesystem::path& in_file_path); 9 | } // namespace tmcppc::problem_34 10 | 11 | 12 | void problem_34_main(std::ostream& os); 13 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_04_streams_and_filesystems/problem_035_computing_the_size_of_a_directory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | namespace tmcppc::problem_35 { 9 | std::uintmax_t directory_size_in_bytes(const std::filesystem::path& in_dir_path, bool follow_symlinks = false); 10 | 11 | std::string directory_size_in_bytes_to_string(uintmax_t n); 12 | } // namespace tmcppc::problem_35 13 | 14 | 15 | void problem_35_main(std::ostream& os); 16 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_04_streams_and_filesystems/problem_037_regex_find_files_in_a_directory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | namespace tmcppc::problem_37 { 10 | std::vector get_directory_entries_matching( 11 | const std::filesystem::path& path, const std::string& pattern_str); 12 | } // namespace tmcppc::problem_37 13 | 14 | 15 | void problem_37_main(std::ostream& os); 16 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_04_streams_and_filesystems/problem_038_temporary_log_files.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_38_main(std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_04_streams_and_filesystems/problems.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "problem_032_pascal_triangle.h" 4 | #include "problem_033_tabular_printing_of_a_list_of_processes.h" 5 | #include "problem_034_removing_empty_lines_from_a_text_file.h" 6 | #include "problem_035_computing_the_size_of_a_directory.h" 7 | #include "problem_036_deleting_files_older_than_a_given_date.h" 8 | #include "problem_037_regex_find_files_in_a_directory.h" 9 | #include "problem_038_temporary_log_files.h" 10 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_05_date_and_time/problem_039_measuring_function_execution_time.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include // invoke 5 | #include 6 | #include 7 | 8 | 9 | namespace tmcppc::problem_39 { 10 | void sort_vector(std::vector& v); 11 | void sort_iota_vector(size_t num_elems, size_t num_reps); 12 | void sort_shuffle_vector(size_t num_elems, size_t num_reps); 13 | 14 | template 15 | Duration measure_time(F&& f, Args&&... args) { 16 | namespace ch = std::chrono; 17 | 18 | ch::steady_clock::time_point start{ ch::steady_clock::now() }; 19 | std::invoke(std::forward(f), std::forward(args)...); 20 | ch::steady_clock::time_point end{ ch::steady_clock::now() }; 21 | 22 | return ch::duration_cast(end - start); 23 | } 24 | } // namespace tmcppc::problem_39 25 | 26 | 27 | void problem_39_main(std::ostream& os); 28 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_05_date_and_time/problem_040_number_of_days_between_two_dates.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | namespace tmcppc::problem_40 { 8 | int difference_in_days(std::chrono::year_month_day start_date, std::chrono::year_month_day end_date); 9 | } // namespace tmcppc::problem_40 10 | 11 | 12 | void problem_40_main(std::ostream& os); 13 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_05_date_and_time/problem_041_day_of_the_week.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | namespace tmcppc::problem_41 { 8 | std::chrono::weekday date_to_weekday(const std::chrono::year_month_day& date); 9 | 10 | unsigned int weekday_to_number(const std::chrono::weekday& wd); 11 | } // namespace tmcppc::problem_41 12 | 13 | 14 | void problem_41_main(std::ostream& os); 15 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_05_date_and_time/problem_042_day_and_week_of_the_year.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | namespace tmcppc::problem_42 { 8 | unsigned int daynum(const std::chrono::year_month_day& date); // starting from 1 9 | 10 | unsigned int weeknum(const std::chrono::year_month_day& date); // starting from 1 11 | } // namespace tmcppc::problem_42 12 | 13 | 14 | void problem_42_main(std::ostream& os); 15 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_05_date_and_time/problem_043_meeting_time_for_multiple_time_zones.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | namespace tmcppc::problem_43 { 9 | using vector_of_participants_and_time_zones = std::vector>; 10 | 11 | // This solution is based on the video Welcome To The Time Zone, 12 | // by Howard Hinnant at CppCon 2016: https://youtu.be/Vwd3pduVGKY?t=968 13 | template 14 | void display_local_meeting_times( 15 | std::ostream& os, 16 | const std::chrono::zoned_time& meeting_zt, 17 | const vector_of_participants_and_time_zones& participants) { 18 | 19 | os << "Local meeting times:\n"; 20 | for (size_t i{ 0 }; i < participants.size(); ++i) { 21 | const auto& [p, tz]{ participants[i] }; 22 | os << std::format("\t{:10} {:%F %R %z} {:20}\n", p, std::chrono::zoned_time{ tz, meeting_zt }, tz); 23 | } 24 | } 25 | } // namespace tmcppc::problem_43 26 | 27 | 28 | void problem_43_main(std::ostream& os); 29 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_05_date_and_time/problem_044_monthly_calendar.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | namespace tmcppc::problem_44 { 8 | void print_calendar_month(std::ostream& os, const std::chrono::year& y, const std::chrono::month& m); 9 | } // namespace tmcppc::problem_44 10 | 11 | 12 | void problem_44_main(std::ostream& os); 13 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_05_date_and_time/problems.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "problem_039_measuring_function_execution_time.h" 4 | #include "problem_040_number_of_days_between_two_dates.h" 5 | #include "problem_041_day_of_the_week.h" 6 | #include "problem_042_day_and_week_of_the_year.h" 7 | #include "problem_043_meeting_time_for_multiple_time_zones.h" 8 | #include "problem_044_monthly_calendar.h" 9 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_06_algorithms_and_data_structures/phone_numbers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | namespace tmcppc::phone { 11 | using numbers = std::vector; 12 | 13 | enum class country_code { 14 | US = 1, 15 | Spain = 34, 16 | UK = 44 17 | }; 18 | 19 | inline std::ostream& operator<<(std::ostream& os, const country_code& cc) { 20 | switch (cc) { 21 | case country_code::US: return os << fmt::format("{}", "US"); 22 | case country_code::Spain: return os << fmt::format("{}", "Spain"); 23 | case country_code::UK: return os << fmt::format("{}", "UK"); 24 | default: return os << fmt::format("{}", "Unknown country code"); 25 | } 26 | return os; 27 | } 28 | } // namespace tmcppc::phone 29 | 30 | 31 | // fmt formatter 32 | template <> 33 | struct fmt::formatter : fmt::ostream_formatter {}; 34 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_06_algorithms_and_data_structures/problem_045_priority_queue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_45_main(std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_06_algorithms_and_data_structures/problem_046_circular_buffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_46_main(std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_06_algorithms_and_data_structures/problem_047_double_buffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_47_main(std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_06_algorithms_and_data_structures/problem_049_text_histogram.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | namespace tmcppc::problem_49 { 9 | using letter_counts = std::map; 10 | 11 | letter_counts count_letters(const std::string& text); 12 | 13 | void print_histogram(std::ostream& os, const letter_counts& counts); 14 | } // namespace tmcppc::problem_49 15 | 16 | 17 | void problem_49_main(std::ostream& os); 18 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_06_algorithms_and_data_structures/problem_050_filtering_a_list_of_phone_numbers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "phone_numbers.h" 4 | 5 | #include 6 | 7 | 8 | namespace tmcppc::problem_50 { 9 | using phone_numbers = tmcppc::phone::numbers; 10 | using country_code = tmcppc::phone::country_code; 11 | 12 | phone_numbers filter_phone_numbers_by_country_code(const phone_numbers& ph_nos, const country_code& cc); 13 | } // namespace tmcppc::problem_50 14 | 15 | 16 | void problem_50_main(std::ostream& os); 17 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_06_algorithms_and_data_structures/problem_051_transforming_a_list_of_phone_numbers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "phone_numbers.h" 4 | 5 | #include 6 | 7 | 8 | namespace tmcppc::problem_51 { 9 | using phone_numbers = tmcppc::phone::numbers; 10 | using country_code = tmcppc::phone::country_code; 11 | 12 | void format_phone_numbers(phone_numbers& ph_nos, const country_code& cc); 13 | } // namespace tmcppc::problem_51 14 | 15 | 16 | void problem_51_main(std::ostream& os); 17 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_06_algorithms_and_data_structures/problem_052_generating_all_the_permutations_of_a_string.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | namespace tmcppc::problem_52 { 9 | using permutations = std::vector; 10 | 11 | permutations all_permutations_rec(std::string str); 12 | permutations all_permutations(std::string str); 13 | } // namespace tmcppc::problem_52 14 | 15 | 16 | void problem_52_main(std::ostream& os); 17 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_06_algorithms_and_data_structures/problem_053_average_rating_of_movies.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | namespace tmcppc::problem_53 { 10 | using ratings = std::vector; 11 | using movie_ratings = std::map; 12 | 13 | double average_rating(ratings rs); 14 | } // namespace tmcppc::problem_53 15 | 16 | 17 | void problem_53_main(std::ostream& os); 18 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_06_algorithms_and_data_structures/problem_054_pairwise_algorithm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // plus 4 | #include 5 | #include // adjacent_difference 6 | #include // as_const, make_pair, pair 7 | #include 8 | 9 | 10 | namespace tmcppc::problem_54 { 11 | template 12 | using pairs_of_consecutive_elements = std::vector>; 13 | 14 | template 15 | auto zip_with_next(const std::vector& v) { 16 | pairs_of_consecutive_elements ret{}; 17 | 18 | if (v.size() < 2) { 19 | return ret; 20 | } 21 | 22 | auto first_cit{ cbegin(v) }; 23 | auto last_cit{ (v.size() % 2 == 0) ? cend(v) : prev(cend(v)) }; 24 | for (auto cit{ first_cit }; cit != last_cit; cit += 2) { 25 | ret.push_back(std::make_pair(*cit, *(next(cit)))); 26 | } 27 | 28 | return ret; 29 | } 30 | } // namespace tmcppc::problem_54 31 | 32 | 33 | void problem_54_main(std::ostream& os); 34 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_06_algorithms_and_data_structures/problem_055_zip_algorithm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // min, transform 4 | #include 5 | #include // back_inserter 6 | #include // make_pair, pair 7 | #include 8 | 9 | 10 | namespace tmcppc::problem_55 { 11 | template 12 | using zipped_vector = std::vector>; 13 | 14 | template 15 | auto zip(const std::vector& rng_1, const std::vector& rng_2) { 16 | zipped_vector ret{}; 17 | auto last_pos{ std::min(rng_1.size(), rng_2.size()) }; 18 | std::transform(cbegin(rng_1), cbegin(rng_1) + last_pos, cbegin(rng_2), std::back_inserter(ret), 19 | [](const T& t, const U& u) { return std::make_pair(t, u); 20 | }); 21 | return ret; 22 | } 23 | } // namespace tmcppc::problem_55 24 | 25 | 26 | void problem_55_main(std::ostream& os); 27 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_06_algorithms_and_data_structures/problem_056_select_algorithm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // transform 4 | #include 5 | #include 6 | #include // back_inserter 7 | #include 8 | #include 9 | #include // invoke_result_t, remove_cvref 10 | #include // forward 11 | #include 12 | 13 | 14 | namespace tmcppc::problem_56 { 15 | struct book { 16 | int id{}; 17 | std::string title; 18 | std::string author; 19 | 20 | friend std::ostream& operator<<(std::ostream& os, const book& b) { 21 | return os << fmt::format("(id = {}, title = {}, author = {})", b.id, b.title, b.author); 22 | } 23 | }; 24 | 25 | template 26 | requires requires (T&& t, F&& f) { f(t); } 27 | auto select(const std::vector& v, F&& f) { 28 | std::vector>> ret{}; 29 | std::ranges::transform(v, std::back_inserter(ret), std::forward(f)); 30 | return ret; 31 | } 32 | } // namespace tmcppc::problem_56 33 | 34 | 35 | // fmt formatter 36 | template <> 37 | struct fmt::formatter : fmt::ostream_formatter {}; 38 | 39 | 40 | void problem_56_main(std::ostream& os); 41 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_06_algorithms_and_data_structures/problem_057_quicksort.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "chapter_07_concurrency/quicksort.h" 4 | 5 | #include 6 | 7 | 8 | void problem_57_main(std::ostream& os); 9 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_06_algorithms_and_data_structures/problem_058_shortest_path_between_two_nodes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_58_main(std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_06_algorithms_and_data_structures/problems.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "problem_045_priority_queue.h" 4 | #include "problem_046_circular_buffer.h" 5 | #include "problem_047_double_buffer.h" 6 | #include "problem_048_most_frequent_element_in_a_range.h" 7 | #include "problem_049_text_histogram.h" 8 | #include "problem_050_filtering_a_list_of_phone_numbers.h" 9 | #include "problem_051_transforming_a_list_of_phone_numbers.h" 10 | #include "problem_052_generating_all_the_permutations_of_a_string.h" 11 | #include "problem_053_average_rating_of_movies.h" 12 | #include "problem_054_pairwise_algorithm.h" 13 | #include "problem_055_zip_algorithm.h" 14 | #include "problem_056_select_algorithm.h" 15 | #include "problem_057_quicksort.h" 16 | #include "problem_058_shortest_path_between_two_nodes.h" 17 | #include "problem_059_weasel_program.h" 18 | #include "problem_060_game_of_life.h" 19 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_07_concurrency/logger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // lock_guard 4 | #include // printable 5 | #include 6 | 7 | 8 | namespace tmcppc::logging::v2 { 9 | class logger { 10 | public: 11 | [[nodiscard]] static logger& get_instance() { 12 | static logger instance; 13 | return instance; 14 | } 15 | 16 | logger(const logger& rhs) = delete; 17 | logger(logger&& rhs) = delete; 18 | logger& operator=(const logger& rhs) = delete; 19 | logger& operator=(logger&& rhs) = delete; 20 | ~logger() = default; 21 | 22 | // Let's print a variadic list of printable arguments instead 23 | void log(std::ostream& os, rtc::print::printable auto ... messages) { 24 | std::lock_guard lock{ m_ }; 25 | (void) (os << ... << messages); 26 | } 27 | 28 | private: 29 | std::mutex m_{}; 30 | 31 | logger() = default; 32 | }; 33 | } // namespace tmcppc::logging::v2 34 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_07_concurrency/problem_064_parallel_sort_algorithm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "chapter_07_concurrency/quicksort.h" 4 | 5 | #include 6 | 7 | 8 | void problem_64_main(std::ostream& os); 9 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_07_concurrency/problem_065_thread_safe_logging.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_65_main(std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_07_concurrency/problems.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "problem_061_parallel_transform_algorithm.h" 4 | #include "problem_062_parallel_minmax_with_threads.h" 5 | #include "problem_063_parallel_minmax_with_async.h" 6 | #include "problem_064_parallel_sort_algorithm.h" 7 | #include "problem_065_thread_safe_logging.h" 8 | #include "problem_066_customer_service_system.h" 9 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_08_design_patterns/problems.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "problem_067_validating_passwords.h" 4 | #include "problem_068_generating_random_passwords.h" 5 | #include "problem_069_generating_social_security_numbers.h" 6 | #include "problem_070_approval_system.h" 7 | #include "problem_071_observable_vector_container.h" 8 | #include "problem_072_computing_order_price_with_discounts.h" 9 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_09_data_serialization/problem_073_xml_serialization.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_73_main(std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_09_data_serialization/problem_074_using_xpath.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "chapter_09_data_serialization/xml/movies.h" 4 | 5 | #include 6 | 7 | 8 | namespace tmcppc::problem_74 { 9 | void print_movies_released_after_year(std::ostream& os, const tmcppc::movies::xml::doc& doc, int year); 10 | void print_last_actor_in_casting_list_for_every_movie(std::ostream& os, const tmcppc::movies::xml::doc& doc); 11 | } // namespace tmcppc::problem_74 12 | 13 | 14 | void problem_74_main(std::ostream& os); 15 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_09_data_serialization/problem_075_json_serialization.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_75_main(std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_09_data_serialization/problem_076_json_deserialization.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_76_main(std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_09_data_serialization/problem_077_printing_a_list_of_movies_to_a_pdf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_77_main(std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_09_data_serialization/problem_078_creating_a_pdf_from_a_collection_of_images.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_78_main(std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_09_data_serialization/problems.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "problem_073_xml_serialization.h" 4 | #include "problem_074_using_xpath.h" 5 | #include "problem_075_json_serialization.h" 6 | #include "problem_076_json_deserialization.h" 7 | #include "problem_077_printing_a_list_of_movies_to_a_pdf.h" 8 | #include "problem_078_creating_a_pdf_from_a_collection_of_images.h" 9 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_10_archives_images_and_databases/problem_079_finding_files_in_a_zip_archive.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | namespace tmcppc::problem_79 { 11 | std::vector regex_search_in_zip_file(std::ostream& os, const std::filesystem::path& file_path, const std::regex& pattern); 12 | } // namespace tmcppc::problem_79 13 | 14 | 15 | void problem_79_main(std::ostream& os); 16 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_10_archives_images_and_databases/problem_080_zip_compression.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_80_main(std::istream& is, std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_10_archives_images_and_databases/problem_081_zip_compression_with_password.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | namespace tmcppc::problem_81 { 9 | void compare_input_and_output(std::ostream& os, const std::filesystem::path& input_path, const std::filesystem::path& output_path, 10 | const std::filesystem::directory_options& options); 11 | void remove_output(std::istream& is, std::ostream& os, const std::filesystem::path& path); 12 | void test_zip_lib(std::istream& is, std::ostream& os, const std::string& password = {}); 13 | } // namespace tmcppc::problem_81 14 | 15 | void problem_81_main(std::istream& is, std::ostream& os); 16 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_10_archives_images_and_databases/problem_082_national_flag_png.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "chapter_10_archives_images_and_databases/png/png_writer_wrapper.h" 4 | 5 | #include 6 | 7 | 8 | namespace tmcppc::problem_82 { 9 | void paint_romania_flag(tmcppc::png::png_writer& png_writer); 10 | } // namespace tmcppc::problem_82 11 | 12 | 13 | void problem_82_main(std::ostream& os); 14 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_10_archives_images_and_databases/problem_083_verification_text_png.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "chapter_10_archives_images_and_databases/png/png_writer_wrapper.h" 4 | 5 | #include 6 | 7 | 8 | namespace tmcppc::problem_83 { 9 | void paint_gradient_background(tmcppc::png::png_writer& png_writer); 10 | void paint_random_letters(tmcppc::png::png_writer& png_writer); 11 | void paint_random_strokes(tmcppc::png::png_writer& png_writer); 12 | void paint_verification_text(tmcppc::png::png_writer& png_writer); 13 | } // namespace tmcppc::problem_83 14 | 15 | 16 | void problem_83_main(std::ostream& os); 17 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_10_archives_images_and_databases/problem_084_ean_13_barcode_generator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_84_main(std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_10_archives_images_and_databases/problem_085_reading_from_an_sqlite_db.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_85_main(std::istream& is, std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_10_archives_images_and_databases/problem_086_inserting_into_an_sqlite_db.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "chapter_09_data_serialization/movies.h" 4 | #include "chapter_10_archives_images_and_databases/sql/movies.h" 5 | 6 | #include 7 | 8 | 9 | namespace tmcppc::problem_86 { 10 | [[nodiscard]] std::string remove_movie_id_line(const std::string& movie_str); 11 | void add_new_movie(std::istream& is, std::ostream& os, tmcppc::movies::sql::database& movies_db, tmcppc::movies::movie_t& movie); 12 | void add_new_movie_from_console(std::istream& is, std::ostream& os, tmcppc::movies::sql::database& movies_db); 13 | void add_new_movie_from_file(std::istream& is, std::ostream& os, tmcppc::movies::sql::database& movies_db); 14 | void add_new_movies(std::istream& is, std::ostream& os, tmcppc::movies::sql::database& movies_db); 15 | } // namespace tmcppc::problem_86 16 | 17 | 18 | void problem_86_main(std::istream& is, std::ostream& os); 19 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_10_archives_images_and_databases/problem_087_handling_images_in_an_sqlite_db.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_87_main(std::istream& is, std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_10_archives_images_and_databases/problems.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "problem_079_finding_files_in_a_zip_archive.h" 4 | #include "problem_080_zip_compression.h" 5 | #include "problem_081_zip_compression_with_password.h" 6 | #include "problem_082_national_flag_png.h" 7 | #include "problem_083_verification_text_png.h" 8 | #include "problem_084_ean_13_barcode_generator.h" 9 | #include "problem_085_reading_from_an_sqlite_db.h" 10 | #include "problem_086_inserting_into_an_sqlite_db.h" 11 | #include "problem_087_handling_images_in_an_sqlite_db.h" 12 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_11_cryptography/crypt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace tmcppc::crypto { 7 | class crypt { 8 | public: 9 | virtual ~crypt() = default; 10 | 11 | [[nodiscard]] virtual std::string encrypt(std::string_view text) const = 0; 12 | [[nodiscard]] virtual std::string decrypt(std::string_view text) const = 0; 13 | }; 14 | } // namespace tmcppc::crypto 15 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_11_cryptography/problem_088_caesar_cipher.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_88_main(std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_11_cryptography/problem_089_vigenere_cipher.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_89_main(std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_11_cryptography/problem_090_base64_encoding.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "chapter_11_cryptography/base64.h" 4 | 5 | #include 6 | #include 7 | 8 | 9 | namespace tmcppc::problem_90 { 10 | using base64 = tmcppc::crypto::base64; 11 | 12 | void test_base_64(std::ostream& os, const std::vector& input_data, bool use_padding = true); 13 | } // namespace tmcppc::problem_90 14 | 15 | 16 | void problem_90_main(std::ostream& os); 17 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_11_cryptography/problem_092_computing_file_hashes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 4 | #include 5 | #include // FileSource 6 | #include // HashFilter, StringSink 7 | #include // HexEncoder 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | namespace tmcppc::crypto { 15 | template 16 | std::string get_hash_as_hex_string(const std::filesystem::path& file_path) { 17 | if (not fs::exists(file_path)) { 18 | throw rtc::filesystem::file_path_does_not_exist_error{ file_path.generic_string()}; 19 | } 20 | 21 | std::string digest{}; 22 | Hash hash{}; 23 | 24 | CryptoPP::FileSource file_source{ 25 | file_path.c_str(), 26 | true, 27 | new CryptoPP::HashFilter{hash, 28 | new CryptoPP::HexEncoder{ 29 | new CryptoPP::StringSink{digest} 30 | } 31 | } 32 | }; 33 | 34 | return digest; 35 | } 36 | } // namespace tmcppc::crypto 37 | 38 | 39 | void problem_92_main(std::ostream& os); 40 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_11_cryptography/problem_093_aes_encryption.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | namespace tmcppc::crypto { 9 | void aes_encrypt(const std::filesystem::path& input_file_path, const std::filesystem::path& encrypted_file_path, 10 | const std::string& password); 11 | void aes_decrypt(const std::filesystem::path& encrypted_file_path, const std::filesystem::path& decrypted_file_path, 12 | const std::string& password); 13 | } // namespace tmcppc::crypto 14 | 15 | 16 | 17 | void problem_93_main(std::ostream& os); 18 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_11_cryptography/problem_094_file_signing.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | namespace tmcppc::crypto { 8 | void generate_keys( 9 | const std::filesystem::path& rsa_private_key_file_path, 10 | const std::filesystem::path& rsa_public_key_file_path); 11 | void sign_file( 12 | const std::filesystem::path& input_file_path, 13 | const std::filesystem::path& rsa_private_key_file_path, 14 | const std::filesystem::path& signature_file_path); 15 | bool verify_file( 16 | const std::filesystem::path& input_file_path, 17 | const std::filesystem::path& rsa_public_key_file_path, 18 | const std::filesystem::path& signature_file_path); 19 | } // namespace tmcppc::problem_94 20 | 21 | 22 | void problem_94_main(std::ostream& os); 23 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_11_cryptography/problems.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "problem_088_caesar_cipher.h" 4 | #include "problem_089_vigenere_cipher.h" 5 | #include "problem_090_base64_encoding.h" 6 | #include "problem_091_validating_user_credentials.h" 7 | #include "problem_092_computing_file_hashes.h" 8 | #include "problem_093_aes_encryption.h" 9 | #include "problem_094_file_signing.h" 10 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_12_networking_and_services/json/bitcoin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../bitcoin.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | namespace tmcppc::bitcoin { 11 | inline void from_json(const nlohmann::json& j, exchange_rate& er) { 12 | j.at("symbol").get_to(er.symbol); 13 | j.at("15m").get_to(er.fifteen_minutes); 14 | j.at("last").get_to(er.last); 15 | j.at("buy").get_to(er.buy); 16 | j.at("sell").get_to(er.sell); 17 | } 18 | 19 | inline void from_json(const nlohmann::json& j, exchange_rates& ers) { 20 | ers.data = j.get>(); 21 | } 22 | } // namespace tmcppc::bitcoin 23 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_12_networking_and_services/problem_095_finding_the_ip_address_of_a_host.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_95_main(std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_12_networking_and_services/problem_096_fizz_buzz_client_server_application.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_96_main(std::istream& is, std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_12_networking_and_services/problem_097_bitcoin_exchange_rates.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | void problem_97_main(std::ostream& os); 7 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_12_networking_and_services/problem_098_fetching_emails_using_imap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "imap/connection.h" 4 | 5 | #include 6 | 7 | 8 | namespace tmcppc::problem_98 { 9 | tmcppc::imap::mailbox_folder_t read_mailbox_folder( 10 | std::istream& is, 11 | std::ostream& os 12 | ); 13 | void print_mailbox_folders( 14 | std::ostream& os, 15 | const tmcppc::imap::mailbox_folders_t& folders 16 | ); 17 | void print_unread_email_ids_from_folder( 18 | std::ostream& os, 19 | const tmcppc::imap::mailbox_folder_t& folder, 20 | const tmcppc::imap::email_subjects_t& email_subjects 21 | ); 22 | void test_imap_connection( 23 | std::istream& is, 24 | std::ostream& os, 25 | const tmcppc::imap::imap_connection& connection 26 | ); 27 | } // namespace tmcppc::problem_98 28 | 29 | 30 | void problem_98_main(std::istream& is, std::ostream& os); 31 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_12_networking_and_services/problem_099_translating_text.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "chapter_12_networking_and_services/text_translation.h" 4 | 5 | #include 6 | 7 | 8 | namespace tmcppc::problem_99 { 9 | void test_text_translation(std::ostream& os, const tmcppc::text_translation::translator& translator); 10 | } // namespace tmcppc::problem_99 11 | 12 | 13 | void problem_99_main(std::istream& is, std::ostream& os); 14 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_12_networking_and_services/problem_100_detecting_faces_in_a_picture.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "chapter_12_networking_and_services/face_detection.h" 4 | 5 | #include 6 | 7 | 8 | namespace tmcppc::problem_100 { 9 | void test_face_detection(std::ostream& os, const tmcppc::face_detection::detector& detector); 10 | } // namespace tmcppc::problem_100 11 | 12 | 13 | void problem_100_main(std::istream& is, std::ostream& os); 14 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_12_networking_and_services/problems.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "problem_095_finding_the_ip_address_of_a_host.h" 4 | #include "problem_096_fizz_buzz_client_server_application.h" 5 | #include "problem_097_bitcoin_exchange_rates.h" 6 | #include "problem_098_fetching_emails_using_imap.h" 7 | #include "problem_099_translating_text.h" 8 | #include "problem_100_detecting_faces_in_a_picture.h" 9 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/chapter_12_networking_and_services/tcp/resolver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include // error_code 6 | #include 7 | 8 | #define BOOST_ASIO_STANDALONE 9 | #include 10 | #include 11 | 12 | 13 | namespace tmcppc::tcp { 14 | using ipv4_addresses = std::vector; 15 | 16 | 17 | struct resolver { 18 | virtual ~resolver() = default; 19 | 20 | [[nodiscard]] virtual ipv4_addresses get_host_ipv4_addresses(std::string_view host, 21 | std::string_view service) const = 0; 22 | }; 23 | 24 | 25 | class resolver_asio : public resolver { 26 | public: 27 | explicit resolver_asio(asio::io_context& io_context) 28 | : io_context_{ io_context } 29 | {} 30 | 31 | [[nodiscard]] ipv4_addresses get_host_ipv4_addresses(std::string_view host, 32 | std::string_view service) const override { 33 | 34 | ipv4_addresses ret{}; 35 | 36 | asio::ip::tcp::resolver resolver{ io_context_ }; 37 | auto iter{ resolver.resolve(asio::ip::tcp::v4(), host, service) }; 38 | asio::ip::tcp::resolver::iterator end{}; 39 | while (iter != end) { 40 | asio::ip::tcp::endpoint endpoint = *iter++; 41 | ret.emplace_back(endpoint.address().to_string().c_str()); 42 | } 43 | return ret; 44 | } 45 | private: 46 | asio::io_context& io_context_; 47 | }; 48 | } // namespace tmcppc::tcp 49 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/console.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // unique_ptr 4 | #include "rtc/console.h" 5 | #include // runtime_error 6 | #include 7 | #include // move 8 | 9 | 10 | namespace tmcppc::system { 11 | struct console_error : public std::runtime_error { 12 | explicit console_error(std::string_view message) 13 | : std::runtime_error{ message.data() } 14 | {} 15 | }; 16 | 17 | struct console_iface { 18 | virtual ~console_iface() = default; 19 | virtual void clear_istream(std::istream& is) const = 0; 20 | virtual void clear_screen() const = 0; 21 | }; 22 | 23 | struct console_impl : public console_iface { 24 | void clear_istream(std::istream& is) const override { 25 | rtc::console::clear_istream(is); 26 | } 27 | void clear_screen() const override { 28 | rtc::console::clear_screen(); 29 | } 30 | }; 31 | 32 | class console { 33 | public: 34 | explicit console(std::unique_ptr impl_up) 35 | : impl_up_{ std::move(impl_up) } { 36 | 37 | if (not impl_up_) { 38 | throw console_error{ "console is null" }; 39 | } 40 | } 41 | void clear_istream(std::istream& is) const { 42 | impl_up_->clear_istream(is); 43 | } 44 | void clear_screen() const { 45 | impl_up_->clear_screen(); 46 | } 47 | private: 48 | std::unique_ptr impl_up_; 49 | }; 50 | } // namespace tmcppc::system 51 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/env.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | namespace tmcppc { 7 | class env { 8 | public: 9 | [[nodiscard]] static env& get_instance() { 10 | static env instance; 11 | return instance; 12 | } 13 | [[nodiscard]] auto get_resource_folder_path() { 14 | return resource_folder_path_; 15 | } 16 | void set_resource_folder_path(const std::filesystem::path& p) { 17 | resource_folder_path_ = p; 18 | } 19 | private: 20 | env() = default; 21 | std::filesystem::path resource_folder_path_{}; 22 | }; 23 | } // namespace tmcppc 24 | -------------------------------------------------------------------------------- /include/the_modern_c++_challenge/timer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include // unique_ptr 5 | #include // runtime_error 6 | #include 7 | #include // sleep_for 8 | #include // move 9 | 10 | namespace ch = std::chrono; 11 | 12 | 13 | namespace tmcppc::chrono { 14 | struct timer_error : public std::runtime_error { 15 | explicit timer_error(std::string_view message) 16 | : std::runtime_error{ message.data() } 17 | {} 18 | }; 19 | 20 | struct timer_iface { 21 | virtual ~timer_iface() = default; 22 | virtual void sleep_for(const ch::duration& duration) const = 0; 23 | }; 24 | 25 | struct timer_impl : public timer_iface { 26 | void sleep_for(const ch::duration& duration) const override { 27 | std::this_thread::sleep_for(duration); 28 | } 29 | }; 30 | 31 | class timer { 32 | public: 33 | explicit timer(std::unique_ptr impl_up) 34 | : impl_up_{ std::move(impl_up) } { 35 | 36 | if (not impl_up_) { 37 | throw timer_error{ "timer is null" }; 38 | } 39 | } 40 | void sleep_for(const ch::duration& duration) const { 41 | impl_up_->sleep_for(duration); 42 | } 43 | private: 44 | std::unique_ptr impl_up_; 45 | }; 46 | } // namespace tmcppc::chrono 47 | -------------------------------------------------------------------------------- /res/crypto/public_key.txt: -------------------------------------------------------------------------------- 1 | 308201A0300D06092A864886F70D01010105000382018D003082018802820181009A5DD4ACBB1484371B57AB13C6623B6E1ECBBD05D23F2927914681EF1F6D698BFFB41CDFC4FF5439B551A66BBA7DCEA6DB14D35B9695F36CD7FC3B4A059185FA015DD29BB0AE93A81D8F235EB868B5EE4BF2B279CEEF65C57AC59913CDC482C57AF4764B32F83C5578C1DDDF5431DEC03F59BE45C8EB595F96D0A10BA9362515C45C73FA247319D880E10A7102B03CF9E48618E668FD38DBE1AA59CD12535BD680862C9597CEDB8D949433199708D1BAF3D19BCA551BDAB554CDFA55119C2A1F572121F375DF5A06D06A49CAEF5C1D357C757C10C73CBE56C4F06D9D4492E3E79603EB97C5E6C2AC13B9A8B5F9BE40E7C5F11A1B9E61A4DFE82F442BAC7FF5B4F331613E64ADD5F83B7FF686AF5E8640F9A7A6F3535F5478476329B2B10967AAED0879E6C4FA2725F5C323D24545B2080F5435900C81BF508B1E8B08BF33B9E211B777BCA9CF95EB693D2A63012893B1C9B7203722E806B20DD83B63621AB8EC03C471FA5D91D4C555F0D89A8E61ED1079B92BAB7B1F1519FDC5C1868F7536EB020111 -------------------------------------------------------------------------------- /res/crypto/signature.txt: -------------------------------------------------------------------------------- 1 | 93F6E528042F5289A2DBC740EE35BE869FBEF0397A115D42C7DCB73A854D5397A391E81CC458B1BF013C8A7319EBD5A60FE15E5CB9B5B86AD8937B9C5FEF9D847BF75BA7E594CC8BC7D1C72096B9114670845A5D64F6BD0C382B4A5653855895F26488E4754B1795541ACF8053CB2EA7BEE3956982FACB763449D5F9F559F477C6D006942B77B5257F8A0CFF37B473DECA39C0E997E6BA9E267A0777C58BEF77206E1937A61AA9DF65319AD0785FB740EDD0F3184556238305EF11C8A0292EE907835E415B2ABF3D3E13DE923E95F86B34D785EB0F2175CD057EA70861165E50BD67B194343DE2B889E3A90EEFD27281A861179D35FE9B4C8CDAB7D37DB9B16CBE4CBE65DF8156610A2ED64A8912A289331D818BF8AA76B7B4FE45B3B114BE71E3706FAF024D0214B30543652067B818233C6EAAEB63C09B6BF1D1745A844DCBE3696A6337DE3F4FA921B21C1955AE0E5D1BF13E8AF1CDF3D915B07BC3DB11D7D2A523EA3B6FB701F4567B43C81674AD966C68FE44BD13FE3CF749A21C6FB6DD -------------------------------------------------------------------------------- /res/db/city.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/db/city.jpg -------------------------------------------------------------------------------- /res/db/new_movies.txt: -------------------------------------------------------------------------------- 1 | 2 2 | Fight Club 3 | 1990 4 | 139 5 | 3 6 | Brad Pitt 7 | Tyler Durden 8 | Edward Norton 9 | Narrator 10 | Meat Loaf 11 | Robert Paulsen 12 | 1 13 | David Fincher 14 | 2 15 | Chuck Palahniuk 16 | Jim Uhls 17 | Blade Runner 18 | 1982 19 | 117 20 | 3 21 | Harrison Ford 22 | Rick Deckard 23 | Rutger Hauer 24 | Roy Batty 25 | Sean Young 26 | Rachael 27 | 1 28 | Ridley Scott 29 | 3 30 | Hampton Fancher 31 | David Webb Peoples 32 | Philip K. Dick 33 | -------------------------------------------------------------------------------- /res/db/poster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/db/poster.png -------------------------------------------------------------------------------- /res/faces.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/faces.jpg -------------------------------------------------------------------------------- /res/fonts/calibri.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/fonts/calibri.ttf -------------------------------------------------------------------------------- /res/fonts/calibrib.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/fonts/calibrib.ttf -------------------------------------------------------------------------------- /res/fonts/calibrii.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/fonts/calibrii.ttf -------------------------------------------------------------------------------- /res/fonts/calibril.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/fonts/calibril.ttf -------------------------------------------------------------------------------- /res/fonts/calibrili.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/fonts/calibrili.ttf -------------------------------------------------------------------------------- /res/fonts/calibriz.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/fonts/calibriz.ttf -------------------------------------------------------------------------------- /res/fonts/pala.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/fonts/pala.ttf -------------------------------------------------------------------------------- /res/images/img_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/images/img_01.png -------------------------------------------------------------------------------- /res/images/img_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/images/img_02.png -------------------------------------------------------------------------------- /res/images/img_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/images/img_03.png -------------------------------------------------------------------------------- /res/images/img_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/images/img_04.png -------------------------------------------------------------------------------- /res/images/img_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/images/img_05.png -------------------------------------------------------------------------------- /res/images/img_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/images/img_06.png -------------------------------------------------------------------------------- /res/images/img_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/images/img_07.png -------------------------------------------------------------------------------- /res/images/img_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/images/img_08.png -------------------------------------------------------------------------------- /res/images/img_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/images/img_09.png -------------------------------------------------------------------------------- /res/images/img_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/images/img_10.png -------------------------------------------------------------------------------- /res/images/masters/2407014001944.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/images/masters/2407014001944.png -------------------------------------------------------------------------------- /res/images/masters/romania_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/images/masters/romania_flag.png -------------------------------------------------------------------------------- /res/sample_folder.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/sample_folder.zip -------------------------------------------------------------------------------- /res/sample_folder/dilbert.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/sample_folder/dilbert.jpg -------------------------------------------------------------------------------- /res/sample_folder/guinness.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/sample_folder/guinness.jpg -------------------------------------------------------------------------------- /res/sample_folder/john_mccarthy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/sample_folder/john_mccarthy.jpg -------------------------------------------------------------------------------- /res/sample_folder/multi_page_2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/sample_folder/multi_page_2.pdf -------------------------------------------------------------------------------- /res/sample_folder/multi_page_3.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/sample_folder/multi_page_3.docx -------------------------------------------------------------------------------- /res/sample_folder/sample_subfolder: -------------------------------------------------------------------------------- 1 | ../sample_subfolder -------------------------------------------------------------------------------- /res/sample_subfolder/use_your_illussion_ii.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rturrado/the_modern_cpp_challenge/2a458372f9d0620f0793a6f6b8272f16a0bdf2be/res/sample_subfolder/use_your_illussion_ii.jpg -------------------------------------------------------------------------------- /src/chapter_01_math/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_01_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_001_sum_of_naturals_divisible_by_3_or_5.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_002_greatest_common_divisor.cpp" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_003_least_common_multiple.cpp" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_004_largest_prime_smaller_than_given_number.cpp" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_005_sexy_prime_pairs.cpp" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_006_abundant_numbers.cpp" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_007_amicable_numbers.cpp" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_008_armstrong_numbers.cpp" 10 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_009_prime_factors.cpp" 11 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_010_gray_code.cpp" 12 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_011_converting_numerical_values_to_roman.cpp" 13 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_012_longest_collatz_sequence.cpp" 14 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_013_computing_the_value_of_pi.cpp" 15 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_014_validating_isbns.cpp" 16 | PARENT_SCOPE 17 | ) 18 | -------------------------------------------------------------------------------- /src/chapter_01_math/problem_002_greatest_common_divisor.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_01_math/problem_002_greatest_common_divisor.h" 2 | 3 | #include 4 | #include // read_positive_number 5 | #include // runtime_error 6 | #include // exchange 7 | 8 | 9 | namespace tmcppc::problem_2 { 10 | int gcd(int m, int n) { 11 | if (m <= 0 or n <= 0) { 12 | throw std::runtime_error{ "calling gcd(m, n) with a negative or zero value" }; 13 | } 14 | 15 | // Sort m and n so that m >= n 16 | if (m < n) { 17 | n = std::exchange(m, n); 18 | } 19 | 20 | for (auto i{ n }; i > 0; --i) { 21 | if ((m % i == 0) and (n % i == 0)) { 22 | return i; 23 | } 24 | } 25 | return -1; 26 | } 27 | } // namespace tmcppc::problem_2 28 | 29 | 30 | // Greatest common divisor 31 | // 32 | // Write a program that, given two positive integers, will calculate and print the greatest common divisor of the two 33 | void problem_2_main(std::istream& is, std::ostream& os) { 34 | using namespace tmcppc::problem_2; 35 | 36 | auto m{ rtc::console::read_positive_number(is, os, "Please enter a first number (>= 1): ", 1) }; 37 | auto n{ rtc::console::read_positive_number(is, os, "Please enter a second number (>= 1): ", 1) }; 38 | 39 | try { 40 | fmt::print(os, "The greatest common divisor of {} and {} is: {}\n\n", m, n, gcd(m, n)); 41 | } catch (const std::exception& ex) { 42 | fmt::print(os, "Error: {}.\n\n", ex.what()); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/chapter_01_math/problem_004_largest_prime_smaller_than_given_number.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_01_math/math.h" // is_prime 2 | #include "chapter_01_math/problem_004_largest_prime_smaller_than_given_number.h" 3 | 4 | #include 5 | #include // read_positive_number 6 | 7 | 8 | namespace tmcppc::problem_4 { 9 | size_t biggest_prime_smaller_than(size_t n) { 10 | using namespace tmcppc::math; 11 | 12 | if (n == 0 or n == 1) { 13 | return 0; 14 | } 15 | return (is_prime(n - 1) ? n - 1 : biggest_prime_smaller_than(n - 1)); 16 | } 17 | } // namespace tmcppc::problem_4 18 | 19 | 20 | // Largest prime smaller than given number 21 | // 22 | // Write a program that computes and prints the largest prime number 23 | // that is smaller than a number provided by the user, which must be a positive integer 24 | void problem_4_main(std::istream& is, std::ostream& os) { 25 | using namespace tmcppc::problem_4; 26 | 27 | auto limit{ rtc::console::read_positive_number(is, os, "Please enter a number (>= 2): ", 2) }; 28 | 29 | fmt::print(os, "Biggest prime number smaller than {} is: {}\n\n", limit, 30 | biggest_prime_smaller_than(static_cast(limit))); 31 | } 32 | -------------------------------------------------------------------------------- /src/chapter_01_math/problem_005_sexy_prime_pairs.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_01_math/math.h" // is_prime 2 | #include "chapter_01_math/problem_005_sexy_prime_pairs.h" 3 | 4 | #include 5 | #include // read_positive_number 6 | #include // pair 7 | #include 8 | 9 | 10 | namespace tmcppc::problem_5 { 11 | std::vector> sexy_prime_pairs_up_to(size_t limit) { 12 | using namespace tmcppc::math; 13 | 14 | std::vector> ret{}; 15 | for (size_t i{ 7 }; i <= limit; ++i) { 16 | if (tmcppc::math::is_prime(i) and tmcppc::math::is_prime(i - 6)) { 17 | ret.emplace_back(i - 6, i); 18 | } 19 | } 20 | return ret; 21 | } 22 | } // namespace tmcppc::problem_5 23 | 24 | 25 | // Sexy prime pairs 26 | // 27 | // Write a program that prints all sexy prime pairs up to a limit entered by the user 28 | void problem_5_main(std::istream& is, std::ostream& os) { 29 | using namespace tmcppc::problem_5; 30 | 31 | auto limit{ rtc::console::read_positive_number(is, os, "Please enter a number (>= 1): ", 1) }; 32 | 33 | fmt::print(os, "Sexy prime pairs up to {}:\n", limit); 34 | for (auto&& p : sexy_prime_pairs_up_to(static_cast(limit))) { 35 | fmt::print(os, "\t{}\n", p); 36 | } 37 | fmt::print(os, "\n"); 38 | } 39 | -------------------------------------------------------------------------------- /src/chapter_01_math/problem_009_prime_factors.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_01_math/math.h" // prime_factors 2 | #include "chapter_01_math/problem_009_prime_factors.h" 3 | 4 | #include 5 | #include // read_positive_number 6 | 7 | 8 | // Prime factors of a number 9 | // 10 | // Write a program that prints the prime factors of a number entered by the user 11 | void problem_9_main(std::istream& is, std::ostream& os) { 12 | using namespace tmcppc::math; 13 | 14 | auto n{ rtc::console::read_positive_number(is, os, "Please enter a number (>= 0): ", 0) }; 15 | 16 | fmt::print(os, "Prime factors of {}: {}\n\n", n, prime_factors(n)); 17 | } 18 | -------------------------------------------------------------------------------- /src/chapter_01_math/problem_010_gray_code.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_01_math/problem_010_gray_code.h" 2 | 3 | #include 4 | #include 5 | 6 | 7 | namespace tmcppc::problem_10 { 8 | size_t binary_to_gray(size_t binary) { 9 | return binary ^ (binary >> 1); 10 | } 11 | 12 | 13 | size_t gray_to_binary(size_t gray) { 14 | size_t binary{ 0 }; 15 | while (gray != 0) { 16 | binary ^= gray; 17 | gray >>= 1; 18 | } 19 | return binary; 20 | } 21 | } // namespace tmcppc::problem_10 22 | 23 | 24 | // Gray code 25 | // 26 | // Write a program that displays the normal binary representations, 27 | // Gray code representations, and decoded Gray code values for all 5-bit numbers 28 | void problem_10_main(std::ostream& os) { 29 | using namespace tmcppc::problem_10; 30 | 31 | fmt::print(os, "Number\tBinary\tGray code\tDecoded Gray code\n"); 32 | for (size_t binary = 0b00000; binary <= 0b11111; ++binary) { 33 | size_t gray{ binary_to_gray(binary) }; 34 | size_t decoded_gray{ gray_to_binary(gray) }; 35 | fmt::print(os, "{}\t{}\t{}\t\t{}\n", 36 | binary, std::bitset<5>{binary}.to_string(), std::bitset<5>{gray}.to_string(), decoded_gray); 37 | } 38 | fmt::print(os, "\n"); 39 | } 40 | -------------------------------------------------------------------------------- /src/chapter_01_math/problem_011_converting_numerical_values_to_roman.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_01_math/problem_011_converting_numerical_values_to_roman.h" 2 | #include "chapter_01_math/roman.h" 3 | 4 | #include 5 | #include // read_positive_number 6 | 7 | 8 | // Converting numerical values to Roman 9 | // 10 | // Write a program that, given a number entered by the user, prints its Roman numeral equivalent 11 | void problem_11_main(std::istream& is, std::ostream& os) { 12 | using namespace tmcppc::date; 13 | 14 | auto message{ fmt::format("Please enter a number (between 1 and {}): ", max_roman_numeral) }; 15 | auto n{ rtc::console::read_positive_number(is, os, message, 1, max_roman_numeral + 1) }; 16 | 17 | fmt::print(os, "Number\tRoman numeral equivalent\n"); 18 | fmt::print(os, "{}\t{}\n\n", n, to_roman_v1(static_cast(n))); 19 | } 20 | -------------------------------------------------------------------------------- /src/chapter_02_language_features/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_02_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_015_ipv4_data_type.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_016_enumerating_ipv4_addresses_in_a_range.cpp" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_017_array_2d.cpp" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_018_variadic_minimum_function.cpp" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_019_adding_a_range_of_values_to_a_container.cpp" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_020_contains_any_all_or_none_from_a_range.cpp" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_021_system_handle_wrapper.cpp" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_022_temperature_scales_literals.cpp" 10 | PARENT_SCOPE 11 | ) 12 | -------------------------------------------------------------------------------- /src/chapter_02_language_features/problem_015_ipv4_data_type.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_02_language_features/ipv4.h" 2 | #include "chapter_02_language_features/problem_015_ipv4_data_type.h" 3 | 4 | #include 5 | #include 6 | #include // getline 7 | 8 | 9 | // IPv4 data type 10 | // 11 | // Write a class that represents an IPv4 address. 12 | // Implement the functions required to be able to read and write such addresses from or to the console. 13 | // The user should be able to input values in dotted form, such as 127.0.0.1 or 168.192.0.100. 14 | // This is also the form in which IPv4 addresses should be formatted to an output stream. 15 | void problem_15_main(std::istream& is, std::ostream& os) { 16 | using namespace tmcppc::network; 17 | 18 | while (true) { 19 | fmt::print(os, "Please enter an IPv4 address (e.g. 127.0.0.1), or 'quit' to finish: "); 20 | 21 | std::string s{}; 22 | std::getline(is, s); 23 | 24 | if (s == "quit") { 25 | break; 26 | } 27 | 28 | try { 29 | ipv4 address{ s }; 30 | fmt::print(os, "\tYou've entered a valid IPv4 address: {}\n", s); 31 | } catch (const std::exception& ex) { 32 | fmt::print(os, "\tError: {}\n", ex.what()); 33 | } 34 | } 35 | fmt::print(os, "\n"); 36 | } 37 | -------------------------------------------------------------------------------- /src/chapter_02_language_features/problem_018_variadic_minimum_function.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_02_language_features/problem_018_variadic_minimum_function.h" 2 | 3 | #include 4 | #include // greater 5 | #include 6 | 7 | 8 | // Minimum function with any number of arguments 9 | // 10 | // Write a function template that can take any number of arguments and returns the minimum value of them all, 11 | // using operator< for comparison. 12 | // Write a variant of the function template that can be parameterized with a binary comparison function 13 | // to use instead of operator<. 14 | void problem_18_main(std::ostream& os) { 15 | using namespace tmcppc::problem_18; 16 | 17 | test_minimum(os, 1, 7, -3, 42); 18 | test_minimum(os, "un", "lugar", "de", "la", "Mancha"); 19 | test_minimum(os, std::string("un"), std::string("lugar"), std::string("de"), std::string("la"), std::string("Mancha")); 20 | fmt::print(os, "\n"); 21 | 22 | test_compare_with(os, "more_than", more_than, 23 | 1, 7, -3, 42); 24 | test_compare_with(os, "std::greater", std::greater{}, 25 | std::string("un"), std::string("lugar"), std::string("de"), std::string("la"), std::string("Mancha")); 26 | fmt::print(os, "\n"); 27 | } 28 | -------------------------------------------------------------------------------- /src/chapter_02_language_features/problem_019_adding_a_range_of_values_to_a_container.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_02_language_features/problem_019_adding_a_range_of_values_to_a_container.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | // Adding a range of values to a container 10 | // 11 | // Write a general-purpose function that can add any number of elements 12 | // to the end of a container that has a method push_back(T&& value). 13 | void problem_19_main(std::ostream& os) { 14 | using namespace tmcppc::problem_19; 15 | 16 | std::vector v_int{}; 17 | push_back_list(v_int, 10, 20, 30); 18 | fmt::print(os, "Adding 10, 20, and 30 to an empty vector of ints: {}\n", v_int); 19 | 20 | std::vector v_str{}; 21 | push_back_list(v_str, "Hey", "Joe!", "Voodoo"); 22 | fmt::print(os, "Adding \"Hey\", \"Joe!\", and \"Voodoo\" to an empty vector of strings: {}\n", v_str); 23 | 24 | std::list l_float{}; 25 | push_back_list_v2(l_float, 3.14f, 0.99f, -273.0f); 26 | fmt::print(os, "Adding 3.14f, 0.99f, and -273.0f ot an empty list of floats: {}\n\n", l_float); 27 | } 28 | -------------------------------------------------------------------------------- /src/chapter_02_language_features/problem_020_contains_any_all_or_none_from_a_range.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_02_language_features/problem_020_contains_any_all_or_none_from_a_range.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #undef NDEBUG 10 | #include // assert 11 | 12 | 13 | // Container any, all, none 14 | // 15 | // Write a set of general-purpose functions that enable checking whether any, all, or none 16 | // of the specified arguments are present in a given container. 17 | void problem_20_main(std::ostream& os) { 18 | using namespace tmcppc::problem_20; 19 | 20 | std::vector v{ 1, 2, 3, 4, 5, 6 }; 21 | fmt::print(os, "{}", "Checking std::vector v{1, 2, 3, 4, 5, 6} contains_any of (0, 3, 30)\n"); 22 | assert(contains_any(v, 0, 3, 30)); 23 | 24 | std::array a{ { 1, 2, 3, 4, 5, 6 } }; 25 | fmt::print(os, "{}", "Checking std::array a{1, 2, 3, 4, 5, 6} contains_all of (1, 3, 5, 6)\n"); 26 | assert(contains_all(a, 1, 3, 5, 6)); 27 | 28 | std::list l{ 1, 2, 3, 4, 5, 6 }; 29 | fmt::print(os, "{}", "Checking std::list l{1, 2, 3, 4, 5, 6} not contains_none of (0, 6)\n"); 30 | assert(not contains_none(l, 0, 6)); 31 | 32 | fmt::print(os, "\n"); 33 | } 34 | -------------------------------------------------------------------------------- /src/chapter_03_strings_and_regular_expressions/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_03_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_023_binary_to_string_conversion.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_024_string_to_binary_conversion.cpp" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_025_capitalizing_an_article_title.cpp" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_026_joining_strings_with_delimiter.cpp" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_027_splitting_a_string_into_tokens.cpp" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_028_longest_palindromic_substring.cpp" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_029_license_plate_validation.cpp" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_030_extracting_url_parts.cpp" 10 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_031_transforming_dates_in_strings.cpp" 11 | PARENT_SCOPE 12 | ) 13 | -------------------------------------------------------------------------------- /src/chapter_03_strings_and_regular_expressions/problem_023_binary_to_string_conversion.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_03_strings_and_regular_expressions/problem_023_binary_to_string_conversion.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include // iota 7 | #include 8 | #include 9 | 10 | 11 | // Binary to string conversion 12 | // 13 | // Write a function that, given a range of 8-bit integers (such as an array or vector), 14 | // returns a string that contains a hexadecimal representation of the input data. 15 | // The function should be able to produce both uppercase and lowercase content. 16 | // 17 | // Here are some input and output examples: 18 | // Input: { 0xBA, 0xAD, 0xF0, 0x0D }, output: "BAADF00D" or "baadf00d" 19 | // Input: { 1, 2, 3, 4, 5, 6 }, output: "010203040506" 20 | void problem_23_main(std::ostream& os) { 21 | using namespace tmcppc::problem_23; 22 | 23 | std::vector v{ 0xBA, 0xAD, 0xf0, 0x0d }; 24 | fmt::print(os, "Converting vector [{:#02x}] to string \"{}\"\n", fmt::join(v, ", "), to_hex_string(v)); 25 | 26 | std::array a{}; 27 | std::iota(std::begin(a), std::end(a), 1); 28 | fmt::print(os, "Converting array [{:#02x}] to string \"{}\"\n\n", fmt::join(a, ", "), to_hex_string(a)); 29 | } 30 | -------------------------------------------------------------------------------- /src/chapter_03_strings_and_regular_expressions/problem_026_joining_strings_with_delimiter.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_03_strings_and_regular_expressions/problem_026_joining_strings_with_delimiter.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | // Joining strings together separated by a delimiter 12 | // 13 | // Write a function that, given a list of strings and a delimiter, creates a new string 14 | // by concatenating all the input strings separated with the specified delimiter. 15 | // The delimiter must not appear after the last string, and when no input string is provided, 16 | // the function must return an empty string. 17 | // 18 | // Example: input { "this", "is", "an", "example" } and delimiter ' ' (space), output: "this is an example". 19 | void problem_26_main(std::ostream& os) { 20 | using namespace tmcppc::problem_26; 21 | 22 | const std::array a0{}; 23 | const std::array a1{ "Joe" }; 24 | const std::string d3{ "#" }; 25 | fmt::print(os, "Joining [{}] with delimiter \"{}\": {}\n", fmt::join(a0, ", "), d3, join(a0, d3)); 26 | fmt::print(os, "Joining [{}] with delimiter \"{}\": {}\n", fmt::join(a1, ", "), d3, join(a1, d3)); 27 | 28 | const std::vector v{ "this", "is", "an", "example" }; 29 | const std::string d1{ " " }; 30 | fmt::print(os, "Joining [{}] with delimiter \"{}\": {}\n", fmt::join(v, ", "), d1, join(v, d1)); 31 | 32 | const std::list l{ "yet", "another", "one!" }; 33 | const std::string d2{ "---" }; 34 | fmt::print(os, "Joining [{}] with delimiter \"{}\": {}\n\n", fmt::join(l, ", "), d2, join(l, d2)); 35 | } 36 | -------------------------------------------------------------------------------- /src/chapter_03_strings_and_regular_expressions/problem_030_extracting_url_parts.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_03_strings_and_regular_expressions/problem_030_extracting_url_parts.h" 2 | #include "chapter_03_strings_and_regular_expressions/url.h" 3 | 4 | #include 5 | #include 6 | 7 | 8 | // Extracting URL parts 9 | // 10 | // Write a function that, given a string that represents a URL, parses and extracts the parts of the URL 11 | // (protocol, domain, port, path, query, and fragment) 12 | void problem_30_main(std::ostream& os) { 13 | using namespace tmcppc::network; 14 | 15 | for (const auto& s : { "http://user:pass@example.com:992/animal/bird?species=seagull#wings", 16 | "http://example.com/animal/bird#wings", 17 | "This is not a valid URL!" }) { 18 | try { 19 | url u{ s }; 20 | fmt::print(os, "Parsing URL \"{}\":\n{}\n\n", s, u); 21 | } catch (const std::exception& err) { 22 | fmt::print(os, "Error: {}\n\n", err.what()); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/chapter_04_streams_and_filesystems/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_04_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_032_pascal_triangle.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_033_tabular_printing_of_a_list_of_processes.cpp" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_034_removing_empty_lines_from_a_text_file.cpp" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_035_computing_the_size_of_a_directory.cpp" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_036_deleting_files_older_than_a_given_date.cpp" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_037_regex_find_files_in_a_directory.cpp" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_038_temporary_log_files.cpp" 9 | PARENT_SCOPE 10 | ) 11 | -------------------------------------------------------------------------------- /src/chapter_05_date_and_time/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_05_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_039_measuring_function_execution_time.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_040_number_of_days_between_two_dates.cpp" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_041_day_of_the_week.cpp" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_042_day_and_week_of_the_year.cpp" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_043_meeting_time_for_multiple_time_zones.cpp" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_044_monthly_calendar.cpp" 8 | PARENT_SCOPE 9 | ) 10 | -------------------------------------------------------------------------------- /src/chapter_05_date_and_time/problem_041_day_of_the_week.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_05_date_and_time/problem_041_day_of_the_week.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace ch = std::chrono; 10 | 11 | 12 | namespace tmcppc::problem_41 { 13 | ch::weekday date_to_weekday(const ch::year_month_day& date) { 14 | if (not date.ok()) { 15 | throw rtc::chrono::invalid_date_error{ date }; 16 | } 17 | return ch::weekday{ std::chrono::sys_days{date} }; 18 | } 19 | 20 | unsigned int weekday_to_number(const ch::weekday& wd) { 21 | return wd.iso_encoding(); 22 | } 23 | } // namespace tmcppc::problem_41 24 | 25 | 26 | // Day of the week 27 | // 28 | // Write a function that, given a date, determines the day of the week. 29 | // This function should return a value between 1 (for Monday) and 7 (for Sunday). 30 | void problem_41_main(std::ostream& os) { 31 | using namespace std::chrono_literals; 32 | using namespace tmcppc::problem_41; 33 | 34 | auto date_1{ 1946y / 8 / 11 }; 35 | auto date_2{ 1952y / 4 / 24 }; 36 | auto date_3{ 1972y / 7 / 9 }; 37 | auto date_4{ 1977y / 5 / 23 }; 38 | 39 | for (const auto& date : { date_1, date_2, date_3, date_4 }) { 40 | try { 41 | auto wd{ date_to_weekday(date) }; 42 | os << std::format("{} was: {} ({})\n", date, weekday_to_number(wd), wd); 43 | } catch (const std::exception& ex) { 44 | os << "Error: " << ex.what() << "\n"; 45 | } 46 | } 47 | os << "\n"; 48 | } 49 | -------------------------------------------------------------------------------- /src/chapter_05_date_and_time/problem_043_meeting_time_for_multiple_time_zones.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_05_date_and_time/problem_043_meeting_time_for_multiple_time_zones.h" 2 | 3 | #include 4 | #include 5 | #include // literals 6 | 7 | 8 | // Meeting time for multiple time zones 9 | // 10 | // Write a function that, given a list of meeting participants and their time zones, 11 | // displays the local meeting time for each participant. 12 | void problem_43_main(std::ostream& os) { 13 | namespace ch = std::chrono; 14 | using namespace std::chrono_literals; 15 | using namespace tmcppc::problem_43; 16 | 17 | ch::zoned_time meeting_zt{ "Europe/Madrid", ch::sys_days{2021y / ch::October / 23} + 18h }; 18 | 19 | auto participants = vector_of_participants_and_time_zones{ 20 | { "Laura", "America/Los_Angeles" }, 21 | { "Daniel", "America/Denver" }, 22 | { "Norman", "America/New_York" }, 23 | { "Leonard", "Europe/London" }, 24 | { "Manuel", "Europe/Minsk" }, 25 | { "Mary", "Europe/Moscow" }, 26 | { "Kaisa", "Asia/Kolkata" }, 27 | { "Norbert", "Asia/Novosibirsk" }, 28 | { "Samuel", "Asia/Singapore" }, 29 | { "Paula", "Australia/Perth" }, 30 | { "Susan", "Australia/Sydney" }, 31 | }; 32 | 33 | display_local_meeting_times(os, meeting_zt, participants); 34 | 35 | fmt::print(os, "\n"); 36 | } 37 | -------------------------------------------------------------------------------- /src/chapter_06_algorithms_and_data_structures/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_06_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_045_priority_queue.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_046_circular_buffer.cpp" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_047_double_buffer.cpp" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_048_most_frequent_element_in_a_range.cpp" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_049_text_histogram.cpp" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_050_filtering_a_list_of_phone_numbers.cpp" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_051_transforming_a_list_of_phone_numbers.cpp" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_052_generating_all_the_permutations_of_a_string.cpp" 10 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_053_average_rating_of_movies.cpp" 11 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_054_pairwise_algorithm.cpp" 12 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_055_zip_algorithm.cpp" 13 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_056_select_algorithm.cpp" 14 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_057_quicksort.cpp" 15 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_058_shortest_path_between_two_nodes.cpp" 16 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_059_weasel_program.cpp" 17 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_060_game_of_life.cpp" 18 | PARENT_SCOPE 19 | ) 20 | -------------------------------------------------------------------------------- /src/chapter_06_algorithms_and_data_structures/problem_054_pairwise_algorithm.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_06_algorithms_and_data_structures/problem_054_pairwise_algorithm.h" 2 | 3 | #include 4 | #include 5 | #include // adjacent_difference 6 | #include 7 | 8 | 9 | // Pairwise algorithm 10 | // 11 | // Write a general-purpose function that, given a range, returns a new range with pairs of consecutive elements from the input range. 12 | // Should the input range have an odd number of elements, the last one must be ignored. 13 | // For example, if the input range was { 1, 1, 3, 5, 8, 13, 21 }, the result must be { { 1, 1 }, { 3, 5 }, { 8, 13 } }. 14 | void problem_54_main(std::ostream& os) { 15 | using namespace tmcppc::problem_54; 16 | 17 | std::vector v_1(6, 1); 18 | std::vector v_2(7, 1); // v_2 has an odd number of elements 19 | 20 | // Fill vectors with the Fibonacci sequence 21 | std::adjacent_difference(begin(v_1), prev(end(v_1)), next(begin(v_1)), std::plus<>{}); 22 | std::adjacent_difference(begin(v_2), prev(end(v_2)), next(begin(v_2)), std::plus<>{}); 23 | 24 | fmt::print(os, "Zipping {} with next: {}\n", v_1, zip_with_next(std::as_const(v_1))); 25 | fmt::print(os, "Zipping {} with next: {}\n\n", v_2, zip_with_next(std::as_const(v_1))); 26 | } 27 | -------------------------------------------------------------------------------- /src/chapter_06_algorithms_and_data_structures/problem_055_zip_algorithm.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_06_algorithms_and_data_structures/problem_055_zip_algorithm.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | // Zip algorithm 10 | // 11 | // Write a function that, given two ranges, returns a new range with pairs of elements from the two ranges. 12 | // Should the two ranges have different sizes, the result must contain as many elements as the smallest of the input ranges. 13 | // For example, if the input ranges were { 1, 2, 3 , 4, 5, 6, 7, 8, 9, 10 } and { 1, 1, 3, 5, 8, 13, 21 }, 14 | // the result should be { { 1, 1 }, { 2, 1 }, { 3, 3 }, { 4, 5 }, { 5, 8 }, { 6, 13 }, {7, 21} }. 15 | void problem_55_main(std::ostream& os) { 16 | using namespace tmcppc::problem_55; 17 | 18 | const std::vector rng_1{ 1, 2, 3 , 4, 5, 6, 7, 8, 9, 10 }; 19 | const std::vector rng_2{ 1, 1, 3, 5, 8, 13, 21 }; 20 | const std::vector rng_3{ 'a', 'b', 'c', 'd', 'e' }; 21 | 22 | fmt::print(os, "Zipping {} and {}:\n", rng_1, rng_2); 23 | fmt::print(os, "\t{}\n\n", zip(rng_1, rng_2)); 24 | 25 | fmt::print(os, "Zipping {} and [{}]:\n", rng_1, fmt::join(rng_3, ", ")); 26 | fmt::print(os, "\t{}\n\n", zip(rng_1, rng_3)); 27 | } 28 | -------------------------------------------------------------------------------- /src/chapter_06_algorithms_and_data_structures/problem_057_quicksort.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_06_algorithms_and_data_structures/problem_057_quicksort.h" 2 | #include "chapter_07_concurrency/quicksort.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | // Sort algorithm 10 | // 11 | // Write a function that, given a pair of random access Input Iterators to define its lower and upper bounds, 12 | // sorts the elements of the range using the quicksort algorithm. 13 | // 14 | // There should be two overloads of the function: 15 | // one that uses operator< to compare the elements of the range and put them in ascending order, 16 | // and one that uses a user-defined binary comparison function for comparing the elements 17 | void problem_57_main(std::ostream& os) { 18 | std::vector v_c{ 'z', 'A', '9', '!', 'm', 'o', 'N', '9' }; 19 | fmt::print(os, "Quicksorting [{}]: ", fmt::join(v_c, ", ")); 20 | tmcppc::algorithm::quicksort(begin(v_c), end(v_c)); 21 | fmt::print(os, "[{}]\n", fmt::join(v_c, ", ")); 22 | 23 | std::vector v_i{ 10, 15, 20, 25, 30, 35, 40 }; 24 | fmt::print(os, "Quicksorting {}: ", v_i); 25 | tmcppc::algorithm::quicksort(begin(v_i), end(v_i), [](int i, int j) { 26 | return (i % 10 - i / 10) < (j % 10 - j / 10); 27 | }); 28 | fmt::print(os, "{}\n\n", v_i); 29 | } 30 | -------------------------------------------------------------------------------- /src/chapter_07_concurrency/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_07_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_061_parallel_transform_algorithm.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_062_parallel_minmax_with_threads.cpp" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_063_parallel_minmax_with_async.cpp" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_064_parallel_sort_algorithm.cpp" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_065_thread_safe_logging.cpp" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_066_customer_service_system.cpp" 8 | PARENT_SCOPE 9 | ) 10 | -------------------------------------------------------------------------------- /src/chapter_07_concurrency/parallel_minmax.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // max_element, min_element, shuffle 4 | #include 5 | #include 6 | #include 7 | #include // iota 8 | #include 9 | #include // default_random_engine, random_device 10 | #include 11 | #include 12 | 13 | 14 | template 15 | void parallel_minmax(std::ostream& os, ParallelMinFunction&& parallel_min, ParallelMaxFunction&& parallel_max) { 16 | std::vector v(20); 17 | std::iota(std::begin(v), std::end(v), -10); 18 | std::ranges::shuffle(v, std::default_random_engine{ std::random_device{}() }); 19 | 20 | fmt::print(os, "v = {}\n\n", v); 21 | 22 | fmt::print(os, "std::min_element(v) = {}\n", 23 | *std::ranges::min_element(v)); 24 | fmt::print(os, "std::min_element(std::execution::par, v) = {}\n", 25 | *std::min_element(std::execution::par, std::cbegin(v), std::cend(v))); 26 | fmt::print(os, "parallel_min (using threads) = {}\n\n", 27 | *parallel_min(v)); 28 | 29 | fmt::print(os, "std::max_element(v) = {}\n", 30 | *std::ranges::max_element(v)); 31 | fmt::print(os, "std::max_element(std::execution::par, v) = {}\n", 32 | *std::max_element(std::execution::par, std::cbegin(v), std::cend(v))); 33 | fmt::print(os, "parallel_max (using threads) = {}\n\n", 34 | *parallel_max(v)); 35 | } 36 | -------------------------------------------------------------------------------- /src/chapter_07_concurrency/problem_061_parallel_transform_algorithm.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_07_concurrency/problem_061_parallel_transform_algorithm.h" 2 | 3 | #include // par 4 | #include 5 | #include 6 | #include // iota 7 | #include 8 | 9 | 10 | // Parallel transform algorithm 11 | // 12 | // Write a general-purpose algorithm that applies a given unary function to transform the elements of a range in parallel. 13 | // The unary operation used to transform the range must not invalidate range iterators or modify the elements of the range. 14 | // The level of parallelism, that is, the number of execution threads and the way it is achieved, is an implementation detail. 15 | void problem_61_main(std::ostream& os) { 16 | auto square = [](int n) { return n * n; }; 17 | 18 | std::vector v(10); 19 | std::vector w(10); 20 | std::iota(std::begin(v), std::end(v), 0); 21 | 22 | fmt::print(os, "v = {}\n\n", v); 23 | 24 | std::ranges::transform(v, std::begin(w), square); 25 | fmt::print(os, "std::transform(v); v = {}\n", w); 26 | 27 | std::transform(std::execution::par, std::cbegin(v), std::cend(v), std::begin(w), square); 28 | fmt::print(os, "std::transform(std::execution::par, v); v = {}\n", w); 29 | 30 | tmcppc::algorithm::parallel_transform(std::cbegin(v), std::cend(v), std::begin(w), square); 31 | fmt::print(os, "parallel_transform(v); v = {}\n\n", w); 32 | } 33 | -------------------------------------------------------------------------------- /src/chapter_07_concurrency/problem_062_parallel_minmax_with_threads.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_07_concurrency/problem_062_parallel_minmax_with_threads.h" 2 | #include "parallel_minmax.h" 3 | 4 | #include 5 | 6 | 7 | // Parallel min and max element algorithms using threads 8 | // 9 | // Implement general-purpose parallel algorithms that find the minimum value and, respectively, the maximum value in a given range. 10 | // The parallelism should be implemented using threads, although the number of concurrent threads is an implementation detail. 11 | void problem_62_main(std::ostream& os) { 12 | parallel_minmax( 13 | os, 14 | [](auto&& rng) { return tmcppc::algorithm::thread::parallel_min(rng); }, 15 | [](auto&& rng) { return tmcppc::algorithm::thread::parallel_max(rng); } 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /src/chapter_07_concurrency/problem_063_parallel_minmax_with_async.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_07_concurrency/problem_063_parallel_minmax_with_async.h" 2 | #include "parallel_minmax.h" 3 | 4 | #include 5 | 6 | 7 | // Parallel min and max element algorithms using asynchronous functions 8 | // 9 | // Implement general-purpose parallel algorithms that find the minimum value and, respectively, the maximum value in a given range. 10 | // The parallelism should be implemented using asynchronous functions, 11 | // although the number of concurrent functions is an implementation detail. 12 | void problem_63_main(std::ostream& os) { 13 | parallel_minmax( 14 | os, 15 | [](auto&& rng) { return tmcppc::algorithm::async::parallel_min(rng); }, 16 | [](auto&& rng) { return tmcppc::algorithm::async::parallel_max(rng); } 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/chapter_07_concurrency/problem_064_parallel_sort_algorithm.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_07_concurrency/problem_064_parallel_sort_algorithm.h" 2 | 3 | #include // shuffle, sort 4 | #include 5 | #include 6 | #include // iota 7 | #include // default_random_engine, random_device 8 | #include 9 | 10 | 11 | // Parallel sort algorithm 12 | // 13 | // Write a parallel version of the sort algorithm 14 | // as defined for problem "57. Sort Algorithm", in "Chapter 6, Algorithms and Data Structures", 15 | // which, given a pair of random access iterators to define its lower and upper bounds, 16 | // sorts the elements of the range using the quicksort algorithm. 17 | // The function should use the comparison operators for comparing the elements of the range. 18 | // The level of parallelism and the way to achieve it is an implementation detail. 19 | void problem_64_main(std::ostream& os) { 20 | std::vector v(20); 21 | std::iota(std::begin(v), std::end(v), -10); 22 | std::ranges::shuffle(v, std::default_random_engine{ std::random_device{}() }); 23 | 24 | fmt::print(os, "v = {}\n\n", v); 25 | { 26 | auto w{ v }; 27 | std::ranges::sort(w); 28 | fmt::print(os, "std::sort(v); v = {}\n", w); 29 | } 30 | { 31 | auto w{ v }; 32 | tmcppc::algorithm::quicksort(std::begin(w), std::end(w)); 33 | fmt::print(os, "quicksort(v); v = {}\n", w); 34 | } 35 | { 36 | auto w{ v }; 37 | tmcppc::algorithm::parallel_quicksort(std::begin(w), std::end(w)); 38 | fmt::print(os, "parallel_quicksort; v = {}\n\n", w); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/chapter_07_concurrency/problem_066_customer_service_system.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_07_concurrency/problem_066_customer_service_system.h" 2 | 3 | #include 4 | #include 5 | #include // read_positive_number 6 | 7 | 8 | // Customer service system 9 | // 10 | // Write a program that simulates the way customers are served in an office. 11 | // The office has three desks where customers can be served at the same time. 12 | // Customers can enter the office at any time. 13 | // They take a ticket with a service number from a ticketing machine and 14 | // wait until their number is next for service at one of the desks. 15 | // Customers are served in the order they entered the office, or more precisely, 16 | // in the order given by their ticket. 17 | // Every time a service desk finishes serving a customer, the next customer in order is served. 18 | // The simulation should stop after a particular number of customers have been issued tickets and served. 19 | void problem_66_main(std::istream& is, std::ostream& os) { 20 | using namespace rtc::console; 21 | using namespace tmcppc::office; 22 | 23 | size_t number_of_customers{ static_cast( 24 | read_positive_number(is, os, "Please enter the number of customers (between 1 and 100): ", 1, 101) 25 | ) }; 26 | size_t number_of_desks{ static_cast( 27 | read_positive_number(is, os, "Please enter the number of desks (between 1 and 10): ", 1, 11) 28 | ) }; 29 | 30 | office_simulator office_simulator{ number_of_customers, number_of_desks }; 31 | office_simulator.run(os); 32 | 33 | fmt::print(os, "\n"); 34 | } 35 | -------------------------------------------------------------------------------- /src/chapter_08_design_patterns/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_08_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_067_validating_passwords.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_068_generating_random_passwords.cpp" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_069_generating_social_security_numbers.cpp" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_070_approval_system.cpp" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_071_observable_vector_container.cpp" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_072_computing_order_price_with_discounts.cpp" 8 | PARENT_SCOPE 9 | ) 10 | -------------------------------------------------------------------------------- /src/chapter_08_design_patterns/problem_068_generating_random_passwords.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_08_design_patterns/problem_068_generating_random_passwords.h" 2 | 3 | #include 4 | #include // make_unique 5 | #include 6 | 7 | 8 | // Generating random passwords 9 | // 10 | // Write a program that can generate random passwords according to some predefined rules. 11 | // Every password must have a configurable minimum length. 12 | // In addition, it should be possible to include in the generation rules such as the presence of at least one digit, 13 | // symbol, lower or uppercase character, and so on. These additional rules must be configurable and composable. 14 | void problem_68_main(std::ostream& os) { 15 | using namespace tmcppc::password; 16 | 17 | auto g{ std::make_unique() }; 18 | 19 | g->add_generator(std::make_unique(2)); 20 | g->add_generator(std::make_unique>(2)); 21 | g->add_generator(std::make_unique>(2)); 22 | g->add_generator(std::make_unique>(2)); 23 | 24 | fmt::print(os, "Creating a password with 2 symbols, 2 digits, 2 lowercase letters, and 2 uppercase letters: {}\n\n", g->generate()); 25 | } 26 | -------------------------------------------------------------------------------- /src/chapter_09_data_serialization/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_09_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_073_xml_serialization.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_074_using_xpath.cpp" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_075_json_serialization.cpp" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_076_json_deserialization.cpp" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_077_printing_a_list_of_movies_to_a_pdf.cpp" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_078_creating_a_pdf_from_a_collection_of_images.cpp" 8 | "${pugixml_SOURCE_DIR}/src/pugixml.cpp" 9 | PARENT_SCOPE 10 | ) 11 | -------------------------------------------------------------------------------- /src/chapter_09_data_serialization/problem_076_json_deserialization.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_09_data_serialization/problem_075_json_serialization.h" 2 | #include "chapter_09_data_serialization/problem_076_json_deserialization.h" 3 | 4 | 5 | // Deserializing data from JSON 6 | // 7 | // Consider a JSON file with a list of movies as shown in the previous problem. 8 | // Write a program that can deserialize its content. 9 | void problem_76_main(std::ostream& os) { 10 | // Problem 75 already tests serialization-to and deserialization-from JSON files 11 | problem_75_main(os); 12 | } 13 | -------------------------------------------------------------------------------- /src/chapter_09_data_serialization/problem_078_creating_a_pdf_from_a_collection_of_images.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_09_data_serialization/pdf/images_doc.h" 2 | #include "chapter_09_data_serialization/pdf/image_list_layouter.h" 3 | #include "chapter_09_data_serialization/problem_078_creating_a_pdf_from_a_collection_of_images.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | // Creating a PDF from a collection of images 11 | // 12 | // Write a program that can create a PDF document that contains images from a user-specified directory. 13 | // The images must be displayed one after another. 14 | // If an image does not fit on the remainder of a page, it must be placed on the next page. 15 | void problem_78_main(std::ostream& os) { 16 | using namespace tmcppc::pdf; 17 | 18 | const auto input_dir_path{ tmcppc::env::get_instance().get_resource_folder_path() / "images" }; 19 | const auto temp_file_path{ std::filesystem::temp_directory_path() / "list_of_images.pdf" }; 20 | 21 | try { 22 | images_doc out_doc{ input_dir_path }; 23 | fmt::print(os, "Writing PDF out to: {}\n\n", temp_file_path.generic_string()); 24 | out_doc.save_to(temp_file_path, std::make_unique()); 25 | } catch (const std::exception& err) { 26 | fmt::print(os, "Error: {}\n\n", err.what()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/chapter_10_archives_images_and_databases/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_10_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_079_finding_files_in_a_zip_archive.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_080_zip_compression.cpp" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_081_zip_compression_with_password.cpp" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_082_national_flag_png.cpp" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_083_verification_text_png.cpp" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_084_ean_13_barcode_generator.cpp" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_085_reading_from_an_sqlite_db.cpp" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_086_inserting_into_an_sqlite_db.cpp" 10 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_087_handling_images_in_an_sqlite_db.cpp" 11 | PARENT_SCOPE 12 | ) 13 | -------------------------------------------------------------------------------- /src/chapter_10_archives_images_and_databases/problem_080_zip_compression.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_10_archives_images_and_databases/problem_080_zip_compression.h" 2 | #include "chapter_10_archives_images_and_databases/problem_081_zip_compression_with_password.h" 3 | #include "chapter_10_archives_images_and_databases/zip/zip_lib_wrapper.h" 4 | 5 | 6 | // Compressing and decompressing files to/from a ZIP archive 7 | // 8 | // Write a program that can do the following: 9 | // - Compress either a file or the contents of a user-specified directory, recursively, to a ZIP archive. 10 | // - Decompress the contents of a ZIP archive to a user-specified destination directory. 11 | void problem_80_main(std::istream& is, std::ostream& os) { 12 | using namespace tmcppc::problem_81; 13 | 14 | // Problem 81 tests compression-to and decompression-from ZIP files 15 | test_zip_lib(is, os); 16 | } 17 | -------------------------------------------------------------------------------- /src/chapter_10_archives_images_and_databases/problem_084_ean_13_barcode_generator.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_10_archives_images_and_databases/ean_13/barcode.h" 2 | #include "chapter_10_archives_images_and_databases/ean_13/barcode_png_generator.h" 3 | #include "chapter_10_archives_images_and_databases/problem_084_ean_13_barcode_generator.h" 4 | 5 | #include 6 | #include 7 | 8 | 9 | // EAN-13 barcode generator 10 | // 11 | // Write a program that can generate a PNG image with an EAN-13 barcode for any international article number in version 13 of the standard. 12 | // For simplicity, the image should only contain the barcode and can skip the EAN-13 number printed under the barcode. 13 | void problem_84_main(std::ostream& os) { 14 | auto code_png_generator{ tmcppc::ean_13::barcode_png::generator{} }; 15 | for (auto&& code_str : { "2407014001944", "9781123123456", "5012345678900" }) { 16 | const auto image_file_path{ tmcppc::png::create_png_file_path(std::filesystem::temp_directory_path(), code_str) }; 17 | fmt::print(os, "Creating {}...\n\n", image_file_path.generic_string()); 18 | 19 | code_png_generator(tmcppc::ean_13::barcode{ code_str }, 1.0, image_file_path); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/chapter_11_cryptography/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_11_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_088_caesar_cipher.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_089_vigenere_cipher.cpp" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_090_base64_encoding.cpp" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_091_validating_user_credentials.cpp" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_092_computing_file_hashes.cpp" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_093_aes_encryption.cpp" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_094_file_signing.cpp" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/vigenere.cpp" 10 | PARENT_SCOPE 11 | ) 12 | -------------------------------------------------------------------------------- /src/chapter_11_cryptography/problem_088_caesar_cipher.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_11_cryptography/caesar.h" 2 | #include "chapter_11_cryptography/crypt.h" 3 | #include "chapter_11_cryptography/problem_088_caesar_cipher.h" 4 | #include "env.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | // Caesar cipher 12 | // 13 | // Write a program that can encrypt and decrypt messages using a Caesar cipher with a right rotation and any shift value. 14 | // For simplicity, the program should consider only uppercase text messages and only encode letters, 15 | // ignoring digits, symbols, and other types of characters. 16 | void problem_88_main(std::ostream& os) { 17 | using namespace tmcppc::crypto; 18 | using crypt = tmcppc::crypto::crypt; 19 | 20 | const auto input_file_path{ tmcppc::env::get_instance().get_resource_folder_path() / "sample_file.txt" }; 21 | const auto input_file_content{ rtc::filesystem::get_text_file_content(input_file_path) }; 22 | 23 | const std::unique_ptr crypt_up{ std::make_unique() }; 24 | 25 | fmt::print(os, "Encrypting and decrypting file '{}'\n", input_file_path.generic_string()); 26 | const auto encrypted_file_content{ crypt_up->encrypt(input_file_content) }; 27 | const auto decrypted_file_content{ crypt_up->decrypt(encrypted_file_content) }; 28 | 29 | if (input_file_content == decrypted_file_content) { 30 | fmt::print(os, "\tOK\n"); 31 | } else { 32 | fmt::print(os, "\tError: the decrypted content differs from the original content\n"); 33 | } 34 | 35 | fmt::print(os, "\n"); 36 | } 37 | -------------------------------------------------------------------------------- /src/chapter_11_cryptography/problem_089_vigenere_cipher.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_11_cryptography/crypt.h" 2 | #include "chapter_11_cryptography/problem_089_vigenere_cipher.h" 3 | #include "chapter_11_cryptography/vigenere.h" 4 | #include "env.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | // Vigenere cipher 12 | // 13 | // Write a program that can encrypt and decrypt messages using the Vigenere cipher. 14 | // For simplicity, the input plain-text messages for encryption should consist of only uppercase letters. 15 | void problem_89_main(std::ostream& os) { 16 | using namespace tmcppc::crypto; 17 | using crypt = tmcppc::crypto::crypt; 18 | 19 | const auto input_file_path{ tmcppc::env::get_instance().get_resource_folder_path() / "sample_file.txt" }; 20 | const auto input_file_content{ rtc::filesystem::get_text_file_content(input_file_path) }; 21 | 22 | const std::unique_ptr crypt_up{ std::make_unique() }; 23 | 24 | fmt::print(os, "Encrypting and decrypting file '{}'\n", input_file_path.generic_string()); 25 | const auto encrypted_file_content{ crypt_up->encrypt(input_file_content) }; 26 | const auto decrypted_file_content{ crypt_up->decrypt(encrypted_file_content) }; 27 | 28 | if (input_file_content == decrypted_file_content) { 29 | fmt::print(os, "\tOK\n"); 30 | } else { 31 | fmt::print(os, "\tError: the decrypted content differs from the original content\n"); 32 | } 33 | 34 | fmt::print(os, "\n"); 35 | } 36 | -------------------------------------------------------------------------------- /src/chapter_11_cryptography/problem_091_validating_user_credentials.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_11_cryptography/problem_091_validating_user_credentials.h" 2 | 3 | #include 4 | #include 5 | 6 | 7 | // Validating user credentials 8 | // 9 | // Write a program that simulates the way users authenticate to a secured system. 10 | // In order to log in, a user must be already registered with the system. 11 | // The user enters a username and a password and the program checks if it matches any of its registered users; 12 | // if it does, the user is granted access, otherwise, the operation fails. 13 | // For security reasons, the system must not record the password but use an SHA hash instead. 14 | void problem_91_main(std::istream& is, std::ostream& os) { 15 | using namespace tmcppc::crypto; 16 | 17 | login_simulator{ is, os }.run(); 18 | fmt::print(os, "\n"); 19 | } 20 | -------------------------------------------------------------------------------- /src/chapter_11_cryptography/problem_092_computing_file_hashes.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_11_cryptography/problem_092_computing_file_hashes.h" 2 | #include "env.h" 3 | 4 | #include // MD5 5 | #include // SHA1, SHA256 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | // Computing file hashes 12 | // 13 | // Write a program that, given a path to a file, computes and prints to the console 14 | // the SHA1, SHA256, and MD5 hash values for the content of the file. 15 | void problem_92_main(std::ostream& os) { 16 | using namespace tmcppc::crypto; 17 | 18 | const auto input_file_path{ tmcppc::env::get_instance().get_resource_folder_path() / "fonts" / "calibri.ttf" }; 19 | 20 | fmt::print(os, "Calculating SHA1, SHA256 and MD5 for file '{}'\n", input_file_path.generic_string()); 21 | 22 | fmt::print(os, "\tSHA1: '{}'\n", get_hash_as_hex_string(input_file_path)); 23 | fmt::print(os, "\tSHA256: '{}'\n", get_hash_as_hex_string(input_file_path)); 24 | fmt::print(os, "\tMD5: '{}'\n", get_hash_as_hex_string(input_file_path)); 25 | 26 | fmt::print(os, "\n"); 27 | } 28 | -------------------------------------------------------------------------------- /src/chapter_11_cryptography/vigenere.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_11_cryptography/vigenere.h" 2 | 3 | 4 | namespace tmcppc::crypto { 5 | /* static */ constexpr vigenere::square_t vigenere::square_{ vigenere::build_square() }; 6 | } // namespace tmcppc::crypto 7 | -------------------------------------------------------------------------------- /src/chapter_12_networking_and_services/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_12_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_095_finding_the_ip_address_of_a_host.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_096_fizz_buzz_client_server_application.cpp" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_097_bitcoin_exchange_rates.cpp" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_098_fetching_emails_using_imap.cpp" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_099_translating_text.cpp" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_100_detecting_faces_in_a_picture.cpp" 8 | PARENT_SCOPE 9 | ) 10 | -------------------------------------------------------------------------------- /src/chapter_12_networking_and_services/problem_095_finding_the_ip_address_of_a_host.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_12_networking_and_services/problem_095_finding_the_ip_address_of_a_host.h" 2 | #include "chapter_12_networking_and_services/tcp/resolver.h" 3 | 4 | #include 5 | #include 6 | #include // pair 7 | #include 8 | 9 | #define BOOST_ASIO_STANDALONE 10 | #include 11 | 12 | 13 | // Finding the IP address of a host 14 | // 15 | // Write a program that can retrieve and print the IPv4 address of a host. 16 | // If multiple addresses are found, then all of them should be printed. 17 | // The program should work on all platforms 18 | void problem_95_main(std::ostream& os) { 19 | using namespace tmcppc::tcp; 20 | 21 | asio::io_context io_context{}; 22 | resolver_asio resolver{ io_context }; 23 | for (auto&& [host, service] : std::vector>{ 24 | { "localhost", "8080" }, 25 | { "www.boost.org", "http" }, 26 | { "www.google.com", "https" }, 27 | { "www.---.com", "http" }, 28 | { "www.boost.org", "blah" } }) { 29 | 30 | fmt::print(os, "Getting IPv4 addresses for host = '{}' and service = '{}'\n", host, service); 31 | try { 32 | for (auto&& address : resolver.get_host_ipv4_addresses(host, service)) { 33 | fmt::print(os, "\t{}\n", address); 34 | } 35 | } catch (const std::exception& ex) { 36 | fmt::print(os, "\tError: {}\n", ex.what()); 37 | } 38 | } 39 | 40 | fmt::print(os, "\n"); 41 | } 42 | -------------------------------------------------------------------------------- /src/chapter_12_networking_and_services/problem_097_bitcoin_exchange_rates.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_12_networking_and_services/bitcoin/connection.h" 2 | #include "chapter_12_networking_and_services/problem_097_bitcoin_exchange_rates.h" 3 | 4 | #include 5 | #include // make_unique 6 | #include 7 | 8 | 9 | // Bitcoin exchange rates 10 | // 11 | // Write a program that displays Bitcoin exchange rates for the most important currencies (such as USD, EUR, or GBP). 12 | // The exchange rates must be fetched from an online service, such as: https://blockchain.info 13 | void problem_97_main(std::ostream& os) { 14 | using namespace tmcppc::bitcoin; 15 | 16 | bitcoin_connection connection{ std::make_unique() }; 17 | try { 18 | fmt::print(os, "Current bitcoin exchange rates:\n{}\n", connection.get_current_exchange_rates()); 19 | } catch (const std::exception& ex) { 20 | fmt::print(os, "Error: {}\n", ex.what()); 21 | } 22 | 23 | fmt::print(os, "\n"); 24 | } 25 | -------------------------------------------------------------------------------- /test/chapter_01_math/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_01_test_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/digits.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/math.cpp" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_001_sum_of_naturals_divisible_by_3_or_5.cpp" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_002_greatest_common_divisor.cpp" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_003_least_common_multiple.cpp" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_004_largest_prime_smaller_than_given_number.cpp" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_005_sexy_prime_pairs.cpp" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_006_abundant_numbers.cpp" 10 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_007_amicable_numbers.cpp" 11 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_008_armstrong_numbers.cpp" 12 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_009_prime_factors.cpp" 13 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_010_gray_code.cpp" 14 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_011_converting_numerical_values_to_roman.cpp" 15 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_012_longest_collatz_sequence.cpp" 16 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_013_computing_the_value_of_pi.cpp" 17 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_014_validating_isbns.cpp" 18 | "${CMAKE_CURRENT_SOURCE_DIR}/roman.cpp" 19 | PARENT_SCOPE 20 | ) 21 | -------------------------------------------------------------------------------- /test/chapter_01_math/digits.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_01_math/digits.h" 2 | 3 | #include 4 | 5 | using namespace tmcppc::math; 6 | 7 | 8 | TEST(size, n_0) { digits d{}; EXPECT_EQ(d.size(), 1); } 9 | TEST(size, n_1000) { digits d{1000}; EXPECT_EQ(d.size(), 4); } 10 | 11 | TEST(to_string, n_0) { digits d{}; EXPECT_EQ(d.to_string(), "0"); } 12 | TEST(to_string, n_1000) { digits d{ 1000 }; EXPECT_EQ(d.to_string(), "1000"); } 13 | 14 | TEST(pre_increment, n_0) { digits d{}; EXPECT_EQ((++d).to_string(), "1"); } 15 | TEST(pre_increment, n_9) { digits d{9}; EXPECT_EQ((++d).to_string(), "10"); } 16 | 17 | TEST(pre_decrement, n_0) { digits d{}; EXPECT_EQ((--d).to_string(), "0"); } 18 | TEST(pre_decrement, n_10) { digits d{10}; EXPECT_EQ((--d).to_string(), "9"); } 19 | -------------------------------------------------------------------------------- /test/chapter_01_math/problem_001_sum_of_naturals_divisible_by_3_or_5.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_01_math/problem_001_sum_of_naturals_divisible_by_3_or_5.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace tmcppc::problem_1; 8 | 9 | 10 | TEST(sum_of_naturals_divisible_by_3_and_5, v1_with_number_0) { 11 | EXPECT_EQ(naturals_divisible_by_3_or_5_up_to_limit_v1(0), std::vector{ 0 }); 12 | } 13 | 14 | TEST(sum_of_naturals_divisible_by_3_and_5, v2_with_number_0) { 15 | EXPECT_EQ(naturals_divisible_by_3_or_5_up_to_limit_v2(0), std::vector{ 0 }); 16 | } 17 | 18 | TEST(sum_of_naturals_divisible_by_3_and_5, v1_with_number_47) { 19 | EXPECT_THAT( 20 | naturals_divisible_by_3_or_5_up_to_limit_v1(47), 21 | ::testing::ElementsAre(0, 3, 5, 6, 9, 10, 12, 15, 18, 20, 21, 24, 25, 27, 30, 33, 35, 36, 39, 40, 42, 45)); 22 | } 23 | 24 | TEST(sum_of_naturals_divisible_by_3_and_5, v2_with_number_47) { 25 | EXPECT_THAT( 26 | naturals_divisible_by_3_or_5_up_to_limit_v2(47), 27 | ::testing::ElementsAre(0, 3, 5, 6, 9, 10, 12, 15, 18, 20, 21, 24, 25, 27, 30, 33, 35, 36, 39, 40, 42, 45)); 28 | } 29 | 30 | TEST(problem_1_main, number_47) { 31 | std::istringstream iss{ "47\n" }; 32 | std::ostringstream oss{}; 33 | problem_1_main(iss, oss); 34 | EXPECT_THAT(oss.str(), ::testing::HasSubstr( 35 | "The sum of all natural numbers divisible by either 3 or 5 and up to 47 is:\n\t" 36 | "495 [0, 3, 5, 6, 9, 10, 12, 15, 18, 20, 21, 24, 25, 27, 30, 33, 35, 36, 39, 40, 42, 45]\n\n")); 37 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 38 | } 39 | -------------------------------------------------------------------------------- /test/chapter_01_math/problem_003_least_common_multiple.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_01_math/problem_003_least_common_multiple.h" 2 | 3 | #include 4 | #include 5 | #include // runtime_error 6 | #include 7 | 8 | using namespace tmcppc::problem_3; 9 | 10 | 11 | TEST(lcm, empty_v) { EXPECT_THROW(lcm(std::vector{}), std::runtime_error); } 12 | TEST(lcm, zero_element) { EXPECT_THROW(lcm(std::vector{ 10, 0 }), std::runtime_error); } 13 | TEST(lcm, negative_element) { EXPECT_THROW(lcm(std::vector{ -5, 10 }), std::runtime_error); } 14 | TEST(lcm, v_15_50) { EXPECT_EQ(lcm(std::vector{ 15, 50 }), 150); } 15 | 16 | TEST(problem_3_main, v_15_50) { 17 | std::istringstream iss{ "15 50 quit\n" }; 18 | std::ostringstream oss{}; 19 | problem_3_main(iss, oss); 20 | EXPECT_THAT(oss.str(), ::testing::HasSubstr("The least common multiple of [15, 50] is: 150\n\n")); 21 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 22 | } 23 | -------------------------------------------------------------------------------- /test/chapter_01_math/problem_004_largest_prime_smaller_than_given_number.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_01_math/problem_004_largest_prime_smaller_than_given_number.h" 2 | 3 | #include 4 | #include 5 | #include // istringstream, ostringstream 6 | 7 | using namespace tmcppc::problem_4; 8 | 9 | 10 | TEST(biggest_prime_smaller_than, zero) { EXPECT_EQ(biggest_prime_smaller_than(0), 0); } 11 | TEST(biggest_prime_smaller_than, one) { EXPECT_EQ(biggest_prime_smaller_than(1), 0); } 12 | TEST(biggest_prime_smaller_than, two) { EXPECT_EQ(biggest_prime_smaller_than(2), 1); } 13 | TEST(biggest_prime_smaller_than, twenty) { EXPECT_EQ(biggest_prime_smaller_than(20), 19); } 14 | 15 | TEST(problem_4_main, forty_eight) { 16 | std::istringstream iss{ "48\n" }; 17 | std::ostringstream oss{}; 18 | problem_4_main(iss, oss); 19 | EXPECT_THAT(oss.str(), ::testing::HasSubstr("Biggest prime number smaller than 48 is: 47\n\n")); 20 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 21 | } 22 | -------------------------------------------------------------------------------- /test/chapter_01_math/problem_009_prime_factors.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_01_math/problem_009_prime_factors.h" 2 | 3 | #include 4 | #include 5 | #include // istringstream, ostringstream 6 | 7 | 8 | TEST(problem_9_main, n_100) { 9 | std::istringstream iss{ "100\n" }; 10 | std::ostringstream oss{}; 11 | problem_9_main(iss, oss); 12 | EXPECT_THAT(oss.str(), ::testing::HasSubstr("Prime factors of 100: [1, 2, 2, 5, 5]\n\n")); 13 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 14 | } 15 | -------------------------------------------------------------------------------- /test/chapter_01_math/problem_011_converting_numerical_values_to_roman.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_01_math/problem_011_converting_numerical_values_to_roman.h" 2 | 3 | #include 4 | #include 5 | #include // istringstream, ostringstream 6 | 7 | 8 | TEST(problem_11_main, n_2022) { 9 | std::istringstream iss{ "2022\n" }; 10 | std::ostringstream oss{}; 11 | problem_11_main(iss, oss); 12 | EXPECT_THAT(oss.str(), ::testing::HasSubstr( 13 | "Number\tRoman numeral equivalent\n" 14 | "2022\tMMXXII\n\n" 15 | )); 16 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 17 | } 18 | -------------------------------------------------------------------------------- /test/chapter_01_math/problem_013_computing_the_value_of_pi.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_01_math/problem_013_computing_the_value_of_pi.h" 2 | 3 | #include 4 | #include 5 | #include // ostringstream 6 | 7 | using namespace tmcppc::problem_13; 8 | 9 | 10 | TEST(compute_pi, n_10) { EXPECT_NEAR(compute_pi(10), 3.14159, 0.9); } 11 | TEST(compute_pi, n_100) { EXPECT_NEAR(compute_pi(100), 3.14159, 0.2); } 12 | TEST(compute_pi, n_1000) { EXPECT_NEAR(compute_pi(1'000), 3.14159, 0.1); } 13 | TEST(compute_pi, n_10_000) { EXPECT_NEAR(compute_pi(10'000), 3.14159, 0.05); } 14 | TEST(compute_pi, n_100_000) { EXPECT_NEAR(compute_pi(100'000), 3.14159, 0.01); } 15 | TEST(compute_pi, n_1_000_000) { EXPECT_NEAR(compute_pi(1'000'000), 3.14159, 0.01); } 16 | TEST(compute_pi, n_10_000_000) { EXPECT_NEAR(compute_pi(10'000'000), 3.14159, 0.01); } 17 | 18 | TEST(problem_13_main, value_of_pi_with_a_precision_of_two_decimal_digits) { 19 | std::ostringstream oss{}; 20 | problem_13_main(oss); 21 | EXPECT_THAT(oss.str(), ::testing::HasSubstr("Estimated value of pi: 3.14")); 22 | EXPECT_THAT(oss.str(), ::testing::EndsWith("\n\n")); 23 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 24 | } 25 | -------------------------------------------------------------------------------- /test/chapter_02_language_features/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Subdirectories 2 | add_subdirectory(temperature) 3 | 4 | 5 | set(chapter_02_test_sources 6 | ${chapter_02_test_temperature_sources} 7 | "${CMAKE_CURRENT_SOURCE_DIR}/array_2d.cpp" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/ipv4.cpp" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/ipv4_range.cpp" 10 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_015_ipv4_data_type.cpp" 11 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_016_enumerating_ipv4_addresses_in_a_range.cpp" 12 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_017_array_2d.cpp" 13 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_018_variadic_minimum_function.cpp" 14 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_019_adding_a_range_of_values_to_a_container.cpp" 15 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_020_contains_any_all_or_none_from_a_range.cpp" 16 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_021_system_handle_wrapper.cpp" 17 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_022_temperature_scales_literals.cpp" 18 | "${CMAKE_CURRENT_SOURCE_DIR}/unique_hdl.cpp" 19 | PARENT_SCOPE 20 | ) 21 | -------------------------------------------------------------------------------- /test/chapter_02_language_features/problem_015_ipv4_data_type.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_02_language_features/problem_015_ipv4_data_type.h" 2 | 3 | #include 4 | #include 5 | #include // istringstream, ostringstream 6 | 7 | 8 | TEST(problem_15_main, ip_127_0_0_1_and_abc) { 9 | std::istringstream iss{ "127.0.0.1\nabc\nquit\n" }; 10 | std::ostringstream oss{}; 11 | problem_15_main(iss, oss); 12 | EXPECT_THAT(oss.str(), ::testing::HasSubstr("\tYou've entered a valid IPv4 address: 127.0.0.1\n")); 13 | EXPECT_THAT(oss.str(), ::testing::HasSubstr("\tError: invalid IPv4 address: abc\n")); 14 | EXPECT_THAT(oss.str(), ::testing::EndsWith("\n")); 15 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n"))); 16 | } 17 | -------------------------------------------------------------------------------- /test/chapter_02_language_features/problem_016_enumerating_ipv4_addresses_in_a_range.cpp: -------------------------------------------------------------------------------- 1 | #include "../console/fake.h" 2 | #include "chapter_02_language_features/problem_016_enumerating_ipv4_addresses_in_a_range.h" 3 | 4 | #include 5 | #include 6 | #include // istringstream, ostringstream 7 | 8 | using namespace tmcppc::system; 9 | 10 | 11 | TEST(problem_16_main, invalid_and_invalid_range_and_valid) { 12 | std::istringstream iss{ "127.0.0.1\n300.300.300.300\n127.0.0.1 1.1.1.1\n127.0.0.1 127.0.0.5\n" }; 13 | std::ostringstream oss{}; 14 | problem_16_main(iss, oss, console{ std::make_unique() }); 15 | EXPECT_THAT(oss.str(), ::testing::HasSubstr("\tError: invalid input.\n")); 16 | EXPECT_THAT(oss.str(), ::testing::HasSubstr("\tError: range start address is bigger than range end address.\n")); 17 | EXPECT_THAT(oss.str(), ::testing::HasSubstr( 18 | "\t127.0.0.1\n" 19 | "\t127.0.0.2\n" 20 | "\t127.0.0.3\n" 21 | "\t127.0.0.4\n" 22 | "\t127.0.0.5\n\n" 23 | )); 24 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 25 | } 26 | -------------------------------------------------------------------------------- /test/chapter_02_language_features/problem_021_system_handle_wrapper.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_02_language_features/problem_021_system_handle_wrapper.h" 2 | 3 | #include // transform 4 | #include 5 | #include 6 | #include // wstring 7 | 8 | 9 | TEST(problem_21_main, output) { 10 | std::wostringstream woss{}; 11 | problem_21_main(woss); 12 | std::wstring woss_str{ woss.str() }; 13 | std::string oss_str(woss_str.size(), 0); 14 | std::ranges::transform(woss_str, std::begin(oss_str), 15 | [](wchar_t c) { return static_cast(c); 16 | }); 17 | #ifdef _WIN32 18 | EXPECT_THAT(oss_str, ::testing::ContainsRegex( 19 | "Opened: .*res/sample_file.txt" 20 | )); 21 | EXPECT_THAT(oss_str, ::testing::HasSubstr( 22 | "Read 1024 bytes from file\n" 23 | "Error: I'm a throwing function!\n\n" 24 | )); 25 | #endif 26 | EXPECT_THAT(oss_str, ::testing::Not(::testing::EndsWith("\n\n\n"))); 27 | } 28 | -------------------------------------------------------------------------------- /test/chapter_02_language_features/temperature/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Subdirectories 2 | add_subdirectory(v1) 3 | add_subdirectory(v2) 4 | 5 | 6 | set(chapter_02_test_temperature_sources 7 | ${chapter_02_test_temperature_v1_sources} 8 | ${chapter_02_test_temperature_v2_sources} 9 | PARENT_SCOPE 10 | ) 11 | -------------------------------------------------------------------------------- /test/chapter_02_language_features/temperature/v1/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_02_test_temperature_v1_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/temperature.cpp" 3 | PARENT_SCOPE 4 | ) 5 | -------------------------------------------------------------------------------- /test/chapter_02_language_features/temperature/v2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_02_test_temperature_v2_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/temperature.cpp" 3 | PARENT_SCOPE 4 | ) 5 | -------------------------------------------------------------------------------- /test/chapter_03_strings_and_regular_expressions/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_03_test_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_023_binary_to_string_conversion.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_024_string_to_binary_conversion.cpp" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_025_capitalizing_an_article_title.cpp" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_026_joining_strings_with_delimiter.cpp" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_027_splitting_a_string_into_tokens.cpp" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_028_longest_palindromic_substring.cpp" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_029_license_plate_validation.cpp" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_030_extracting_url_parts.cpp" 10 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_031_transforming_dates_in_strings.cpp" 11 | "${CMAKE_CURRENT_SOURCE_DIR}/url.cpp" 12 | PARENT_SCOPE 13 | ) 14 | -------------------------------------------------------------------------------- /test/chapter_03_strings_and_regular_expressions/problem_023_binary_to_string_conversion.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_03_strings_and_regular_expressions/problem_023_binary_to_string_conversion.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include // iota 8 | #include 9 | #include 10 | 11 | using namespace tmcppc::problem_23; 12 | 13 | 14 | TEST(to_hex_string, empty_container) { 15 | EXPECT_EQ(to_hex_string(std::list{}), ""); 16 | } 17 | 18 | TEST(to_hex_string, array_010203040506) { 19 | std::array a{}; 20 | std::iota(std::begin(a), std::end(a), 1); 21 | EXPECT_EQ(to_hex_string(a), "010203040506"); 22 | } 23 | 24 | TEST(to_hex_string, vector_BAADF00D) { 25 | std::vector v{ 0xBA, 0xAD, 0xf0, 0x0d }; 26 | EXPECT_EQ(to_hex_string(v), "baadf00d"); 27 | } 28 | 29 | TEST(problem_23_main, output) { 30 | std::ostringstream oss{}; 31 | problem_23_main(oss); 32 | EXPECT_THAT(oss.str(), ::testing::HasSubstr( 33 | "Converting vector [0xba, 0xad, 0xf0, 0xd] to string \"baadf00d\"\n" 34 | "Converting array [0x1, 0x2, 0x3, 0x4, 0x5, 0x6] to string \"010203040506\"\n\n" 35 | )); 36 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 37 | } 38 | -------------------------------------------------------------------------------- /test/chapter_03_strings_and_regular_expressions/problem_025_capitalizing_an_article_title.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_03_strings_and_regular_expressions/problem_025_capitalizing_an_article_title.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace tmcppc::problem_25; 8 | 9 | 10 | TEST(capitalize, empty_string) { 11 | std::string result{}; 12 | EXPECT_EQ(capitalize(""), result); 13 | } 14 | TEST(capitalize, all_lowercase) { 15 | EXPECT_THAT(capitalize("the c++ challenger"), ::testing::StrEq("The C++ Challenger")); 16 | } 17 | TEST(capitalize, all_uppercase) { 18 | EXPECT_THAT(capitalize("THE C++ CHALLENGER"), ::testing::StrEq("The C++ Challenger")); 19 | } 20 | TEST(capitalize, uppercase_and_lowercase) { 21 | EXPECT_THAT(capitalize("THIS IS an ExamplE, should wORk!"), ::testing::StrEq("This Is An Example, Should Work!")); 22 | } 23 | TEST(capitalize, all_letters) { 24 | EXPECT_THAT(capitalize("SUPERCalIfragiListicoeSPialiDOSo"), ::testing::StrEq("Supercalifragilisticoespialidoso")); 25 | } 26 | 27 | TEST(problem_25_main, output) { 28 | std::ostringstream oss{}; 29 | problem_25_main(oss); 30 | EXPECT_THAT(oss.str(), ::testing::HasSubstr( 31 | "Capitalizing word \"the c++ challenger\": \"The C++ Challenger\"\n" 32 | "Capitalizing word \"THIS IS an ExamplE, should wORk!\": \"This Is An Example, Should Work!\"\n\n" 33 | )); 34 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 35 | } 36 | -------------------------------------------------------------------------------- /test/chapter_03_strings_and_regular_expressions/problem_026_joining_strings_with_delimiter.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_03_strings_and_regular_expressions/problem_026_joining_strings_with_delimiter.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace tmcppc::problem_26; 11 | 12 | 13 | TEST(join, empty_array) { 14 | std::string result{}; 15 | EXPECT_EQ(join(std::array{}, " "), result); 16 | } 17 | TEST(join, one_element_array_with_pound_delimiter) { 18 | EXPECT_THAT(join(std::array{ "Joe" }, "#"), ::testing::StrEq("Joe")); 19 | } 20 | TEST(join, vector_with_space_delimiter) { 21 | EXPECT_THAT(join(std::vector{ "this", "is", "an", "example" }, " "), ::testing::StrEq("this is an example")); 22 | } 23 | TEST(join, list_with_dashes_delimiter) { 24 | EXPECT_THAT(join(std::list{ "yet", "another", "one!" }, "---"), ::testing::StrEq("yet---another---one!")); 25 | } 26 | 27 | TEST(problem_26_main, output) { 28 | std::ostringstream oss{}; 29 | problem_26_main(oss); 30 | EXPECT_THAT(oss.str(), ::testing::HasSubstr( 31 | "Joining [] with delimiter \"#\": \n" 32 | "Joining [Joe] with delimiter \"#\": Joe\n" 33 | "Joining [this, is, an, example] with delimiter \" \": this is an example\n" 34 | "Joining [yet, another, one!] with delimiter \"---\": yet---another---one!\n\n" 35 | )); 36 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 37 | } 38 | -------------------------------------------------------------------------------- /test/chapter_03_strings_and_regular_expressions/problem_027_splitting_a_string_into_tokens.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_03_strings_and_regular_expressions/problem_027_splitting_a_string_into_tokens.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace tmcppc::problem_27; 9 | 10 | 11 | TEST(split, empty_string) { 12 | std::vector result{}; 13 | EXPECT_EQ(split("", " "), result); 14 | } 15 | TEST(split, delimiter_not_found) { 16 | EXPECT_THAT(split("a;b;c", "-"), ::testing::ElementsAre("a;b;c")); 17 | } 18 | TEST(split, delimiter_found) { 19 | EXPECT_THAT(split("a;b;c", ";"), ::testing::ElementsAre("a", "b", "c")); 20 | } 21 | TEST(split, many_delimiters) { 22 | EXPECT_THAT(split("a;b\tc", ";\t"), ::testing::ElementsAre("a", "b", "c")); 23 | } 24 | 25 | TEST(problem_27_main, output) { 26 | std::ostringstream oss{}; 27 | problem_27_main(oss); 28 | EXPECT_THAT(oss.str(), ::testing::HasSubstr( 29 | "Splitting string \"this,is.a sample!!\" using any delimiter of \",.! \" into: [this, is, a, sample]\n" 30 | "Splitting string \"this,is.a sample!!\" using any delimiter of \"#\" into: [this,is.a sample!!]\n\n" 31 | )); 32 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 33 | } 34 | -------------------------------------------------------------------------------- /test/chapter_03_strings_and_regular_expressions/problem_030_extracting_url_parts.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_03_strings_and_regular_expressions/problem_030_extracting_url_parts.h" 2 | #include "chapter_03_strings_and_regular_expressions/url.h" 3 | 4 | #include 5 | #include 6 | #include // ostringstream 7 | 8 | 9 | TEST(problem_30_main, output) { 10 | std::ostringstream oss{}; 11 | problem_30_main(oss); 12 | EXPECT_THAT(oss.str(), ::testing::HasSubstr( 13 | "Parsing URL \"http://user:pass@example.com:992/animal/bird?species=seagull#wings\":\n" 14 | "[\n" 15 | "\tProtocol: http\n" 16 | "\tLogin: user:pass\n" 17 | "\tDomain: example.com\n" 18 | "\tPort: 992\n" 19 | "\tPath: animal/bird\n" 20 | "\tQuery: species=seagull\n" 21 | "\tFragment: wings\n" 22 | "]\n" 23 | "\n" 24 | "Parsing URL \"http://example.com/animal/bird#wings\":\n" 25 | "[\n" 26 | "\tProtocol: http\n" 27 | "\tDomain: example.com\n" 28 | "\tPath: animal/bird\n" 29 | "\tFragment: wings\n" 30 | "]\n" 31 | "\n" 32 | "Error: invalid URL: \"This is not a valid URL!\"\n\n" 33 | )); 34 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 35 | } 36 | -------------------------------------------------------------------------------- /test/chapter_04_streams_and_filesystems/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_04_test_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/logger.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_032_pascal_triangle.cpp" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_033_tabular_printing_of_a_list_of_processes.cpp" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_034_removing_empty_lines_from_a_text_file.cpp" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_035_computing_the_size_of_a_directory.cpp" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_036_deleting_files_older_than_a_given_date.cpp" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_037_regex_find_files_in_a_directory.cpp" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_038_temporary_log_files.cpp" 10 | PARENT_SCOPE 11 | ) 12 | -------------------------------------------------------------------------------- /test/chapter_04_streams_and_filesystems/problem_038_temporary_log_files.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_04_streams_and_filesystems/problem_038_temporary_log_files.h" 2 | 3 | #include 4 | #include 5 | #include // ostringstream 6 | 7 | 8 | TEST(problem_38_main, output) { 9 | std::ostringstream oss{}; 10 | problem_38_main(oss); 11 | EXPECT_THAT(oss.str(), ::testing::ContainsRegex( 12 | "Creating logger_1 and logger_2 instances...\n" 13 | "Writing out to logger_1 and logger_2...\n" 14 | "\tR u awake\\? Want 2 chat\\?\n" 15 | "\tO Rom. Where4 art thou\\?\n" 16 | "\tOutside yr window.\n" 17 | "\tStalker! J/K.\n" 18 | "\tHad 2-feeln' romantc.\n" 19 | "\tB careful. My family h8 u.\n" 20 | "\tI no. What about u\\?\n" 21 | "\t'M up for marriage if u r. Is tht a bit fwd\\?\n" 22 | "\tNo. Yes. No. Oh, dsnt mat-r. 2moro @ 9\\?\n" 23 | "\tLuv U xxxx\n" 24 | "Moving logger_1 from '.*log' to '.*log_1.txt'\n" 25 | "Writing out something else to logger_1...\n" 26 | "\tCU then xxxx\n" 27 | "Moving logger_1 from '.*log_1.txt' to '.*log_1-new.txt'\n" 28 | "Asking for logger_1 location: '.*log_1-new.txt'\n\n" 29 | )); 30 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 31 | } 32 | -------------------------------------------------------------------------------- /test/chapter_05_date_and_time/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_05_test_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_039_measuring_function_execution_time.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_040_number_of_days_between_two_dates.cpp" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_041_day_of_the_week.cpp" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_042_day_and_week_of_the_year.cpp" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_043_meeting_time_for_multiple_time_zones.cpp" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_044_monthly_calendar.cpp" 8 | PARENT_SCOPE 9 | ) 10 | -------------------------------------------------------------------------------- /test/chapter_05_date_and_time/problem_039_measuring_function_execution_time.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_05_date_and_time/problem_039_measuring_function_execution_time.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include // ostringstream 7 | #include // sleep_for 8 | 9 | namespace ch = std::chrono; 10 | using namespace std::chrono_literals; 11 | using namespace tmcppc::problem_39; 12 | 13 | 14 | TEST(measure_time, f_no_args) { 15 | auto duration{ 16 | measure_time( 17 | []() { std::this_thread::sleep_for(10ms); } 18 | ) 19 | }; 20 | EXPECT_GT(duration, 5ms); 21 | } 22 | TEST(measure_time, f_args) { 23 | auto duration{ 24 | measure_time( 25 | [](const auto& duration) { std::this_thread::sleep_for(duration); }, 26 | 10ms 27 | ) 28 | }; 29 | EXPECT_GT(duration, 5ms); 30 | } 31 | 32 | 33 | TEST(problem_39_main, output) { 34 | std::ostringstream oss{}; 35 | problem_39_main(oss); 36 | EXPECT_THAT(oss.str(), ::testing::ContainsRegex( 37 | "Measuring times...\n" 38 | "\tsort_iota_vector\\(num_elems = 1000000, num_reps = 1\\): .*\n" 39 | "\tsort_shuffle_vector\\(num_elems = 1000000, num_reps = 1\\): .*\n" 40 | "\n" 41 | "\tsort_iota_vector\\(num_elems = 1000, num_reps = 1000\\): .*\n" 42 | "\tsort_shuffle_vector\\(num_elems = 1000, num_reps = 1000\\): .*\n\n" 43 | )); 44 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 45 | } 46 | -------------------------------------------------------------------------------- /test/chapter_06_algorithms_and_data_structures/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_06_test_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/circular_buffer.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/double_buffer.cpp" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/graph.cpp" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/phone_numbers.cpp" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/priority_queue.cpp" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_045_priority_queue.cpp" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_046_circular_buffer.cpp" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_047_double_buffer.cpp" 10 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_048_most_frequent_element_in_a_range.cpp" 11 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_049_text_histogram.cpp" 12 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_050_filtering_a_list_of_phone_numbers.cpp" 13 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_051_transforming_a_list_of_phone_numbers.cpp" 14 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_052_generating_all_the_permutations_of_a_string.cpp" 15 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_053_average_rating_of_movies.cpp" 16 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_054_pairwise_algorithm.cpp" 17 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_055_zip_algorithm.cpp" 18 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_056_select_algorithm.cpp" 19 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_057_quicksort.cpp" 20 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_058_shortest_path_between_two_nodes.cpp" 21 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_059_weasel_program.cpp" 22 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_060_game_of_life.cpp" 23 | PARENT_SCOPE 24 | ) 25 | -------------------------------------------------------------------------------- /test/chapter_06_algorithms_and_data_structures/phone_numbers.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_06_algorithms_and_data_structures/phone_numbers.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | using tmcppc::phone::country_code; 8 | 9 | 10 | TEST(country_code_US, fmt_format) { EXPECT_EQ(fmt::format("{}", country_code::US), "US"); } 11 | TEST(country_code_Spain, fmt_format) { EXPECT_EQ(fmt::format("{}", country_code::Spain), "Spain"); } 12 | TEST(country_code_UK, fmt_format) { EXPECT_EQ(fmt::format("{}", country_code::UK), "UK"); } 13 | TEST(country_code_unknown, fmt_format) { 14 | EXPECT_EQ(fmt::format("{}", static_cast(10)), "Unknown country code"); 15 | } 16 | -------------------------------------------------------------------------------- /test/chapter_06_algorithms_and_data_structures/problem_046_circular_buffer.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_06_algorithms_and_data_structures/problem_046_circular_buffer.h" 2 | 3 | #include 4 | #include 5 | #include // ostringstream 6 | 7 | 8 | TEST(problem_46_main, output) { 9 | std::ostringstream oss{}; 10 | problem_46_main(oss); 11 | EXPECT_THAT(oss.str(), ::testing::HasSubstr( 12 | "Error: trying to create a circular_buffer with a fixed size of 0.\n" 13 | "\n" 14 | "circular_buffer cb_3(5);\n" 15 | "\tcb_3: [0, 0, 0, 0, 0], capacity: 5, size: 0\n" 16 | "\n" 17 | "cb_3.push_back(1);\n" 18 | "\tcb_3: [1, 0, 0, 0, 0], capacity: 5, size: 1, front: 1, back: 1\n" 19 | "cb_3.push_back(2);\n" 20 | "\tcb_3: [1, 2, 0, 0, 0], capacity: 5, size: 2, front: 1, back: 2\n" 21 | "cb_3.push_back(3);\n" 22 | "\tcb_3: [1, 2, 3, 0, 0], capacity: 5, size: 3, front: 1, back: 3\n" 23 | "cb_3.push_back(4);\n" 24 | "\tcb_3: [1, 2, 3, 4, 0], capacity: 5, size: 4, front: 1, back: 4\n" 25 | "cb_3.push_back(5);\n" 26 | "\tcb_3: [1, 2, 3, 4, 5], capacity: 5, size: 5, front: 1, back: 5\n" 27 | "cb_3.push_back(6);\n" 28 | "\tcb_3: [6, 2, 3, 4, 5], capacity: 5, size: 5, front: 2, back: 6\n" 29 | "\n" 30 | "cb_3.pop_front();\n" 31 | "\tcb_3: [6, 2, 3, 4, 5], capacity: 5, size: 4, front: 3, back: 6\n" 32 | "cb_3.pop_back();\n" 33 | "\tcb_3: [6, 2, 3, 4, 5], capacity: 5, size: 3, front: 3, back: 5\n" 34 | "\n" 35 | "cb_3.clear();\n" 36 | "\tcb_3: [6, 2, 3, 4, 5], capacity: 5, size: 0\n" 37 | )); 38 | } 39 | -------------------------------------------------------------------------------- /test/chapter_06_algorithms_and_data_structures/problem_054_pairwise_algorithm.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_06_algorithms_and_data_structures/problem_054_pairwise_algorithm.h" 2 | 3 | #include 4 | #include 5 | #include // pair 6 | #include 7 | 8 | using namespace tmcppc::problem_54; 9 | 10 | 11 | TEST(zip_with_next, empty_vector) { 12 | EXPECT_TRUE(zip_with_next(std::vector{}).empty()); 13 | } 14 | TEST(zip_with_next, one_element_vector) { 15 | EXPECT_TRUE(zip_with_next(std::vector{ 1 }).empty()); 16 | } 17 | TEST(zip_with_next, two_elements_vector) { 18 | EXPECT_THAT(zip_with_next(std::vector{ 1, 2 }), ::testing::ElementsAre( 19 | std::pair{ 1, 2 } 20 | )); 21 | } 22 | TEST(zip_with_next, three_elements_vector) { 23 | EXPECT_THAT(zip_with_next(std::vector{ 1, 2, 3 }), ::testing::ElementsAre( 24 | std::pair{ 1, 2 } 25 | )); 26 | } 27 | TEST(zip_with_next, four_elements_vector) { 28 | EXPECT_THAT(zip_with_next(std::vector{ 1, 2, 3, 4 }), ::testing::ElementsAre( 29 | std::pair{ 1, 2 }, 30 | std::pair{ 3, 4 } 31 | )); 32 | } 33 | 34 | 35 | TEST(problem_54_main, output) { 36 | std::ostringstream oss{}; 37 | problem_54_main(oss); 38 | EXPECT_THAT(oss.str(), ::testing::HasSubstr( 39 | "Zipping [1, 1, 2, 3, 5, 8] with next: [(1, 1), (2, 3), (5, 8)]\n" 40 | "Zipping [1, 1, 2, 3, 5, 8, 13] with next: [(1, 1), (2, 3), (5, 8)]\n\n" 41 | )); 42 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 43 | } 44 | -------------------------------------------------------------------------------- /test/chapter_06_algorithms_and_data_structures/problem_057_quicksort.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_06_algorithms_and_data_structures/problem_057_quicksort.h" 2 | 3 | #include 4 | #include 5 | #include // ostringstream 6 | 7 | 8 | TEST(problem_57_main, output) { 9 | std::ostringstream oss{}; 10 | problem_57_main(oss); 11 | EXPECT_THAT(oss.str(), ::testing::HasSubstr( 12 | "Quicksorting [z, A, 9, !, m, o, N, 9]: [!, 9, 9, A, N, m, o, z]\n" 13 | "Quicksorting [10, 15, 20, 25, 30, 35, 40]: [40, 30, 20, 10, 35, 25, 15]\n\n" 14 | )); 15 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 16 | } 17 | -------------------------------------------------------------------------------- /test/chapter_07_concurrency/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_07_test_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/logger.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_061_parallel_transform_algorithm.cpp" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_062_parallel_minmax_with_threads.cpp" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_063_parallel_minmax_with_async.cpp" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_064_parallel_sort_algorithm.cpp" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_065_thread_safe_logging.cpp" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_066_customer_service_system.cpp" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/quicksort.cpp" 10 | PARENT_SCOPE 11 | ) 12 | -------------------------------------------------------------------------------- /test/chapter_07_concurrency/logger.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_07_concurrency/logger.h" 2 | 3 | #include 4 | #include 5 | #include // ostringstream 6 | 7 | using namespace tmcppc::logging::v2; 8 | 9 | 10 | TEST(logger_v2, log_no_messages) { 11 | std::ostringstream oss{}; 12 | logger::get_instance().log(oss); 13 | EXPECT_TRUE(oss.str().empty()); 14 | } 15 | 16 | TEST(logger_v2, log_messages) { 17 | std::ostringstream oss{}; 18 | logger::get_instance().log(oss, "// This is ", 111, "\n"); 19 | EXPECT_THAT(oss.str(), ::testing::HasSubstr("// This is 111\n")); 20 | } 21 | -------------------------------------------------------------------------------- /test/chapter_07_concurrency/problem_064_parallel_sort_algorithm.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_07_concurrency/problem_064_parallel_sort_algorithm.h" 2 | 3 | #include 4 | #include 5 | #include // ostringstream 6 | 7 | 8 | TEST(problem_64_main, output) { 9 | std::ostringstream oss{}; 10 | problem_64_main(oss); 11 | EXPECT_THAT(oss.str(), ::testing::ContainsRegex("v = \\[.*\\]\n\n")); 12 | EXPECT_THAT(oss.str(), ::testing::HasSubstr( 13 | "std::sort(v); v = [-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n" 14 | "quicksort(v); v = [-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n" 15 | "parallel_quicksort; v = [-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n\n" 16 | )); 17 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 18 | } 19 | -------------------------------------------------------------------------------- /test/chapter_07_concurrency/problem_065_thread_safe_logging.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_07_concurrency/problem_065_thread_safe_logging.h" 2 | 3 | #include 4 | #include 5 | #include // ostringstream 6 | 7 | 8 | TEST(problem_65_main, output) { 9 | std::ostringstream oss{}; 10 | problem_65_main(oss); 11 | EXPECT_THAT(oss.str(), ::testing::HasSubstr("// This is 111\n")); 12 | EXPECT_THAT(oss.str(), ::testing::HasSubstr("!! 222 is here\n")); 13 | EXPECT_THAT(oss.str(), ::testing::HasSubstr("-- 333 THEY CALL ME\n")); 14 | EXPECT_THAT(oss.str(), ::testing::EndsWith("\n\n")); 15 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 16 | } 17 | -------------------------------------------------------------------------------- /test/chapter_08_design_patterns/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_08_test_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_067_validating_passwords.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_068_generating_random_passwords.cpp" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_069_generating_social_security_numbers.cpp" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_070_approval_system.cpp" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_071_observable_vector_container.cpp" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_072_computing_order_price_with_discounts.cpp" 8 | PARENT_SCOPE 9 | ) 10 | -------------------------------------------------------------------------------- /test/chapter_09_data_serialization/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Subdirectories 2 | add_subdirectory(json) 3 | add_subdirectory(pdf) 4 | add_subdirectory(xml) 5 | 6 | 7 | set(chapter_09_test_sources 8 | ${chapter_09_test_json_sources} 9 | ${chapter_09_test_pdf_sources} 10 | ${chapter_09_test_xml_sources} 11 | "${CMAKE_CURRENT_SOURCE_DIR}/movies.cpp" 12 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_073_xml_serialization.cpp" 13 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_074_using_xpath.cpp" 14 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_075_json_serialization.cpp" 15 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_076_json_deserialization.cpp" 16 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_077_printing_a_list_of_movies_to_a_pdf.cpp" 17 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_078_creating_a_pdf_from_a_collection_of_images.cpp" 18 | PARENT_SCOPE 19 | ) 20 | -------------------------------------------------------------------------------- /test/chapter_09_data_serialization/json/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_09_test_json_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/movies.cpp" 3 | PARENT_SCOPE 4 | ) 5 | -------------------------------------------------------------------------------- /test/chapter_09_data_serialization/pdf/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_09_test_pdf_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/images.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/movies.cpp" 4 | PARENT_SCOPE 5 | ) 6 | -------------------------------------------------------------------------------- /test/chapter_09_data_serialization/pdf/images.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_09_data_serialization/pdf/images_doc.h" 2 | #include "chapter_09_data_serialization/pdf/image_list_layouter.h" 3 | 4 | #include 5 | #include 6 | 7 | namespace fs = std::filesystem; 8 | using namespace tmcppc::pdf; 9 | 10 | 11 | TEST(images_doc, save_to_empty_list_of_images) { 12 | const auto input_dir_path{ tmcppc::env::get_instance().get_resource_folder_path() / "fonts" }; 13 | const auto temp_file_path{ fs::temp_directory_path() / "test_pdf_doc_save_to_empty_list_of_images.pdf" }; 14 | images_doc out_doc{ input_dir_path }; 15 | out_doc.save_to(temp_file_path, std::make_unique()); 16 | EXPECT_TRUE(fs::exists(temp_file_path)); 17 | EXPECT_FALSE(fs::is_empty(temp_file_path)); 18 | } 19 | 20 | TEST(images_doc, save_to_list_of_images) { 21 | const auto input_dir_path{ tmcppc::env::get_instance().get_resource_folder_path() / "images" }; 22 | const auto temp_file_path{ fs::temp_directory_path() / "test_pdf_doc_save_to_list_of_images.pdf" }; 23 | images_doc out_doc{ input_dir_path }; 24 | out_doc.save_to(temp_file_path, std::make_unique()); 25 | EXPECT_TRUE(fs::exists(temp_file_path)); 26 | EXPECT_FALSE(fs::is_empty(temp_file_path)); 27 | } 28 | -------------------------------------------------------------------------------- /test/chapter_09_data_serialization/problem_073_xml_serialization.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_09_data_serialization/problem_073_xml_serialization.h" 2 | 3 | #include 4 | #include 5 | #include // ostringstream 6 | 7 | 8 | TEST(problem_73_main, output) { 9 | std::ostringstream oss{}; 10 | problem_73_main(oss); 11 | EXPECT_THAT(oss.str(), ::testing::ContainsRegex( 12 | "Writing XML out to: .*/list_of_movies.xml\n" 13 | "Reading XML in from: .*/list_of_movies.xml\n" 14 | "\n" 15 | "Checking if serializing and deserializing the XML object created the same object... OK\n\n" 16 | )); 17 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 18 | } 19 | -------------------------------------------------------------------------------- /test/chapter_09_data_serialization/problem_074_using_xpath.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_09_data_serialization/problem_074_using_xpath.h" 2 | 3 | #include 4 | #include 5 | #include // ostringstream 6 | 7 | 8 | TEST(problem_74_main, output) { 9 | std::ostringstream oss{}; 10 | problem_74_main(oss); 11 | EXPECT_THAT(oss.str(), ::testing::ContainsRegex( 12 | "Writing XML out to: .*/list_of_movies.xml\n" 13 | "Reading XML in from: .*/list_of_movies.xml\n" 14 | )); 15 | EXPECT_THAT(oss.str(), ::testing::HasSubstr( 16 | "Checking if serializing and deserializing the XML object created the same object... OK\n" 17 | "\n" 18 | "Movies released after year: 1992\n" 19 | "\tThe Matrix: 1999\n" 20 | "\tForrest Gump: 1994\n" 21 | "Movies released after year: 1996\n" 22 | "\tThe Matrix: 1999\n" 23 | "Movies released after year: 2000\n" 24 | "\n" 25 | "Last actor in the casting list for every movie:\n" 26 | "\tThe Matrix: Hugo Weaving\n" 27 | "\tForrest Gump: Mykelti Williamson\n\n" 28 | )); 29 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 30 | } 31 | -------------------------------------------------------------------------------- /test/chapter_09_data_serialization/problem_075_json_serialization.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_09_data_serialization/problem_075_json_serialization.h" 2 | 3 | #include 4 | #include 5 | #include // ostringstream 6 | 7 | 8 | TEST(problem_75_main, output) { 9 | std::ostringstream oss{}; 10 | problem_75_main(oss); 11 | EXPECT_THAT(oss.str(), ::testing::ContainsRegex( 12 | "Writing JSON out to: .*/list_of_movies.json\n" 13 | "Reading JSON in from: .*/list_of_movies.json\n" 14 | "\n" 15 | "Checking if serializing and deserializing the JSON object created the same object... OK\n\n" 16 | )); 17 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 18 | } 19 | -------------------------------------------------------------------------------- /test/chapter_09_data_serialization/problem_076_json_deserialization.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_09_data_serialization/problem_076_json_deserialization.h" 2 | 3 | #include 4 | #include 5 | #include // ostringstream 6 | 7 | 8 | TEST(problem_76_main, output) { 9 | std::ostringstream oss{}; 10 | problem_76_main(oss); 11 | EXPECT_THAT(oss.str(), ::testing::ContainsRegex( 12 | "Writing JSON out to: .*/list_of_movies.json\n" 13 | "Reading JSON in from: .*/list_of_movies.json\n" 14 | "\n" 15 | "Checking if serializing and deserializing the JSON object created the same object... OK\n\n" 16 | )); 17 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 18 | } 19 | -------------------------------------------------------------------------------- /test/chapter_09_data_serialization/problem_077_printing_a_list_of_movies_to_a_pdf.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_09_data_serialization/problem_077_printing_a_list_of_movies_to_a_pdf.h" 2 | 3 | #include 4 | #include 5 | #include // ostringstream 6 | 7 | 8 | TEST(problem_77_main, output) { 9 | std::ostringstream oss{}; 10 | problem_77_main(oss); 11 | EXPECT_THAT(oss.str(), ::testing::ContainsRegex( 12 | "Writing PDF out to: .*/list_of_movies.pdf\n\n" 13 | )); 14 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 15 | } 16 | -------------------------------------------------------------------------------- /test/chapter_09_data_serialization/problem_078_creating_a_pdf_from_a_collection_of_images.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_09_data_serialization/problem_078_creating_a_pdf_from_a_collection_of_images.h" 2 | 3 | #include 4 | #include 5 | #include // ostringstream 6 | 7 | 8 | TEST(problem_78_main, output) { 9 | std::ostringstream oss{}; 10 | problem_78_main(oss); 11 | EXPECT_THAT(oss.str(), ::testing::ContainsRegex( 12 | "Writing PDF out to: .*/list_of_images.pdf\n\n" 13 | )); 14 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 15 | } 16 | -------------------------------------------------------------------------------- /test/chapter_09_data_serialization/xml/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_09_test_xml_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/movies.cpp" 3 | PARENT_SCOPE 4 | ) 5 | -------------------------------------------------------------------------------- /test/chapter_10_archives_images_and_databases/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Subdirectories 2 | add_subdirectory(console) 3 | add_subdirectory(ean_13) 4 | add_subdirectory(file) 5 | add_subdirectory(png) 6 | add_subdirectory(sql) 7 | add_subdirectory(zip) 8 | 9 | 10 | set(chapter_10_test_sources 11 | ${chapter_10_test_console_sources} 12 | ${chapter_10_test_ean_13_sources} 13 | ${chapter_10_test_file_sources} 14 | ${chapter_10_test_png_sources} 15 | ${chapter_10_test_sql_sources} 16 | ${chapter_10_test_zip_sources} 17 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_079_finding_files_in_a_zip_archive.cpp" 18 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_080_zip_compression.cpp" 19 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_081_zip_compression_with_password.cpp" 20 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_082_national_flag_png.cpp" 21 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_083_verification_text_png.cpp" 22 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_084_ean_13_barcode_generator.cpp" 23 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_085_reading_from_an_sqlite_db.cpp" 24 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_086_inserting_into_an_sqlite_db.cpp" 25 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_087_handling_images_in_an_sqlite_db.cpp" 26 | PARENT_SCOPE 27 | ) 28 | -------------------------------------------------------------------------------- /test/chapter_10_archives_images_and_databases/console/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_10_test_console_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/movies.cpp" 3 | PARENT_SCOPE 4 | ) 5 | -------------------------------------------------------------------------------- /test/chapter_10_archives_images_and_databases/ean_13/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_10_test_ean_13_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/barcode.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/barcode_png_generator.cpp" 4 | PARENT_SCOPE 5 | ) 6 | -------------------------------------------------------------------------------- /test/chapter_10_archives_images_and_databases/ean_13/barcode_png_generator.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_10_archives_images_and_databases/ean_13/barcode.h" 2 | #include "chapter_10_archives_images_and_databases/ean_13/barcode_png_generator.h" 3 | #include "env.h" 4 | 5 | #include 6 | #include 7 | #include // pdiff 8 | #include // pdiff 9 | 10 | namespace fs = std::filesystem; 11 | 12 | 13 | TEST(ean_13_barcode_png_generator, operator_function_call) { 14 | const auto master_image_file_path{ tmcppc::env::get_instance().get_resource_folder_path() 15 | / "images" / "masters" / "2407014001944.png" }; 16 | const auto image_file_path{ tmcppc::png::create_png_file_path(std::filesystem::temp_directory_path(), 17 | "test_ean_13_barcode_png_generator_operator_function_all") }; 18 | auto code_png_generator{ tmcppc::ean_13::barcode_png::generator{} }; 19 | auto code_str{ "2407014001944" }; 20 | code_png_generator(tmcppc::ean_13::barcode{ code_str }, 1.0, image_file_path); 21 | EXPECT_TRUE(fs::exists(image_file_path)); 22 | EXPECT_FALSE(fs::is_empty(image_file_path)); 23 | const auto decoded_output_image{ pdiff::read_from_file(image_file_path.string()) }; 24 | const auto decoded_master_image{ pdiff::read_from_file(master_image_file_path.string()) }; 25 | EXPECT_TRUE(pdiff::yee_compare(*decoded_output_image, *decoded_master_image)); 26 | } 27 | -------------------------------------------------------------------------------- /test/chapter_10_archives_images_and_databases/file/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_10_test_file_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/movies.cpp" 3 | PARENT_SCOPE 4 | ) 5 | -------------------------------------------------------------------------------- /test/chapter_10_archives_images_and_databases/png/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_10_test_png_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/png_writer_wrapper.cpp" 3 | PARENT_SCOPE 4 | ) 5 | -------------------------------------------------------------------------------- /test/chapter_10_archives_images_and_databases/png/png_writer_wrapper.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_10_archives_images_and_databases/png/png_writer_wrapper.h" 2 | 3 | #include 4 | 5 | namespace fs = std::filesystem; 6 | using namespace tmcppc::png; 7 | 8 | 9 | TEST(create_png_file_path, file_stem_has_no_extension) { 10 | auto file_root_path{ fs::temp_directory_path() }; 11 | auto input_file_stem{ "test_file_stem_had_no_extension" }; 12 | auto output_file_stem{ "test_file_stem_had_no_extension.png" }; 13 | auto ret{ create_png_file_path(file_root_path, input_file_stem) }; 14 | EXPECT_EQ(ret, fs::path{ file_root_path / output_file_stem }); 15 | } 16 | TEST(create_png_file_path, file_stem_has_txt_extension) { 17 | auto file_root_path{ fs::temp_directory_path() }; 18 | auto input_file_stem{ "test_file_stem_had_txt_extension.txt" }; 19 | auto output_file_stem{ "test_file_stem_had_txt_extension.png" }; 20 | auto ret{ create_png_file_path(file_root_path, input_file_stem) }; 21 | EXPECT_EQ(ret, fs::path{ file_root_path / output_file_stem }); 22 | } 23 | TEST(create_png_file_path, file_stem_has_png_extension) { 24 | auto file_root_path{ fs::temp_directory_path() }; 25 | auto file_stem{ "test_file_stem_had_png_extension.png" }; 26 | auto ret{ create_png_file_path(file_root_path, file_stem) }; 27 | EXPECT_EQ(ret, fs::path{ file_root_path / file_stem }); 28 | } 29 | -------------------------------------------------------------------------------- /test/chapter_10_archives_images_and_databases/problem_079_finding_files_in_a_zip_archive.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_10_archives_images_and_databases/problem_079_finding_files_in_a_zip_archive.h" 2 | 3 | #include 4 | #include 5 | #include // ostringstream 6 | 7 | 8 | TEST(problem_79_main, output) { 9 | std::ostringstream oss{}; 10 | problem_79_main(oss); 11 | EXPECT_THAT(oss.str(), ::testing::HasSubstr( 12 | "Searching for '^.*\\.jpg$' files in " 13 | )); 14 | EXPECT_THAT(oss.str(), ::testing::ContainsRegex( 15 | "'.*/res/sample_folder.zip'...\n" 16 | )); 17 | EXPECT_THAT(oss.str(), ::testing::HasSubstr( 18 | "\tsample_folder/dilbert.jpg\n" 19 | "\tsample_folder/guinness.jpg\n" 20 | "\tsample_folder/john_mccarthy.jpg\n" 21 | "\tsample_folder/sample_subfolder/use_your_illussion_ii.jpg\n\n" 22 | )); 23 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 24 | } 25 | -------------------------------------------------------------------------------- /test/chapter_10_archives_images_and_databases/problem_082_national_flag_png.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_10_archives_images_and_databases/png/png_writer_wrapper.h" 2 | #include "chapter_10_archives_images_and_databases/problem_082_national_flag_png.h" 3 | #include "env.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include // pdiff 9 | #include // pdiff 10 | 11 | namespace fs = std::filesystem; 12 | using namespace tmcppc::png; 13 | using namespace tmcppc::problem_82; 14 | 15 | 16 | TEST(paint_romania_flag, png_output) { 17 | const auto master_image_file_path{ tmcppc::env::get_instance().get_resource_folder_path() 18 | / "images" / "masters" / "romania_flag.png" }; 19 | const auto image_file_path{ create_png_file_path(std::filesystem::temp_directory_path(), "test_paint_romania_flag") }; 20 | { 21 | png_writer png_writer(300, 200, 0.0, image_file_path); 22 | paint_romania_flag(png_writer); 23 | } 24 | EXPECT_TRUE(fs::exists(image_file_path)); 25 | EXPECT_FALSE(fs::is_empty(image_file_path)); 26 | const auto decoded_output_image{ pdiff::read_from_file(image_file_path.string()) }; 27 | const auto decoded_master_image{ pdiff::read_from_file(master_image_file_path.string()) }; 28 | EXPECT_TRUE(pdiff::yee_compare(*decoded_output_image, *decoded_master_image)); 29 | } 30 | 31 | TEST(problem_82_main, ostream_output) { 32 | std::ostringstream oss{}; 33 | problem_82_main(oss); 34 | EXPECT_THAT(oss.str(), ::testing::ContainsRegex("Creating .*/romania_flag.png...\n\n")); 35 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 36 | } 37 | -------------------------------------------------------------------------------- /test/chapter_10_archives_images_and_databases/problem_083_verification_text_png.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_10_archives_images_and_databases/png/png_writer_wrapper.h" 2 | #include "chapter_10_archives_images_and_databases/problem_083_verification_text_png.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include // ostringstream 8 | 9 | namespace fs = std::filesystem; 10 | using namespace tmcppc::png; 11 | using namespace tmcppc::problem_83; 12 | 13 | 14 | TEST(paint_verification_text, png_file_creation) { 15 | const auto image_file_path{ create_png_file_path(std::filesystem::temp_directory_path(), "test_paint_verification_text") }; 16 | { 17 | png_writer png_writer(300, 200, 0.0, image_file_path); 18 | paint_verification_text(png_writer); 19 | } 20 | EXPECT_TRUE(fs::exists(image_file_path)); 21 | EXPECT_FALSE(fs::is_empty(image_file_path)); 22 | } 23 | 24 | TEST(problem_83_main, output) { 25 | std::ostringstream oss{}; 26 | problem_83_main(oss); 27 | EXPECT_THAT(oss.str(), ::testing::ContainsRegex("Creating .*/captcha.png...\n\n")); 28 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 29 | } 30 | -------------------------------------------------------------------------------- /test/chapter_10_archives_images_and_databases/problem_084_ean_13_barcode_generator.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_10_archives_images_and_databases/problem_084_ean_13_barcode_generator.h" 2 | 3 | #include 4 | #include 5 | #include // ostringstream 6 | 7 | 8 | TEST(problem_84_main, output) { 9 | std::ostringstream oss{}; 10 | problem_84_main(oss); 11 | EXPECT_THAT(oss.str(), ::testing::ContainsRegex( 12 | "Creating .*/2407014001944.png...\n\n" 13 | "Creating .*/9781123123456.png...\n\n" 14 | "Creating .*/5012345678900.png...\n\n" 15 | )); 16 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 17 | } 18 | -------------------------------------------------------------------------------- /test/chapter_10_archives_images_and_databases/sql/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_10_test_sql_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/movies.cpp" 3 | PARENT_SCOPE 4 | ) 5 | -------------------------------------------------------------------------------- /test/chapter_10_archives_images_and_databases/zip/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_10_test_zip_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/zip_lib_wrapper.cpp" 3 | PARENT_SCOPE 4 | ) 5 | -------------------------------------------------------------------------------- /test/chapter_11_cryptography/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_11_test_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/base64.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/caesar.cpp" 4 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_088_caesar_cipher.cpp" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_089_vigenere_cipher.cpp" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_090_base64_encoding.cpp" 7 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_091_validating_user_credentials.cpp" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_092_computing_file_hashes.cpp" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_093_aes_encryption.cpp" 10 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_094_file_signing.cpp" 11 | "${CMAKE_CURRENT_SOURCE_DIR}/vigenere.cpp" 12 | PARENT_SCOPE 13 | ) 14 | -------------------------------------------------------------------------------- /test/chapter_11_cryptography/caesar.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_11_cryptography/caesar.h" 2 | 3 | #include 4 | #include 5 | 6 | using namespace std::string_view_literals; 7 | using namespace tmcppc::crypto; 8 | 9 | 10 | TEST(caesar, encrypt_empty_string) { 11 | const auto text{ "" }; 12 | EXPECT_EQ(caesar{}.encrypt(text), text); 13 | } 14 | TEST(caesar, encrypt_string_with_no_alphas) { 15 | const auto text{ "1234567890!?@#" }; 16 | EXPECT_EQ(caesar{}.encrypt(text), text); 17 | } 18 | 19 | TEST(caesar, encrypt_and_decrypt_empty_string) { 20 | const auto text{ "" }; 21 | caesar cipher{}; 22 | auto ret{ cipher.encrypt(text) }; 23 | EXPECT_EQ(cipher.decrypt(ret), text); 24 | } 25 | TEST(caesar, encrypt_and_decrypt_string_with_no_alphas) { 26 | const auto text{ "1234567890!?@#" }; 27 | caesar cipher{}; 28 | auto ret{ cipher.encrypt(text) }; 29 | EXPECT_EQ(cipher.decrypt(ret), text); 30 | } 31 | TEST(caesar, encrypt_and_decrypt) { 32 | const auto text{ "In the beginning, there was simply the event and its consequences."sv }; 33 | caesar cipher{}; 34 | auto ret{ cipher.encrypt(text) }; 35 | EXPECT_EQ(cipher.decrypt(ret), text); 36 | } 37 | -------------------------------------------------------------------------------- /test/chapter_11_cryptography/problem_088_caesar_cipher.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_11_cryptography/problem_088_caesar_cipher.h" 2 | 3 | #include 4 | #include 5 | #include // ostringstream 6 | 7 | 8 | TEST(problem_88_main, output) { 9 | std::ostringstream oss{}; 10 | problem_88_main(oss); 11 | EXPECT_THAT(oss.str(), ::testing::ContainsRegex( 12 | "Encrypting and decrypting file '.*res/sample_file.txt'\n" 13 | "\tOK\n\n" 14 | )); 15 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 16 | } 17 | -------------------------------------------------------------------------------- /test/chapter_11_cryptography/problem_089_vigenere_cipher.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_11_cryptography/problem_089_vigenere_cipher.h" 2 | 3 | #include 4 | #include 5 | #include // ostringstream 6 | 7 | 8 | TEST(problem_89_main, output) { 9 | std::ostringstream oss{}; 10 | problem_89_main(oss); 11 | EXPECT_THAT(oss.str(), ::testing::ContainsRegex( 12 | "Encrypting and decrypting file '.*res/sample_file.txt'\n" 13 | "\tOK\n\n" 14 | )); 15 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 16 | } 17 | -------------------------------------------------------------------------------- /test/chapter_11_cryptography/vigenere.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_11_cryptography/vigenere.h" 2 | 3 | #include 4 | #include 5 | 6 | using namespace std::string_view_literals; 7 | using namespace tmcppc::crypto; 8 | 9 | 10 | TEST(vigenere, encrypt_empty_string) { 11 | const auto text{ "" }; 12 | EXPECT_EQ(vigenere{}.encrypt(text), text); 13 | } 14 | TEST(vigenere, encrypt_string_with_no_alphas) { 15 | const auto text{ "1234567890!?@#" }; 16 | EXPECT_EQ(vigenere{}.encrypt(text), text); 17 | } 18 | 19 | TEST(vigenere, encrypt_and_decrypt_empty_string) { 20 | const auto text{ "" }; 21 | vigenere cipher{}; 22 | auto ret{ cipher.encrypt(text) }; 23 | EXPECT_EQ(cipher.decrypt(ret), text); 24 | } 25 | TEST(vigenere, encrypt_and_decrypt_string_with_no_alphas) { 26 | const auto text{ "1234567890!?@#" }; 27 | vigenere cipher{}; 28 | auto ret{ cipher.encrypt(text) }; 29 | EXPECT_EQ(cipher.decrypt(ret), text); 30 | } 31 | TEST(vigenere, encrypt_and_decrypt) { 32 | const auto text{ "In the beginning, there was simply the event and its consequences."sv }; 33 | vigenere cipher{}; 34 | auto ret{ cipher.encrypt(text) }; 35 | EXPECT_EQ(cipher.decrypt(ret), text); 36 | } 37 | -------------------------------------------------------------------------------- /test/chapter_12_networking_and_services/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Subdirectories 2 | add_subdirectory(bitcoin) 3 | add_subdirectory(imap) 4 | add_subdirectory(json) 5 | 6 | 7 | set(chapter_12_test_sources 8 | ${chapter_12_test_bitcoin_sources} 9 | ${chapter_12_test_imap_sources} 10 | ${chapter_12_test_json_sources} 11 | "${CMAKE_CURRENT_SOURCE_DIR}/bitcoin.cpp" 12 | "${CMAKE_CURRENT_SOURCE_DIR}/face_detection.cpp" 13 | "${CMAKE_CURRENT_SOURCE_DIR}/faces.cpp" 14 | "${CMAKE_CURRENT_SOURCE_DIR}/fizz_buzz.cpp" 15 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_095_finding_the_ip_address_of_a_host.cpp" 16 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_096_fizz_buzz_client_server_application.cpp" 17 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_097_bitcoin_exchange_rates.cpp" 18 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_098_fetching_emails_using_imap.cpp" 19 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_099_translating_text.cpp" 20 | "${CMAKE_CURRENT_SOURCE_DIR}/problem_100_detecting_faces_in_a_picture.cpp" 21 | "${CMAKE_CURRENT_SOURCE_DIR}/text_translation.cpp" 22 | PARENT_SCOPE 23 | ) 24 | -------------------------------------------------------------------------------- /test/chapter_12_networking_and_services/bitcoin/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_12_test_bitcoin_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/connection.cpp" 3 | PARENT_SCOPE 4 | ) 5 | -------------------------------------------------------------------------------- /test/chapter_12_networking_and_services/bitcoin/mock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "chapter_12_networking_and_services/bitcoin/connection.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | namespace tmcppc::bitcoin { 11 | struct connector_mock : public connector_adaptor { 12 | MOCK_METHOD((std::string), get_current_exchange_rates, (), (const, override)); 13 | }; 14 | } // namespace tmcppc::bitcoin 15 | -------------------------------------------------------------------------------- /test/chapter_12_networking_and_services/face_detection/mock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "chapter_12_networking_and_services/face_detection.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | namespace tmcppc::face_detection { 11 | struct provider_mock : public provider_adaptor { 12 | MOCK_METHOD((provider_response), detect, (const std::filesystem::path& path), (const, override)); 13 | }; 14 | } // namespace tmcppc::face_detection 15 | -------------------------------------------------------------------------------- /test/chapter_12_networking_and_services/imap/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_12_test_imap_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/connection.cpp" 3 | PARENT_SCOPE 4 | ) 5 | -------------------------------------------------------------------------------- /test/chapter_12_networking_and_services/imap/mock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "chapter_12_networking_and_services/imap/connection.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | namespace tmcppc::imap { 12 | struct connector_mock : public connector_adaptor { 13 | MOCK_METHOD(std::string, get_mailbox_folders, (), (const, override)); 14 | MOCK_METHOD(std::string, get_unread_email_ids, (std::string_view folder), (const, override)); 15 | MOCK_METHOD(std::string, get_email, (std::string_view folder, size_t id), (const, override)); 16 | }; 17 | } // namespace tmcppc::imap 18 | -------------------------------------------------------------------------------- /test/chapter_12_networking_and_services/json/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(chapter_12_test_json_sources 2 | "${CMAKE_CURRENT_SOURCE_DIR}/bitcoin.cpp" 3 | "${CMAKE_CURRENT_SOURCE_DIR}/faces.cpp" 4 | PARENT_SCOPE 5 | ) 6 | -------------------------------------------------------------------------------- /test/chapter_12_networking_and_services/json/bitcoin.cpp: -------------------------------------------------------------------------------- 1 | #include "../bitcoin/samples.h" 2 | #include "chapter_12_networking_and_services/json/bitcoin.h" 3 | #include "chapter_12_networking_and_services/bitcoin/samples.h" 4 | 5 | #include 6 | #include 7 | 8 | using namespace tmcppc::bitcoin; 9 | 10 | 11 | TEST(exchange_rate, from_json) { 12 | nlohmann::json j = nlohmann::json::parse(samples::connector_response_text::exchange_rate_eur); 13 | exchange_rate er{}; 14 | from_json(j, er); 15 | EXPECT_EQ(er, samples::exchange_rate_eur); 16 | } 17 | TEST(exchange_rates, from_json) { 18 | nlohmann::json j = nlohmann::json::parse(samples::connector_response_text::exchange_rates_eur_gbp_usd); 19 | exchange_rates ers{}; 20 | from_json(j, ers); 21 | EXPECT_EQ(ers, samples::exchange_rates_eur_gbp_usd); 22 | } 23 | -------------------------------------------------------------------------------- /test/chapter_12_networking_and_services/problem_097_bitcoin_exchange_rates.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_12_networking_and_services/problem_097_bitcoin_exchange_rates.h" 2 | 3 | #include 4 | #include 5 | #include // ostringstream 6 | 7 | 8 | TEST(problem_97_main, output) { 9 | std::ostringstream oss{}; 10 | problem_97_main(oss); 11 | EXPECT_THAT(oss.str(), ::testing::HasSubstr( 12 | "Current bitcoin exchange rates:\n" 13 | )); 14 | #if defined(_WIN32) 15 | EXPECT_THAT(oss.str(), ::testing::ContainsRegex( 16 | "\\{ symbol: \\w\\w\\w, 15m: \\d+\\.\\d\\d, last: \\d+\\.\\d\\d, " 17 | "buy: \\d+\\.\\d\\d, sell: \\d+\\.\\d\\d \\},\n.*" 18 | "\\{ symbol: \\w\\w\\w, 15m: \\d+\\.\\d\\d, last: \\d+\\.\\d\\d, " 19 | "buy: \\d+\\.\\d\\d, sell: \\d+\\.\\d\\d \\}\n" 20 | )); 21 | #elif defined(__GNUC__) 22 | EXPECT_THAT(oss.str(), ::testing::ContainsRegex( 23 | "\\{ symbol: \\w\\w\\w, 15m: [0-9]+\\.[0-9][0-9], last: [0-9]+\\.[0-9][0-9], " 24 | "buy: [0-9]+\\.[0-9][0-9], sell: [0-9]+\\.[0-9][0-9] \\},\n.*" 25 | "\\{ symbol: \\w\\w\\w, 15m: [0-9]+\\.[0-9][0-9], last: [0-9]+\\.[0-9][0-9], " 26 | "buy: [0-9]+\\.[0-9][0-9], sell: [0-9]+\\.[0-9][0-9] \\}\n" 27 | "\\}\n\n" 28 | )); 29 | #endif 30 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 31 | } 32 | -------------------------------------------------------------------------------- /test/chapter_12_networking_and_services/problem_100_detecting_faces_in_a_picture.cpp: -------------------------------------------------------------------------------- 1 | #include "chapter_12_networking_and_services/face_detection.h" 2 | #include "chapter_12_networking_and_services/face_detection/samples.h" 3 | #include "chapter_12_networking_and_services/problem_100_detecting_faces_in_a_picture.h" 4 | #include "env.h" 5 | #include "face_detection/mock.h" 6 | #include "face_detection/samples.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include // ostringstream 12 | #include // move 13 | #include 14 | 15 | using namespace tmcppc::face_detection; 16 | 17 | 18 | TEST(test_face_detection, output) { 19 | std::unique_ptr provider_up{ std::make_unique() }; 20 | auto& provider{ *(dynamic_cast(provider_up.get())) }; 21 | EXPECT_CALL(provider, detect(tmcppc::env::get_instance().get_resource_folder_path() / "faces.jpg")) 22 | .WillOnce(::testing::Return(provider_response{ 200, samples::provider_response_text::faces_response })); 23 | 24 | std::ostringstream oss{}; 25 | tmcppc::problem_100::test_face_detection(oss, detector{ std::move(provider_up) }); 26 | 27 | EXPECT_THAT(oss.str(), ::testing::HasSubstr(samples::get_faces_response_output<1>())); 28 | EXPECT_THAT(oss.str(), ::testing::EndsWith("\n\n")); 29 | EXPECT_THAT(oss.str(), ::testing::Not(::testing::EndsWith("\n\n\n"))); 30 | } 31 | -------------------------------------------------------------------------------- /test/chapter_12_networking_and_services/tcp/mock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "chapter_12_networking_and_services/tcp/connection.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include // error_code 10 | 11 | 12 | namespace tmcppc::tcp { 13 | struct connector_mock : public connector { 14 | MOCK_METHOD((size_t), read_until, (std::string& data, std::string_view delimiter, std::error_code& ec), (override)); 15 | MOCK_METHOD((void), write, (const std::string& message, std::error_code& ec), (override)); 16 | MOCK_METHOD((void), accept, (), (override)); 17 | MOCK_METHOD((void), connect, (), (override)); 18 | }; 19 | } // namespace tmcppc::tcp 20 | -------------------------------------------------------------------------------- /test/chapter_12_networking_and_services/text_translation/mock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "chapter_12_networking_and_services/text_translation.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | namespace tmcppc::text_translation { 12 | struct provider_mock : public provider_adaptor { 13 | MOCK_METHOD((std::string), translate, (std::string_view text, tmcppc::text_translation::language_code from, 14 | tmcppc::text_translation::language_code to), (const, override)); 15 | }; 16 | } // namespace tmcppc::text_translation 17 | -------------------------------------------------------------------------------- /test/console/fake.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "console.h" 4 | 5 | 6 | namespace tmcppc::system { 7 | struct console_fake : public console_iface { 8 | void clear_istream(std::istream& is) const override { is.clear(); } 9 | void clear_screen() const override {} 10 | }; 11 | } // namespace tmcppc::system 12 | -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | #include "env.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include // cout 7 | 8 | namespace fs = std::filesystem; 9 | 10 | 11 | void print_usage(std::ostream& os) { 12 | fmt::print(os, "Usage:\n"); 13 | fmt::print(os, "\tthe_modern_c++_challenge_test \n"); 14 | fmt::print(os, "\n"); 15 | fmt::print(os, "Where:\n"); 16 | fmt::print(os, "\tRESOURCE_DIR_PATH Path to the resource folder (relative or absolute)\n"); 17 | fmt::print(os, "Example:\n"); 18 | fmt::print(os, "\tthe_modern_c++_challenge_test ../res\n"); 19 | } 20 | 21 | 22 | int main_impl(int argc, char** argv, std::ostream& os) { 23 | ::testing::InitGoogleTest(&argc, argv); 24 | 25 | if (argc != 2) { 26 | print_usage(os); 27 | return 0; 28 | } 29 | const fs::path resource_folder_path{ argv[1] }; 30 | if (not fs::exists(resource_folder_path)) { 31 | fmt::print(os, "Error: path '{}' does not exist\n", resource_folder_path.generic_string()); 32 | return 0; 33 | } 34 | if (not fs::is_directory(resource_folder_path)) { 35 | fmt::print(os, "Error: path '{}' is not a directory\n", resource_folder_path.generic_string()); 36 | return 0; 37 | } 38 | tmcppc::env::get_instance().set_resource_folder_path(fs::absolute(resource_folder_path)); 39 | 40 | return RUN_ALL_TESTS(); 41 | } 42 | 43 | 44 | int main(int argc, char** argv) { 45 | return main_impl(argc, argv, std::cout); 46 | } 47 | -------------------------------------------------------------------------------- /test/timer/fake.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "timer.h" 4 | 5 | #include 6 | 7 | namespace ch = std::chrono; 8 | 9 | 10 | namespace tmcppc::chrono { 11 | struct timer_fake : public timer_iface { 12 | void sleep_for([[maybe_unused]] const ch::duration& duration) const override {} 13 | }; 14 | } // namespace tmcppc::chrono 15 | -------------------------------------------------------------------------------- /vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "main", 3 | "version-string": "latest", 4 | "dependencies": [ 5 | "curl", 6 | "freetype", 7 | "libpng", 8 | "zlib" 9 | ] 10 | } 11 | --------------------------------------------------------------------------------