From c2ece13931dee2b91ab21da3af640f3a20a4dd77 Mon Sep 17 00:00:00 2001 From: Iain Buclaw <ibuclaw@gdcproject.org> Date: Tue, 25 Feb 2025 21:01:23 +0100 Subject: [PATCH] libphobos: Generate test files for phobos testsuite Extracts all public unittests from libphobos/src and emits them as standalone tests in the testsuite using the tests_extractor script. Compiling every module in the Phobos library with unittests included is computationally expensive, and these tests are now only ran when GCC_TEST_RUN_EXPENSIVE is not empty. When instead just compiling the unittests and linking in the module under test, this has been observed to reduce the time spent running the testsuite by more than half. libphobos/ChangeLog: * testsuite/libphobos.phobos/shared/phobos-shared.exp: Require is-effective-target run_expensive_tests. * testsuite/libphobos.phobos/static/phobos-static.exp: Likewise. * testsuite/libphobos.phobos/phobos.exp: New test. * testsuite/libphobos.phobos/std_algorithm_comparison.d: New test. * testsuite/libphobos.phobos/std_algorithm_iteration.d: New test. * testsuite/libphobos.phobos/std_algorithm_mutation.d: New test. * testsuite/libphobos.phobos/std_algorithm_searching.d: New test. * testsuite/libphobos.phobos/std_algorithm_setops.d: New test. * testsuite/libphobos.phobos/std_algorithm_sorting.d: New test. * testsuite/libphobos.phobos/std_array.d: New test. * testsuite/libphobos.phobos/std_ascii.d: New test. * testsuite/libphobos.phobos/std_base64.d: New test. * testsuite/libphobos.phobos/std_bigint.d: New test. * testsuite/libphobos.phobos/std_bitmanip.d: New test. * testsuite/libphobos.phobos/std_checkedint.d: New test. * testsuite/libphobos.phobos/std_complex.d: New test. * testsuite/libphobos.phobos/std_concurrency.d: New test. * testsuite/libphobos.phobos/std_container_array.d: New test. * testsuite/libphobos.phobos/std_container_binaryheap.d: New test. * testsuite/libphobos.phobos/std_container_dlist.d: New test. * testsuite/libphobos.phobos/std_container_rbtree.d: New test. * testsuite/libphobos.phobos/std_container_slist.d: New test. * testsuite/libphobos.phobos/std_container_util.d: New test. * testsuite/libphobos.phobos/std_conv.d: New test. * testsuite/libphobos.phobos/std_csv.d: New test. * testsuite/libphobos.phobos/std_datetime_date.d: New test. * testsuite/libphobos.phobos/std_datetime_interval.d: New test. * testsuite/libphobos.phobos/std_datetime_package.d: New test. * testsuite/libphobos.phobos/std_datetime_stopwatch.d: New test. * testsuite/libphobos.phobos/std_datetime_systime.d: New test. * testsuite/libphobos.phobos/std_datetime_timezone.d: New test. * testsuite/libphobos.phobos/std_demangle.d: New test. * testsuite/libphobos.phobos/std_digest_crc.d: New test. * testsuite/libphobos.phobos/std_digest_hmac.d: New test. * testsuite/libphobos.phobos/std_digest_md.d: New test. * testsuite/libphobos.phobos/std_digest_murmurhash.d: New test. * testsuite/libphobos.phobos/std_digest_package.d: New test. * testsuite/libphobos.phobos/std_digest_ripemd.d: New test. * testsuite/libphobos.phobos/std_digest_sha.d: New test. * testsuite/libphobos.phobos/std_encoding.d: New test. * testsuite/libphobos.phobos/std_exception.d: New test. * testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_affix_allocator.d: New test. * testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_aligned_block_list.d: New test. * testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_allocator_list.d: New test. * testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_ascending_page_allocator.d: New test. * testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_bitmapped_block.d: New test. * testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_bucketizer.d: New test. * testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_fallback_allocator.d: New test. * testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_free_list.d: New test. * testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_kernighan_ritchie.d: New test. * testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_quantizer.d: New test. * testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_region.d: New test. * testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_scoped_allocator.d: New test. * testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_segregator.d: New test. * testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_stats_collector.d: New test. * testsuite/libphobos.phobos/std_experimental_allocator_common.d: New test. * testsuite/libphobos.phobos/std_experimental_allocator_gc_allocator.d: New test. * testsuite/libphobos.phobos/std_experimental_allocator_mallocator.d: New test. * testsuite/libphobos.phobos/std_experimental_allocator_package.d: New test. * testsuite/libphobos.phobos/std_experimental_allocator_showcase.d: New test. * testsuite/libphobos.phobos/std_experimental_allocator_typed.d: New test. * testsuite/libphobos.phobos/std_file.d: New test. * testsuite/libphobos.phobos/std_format_package.d: New test. * testsuite/libphobos.phobos/std_format_read.d: New test. * testsuite/libphobos.phobos/std_format_spec.d: New test. * testsuite/libphobos.phobos/std_format_write.d: New test. * testsuite/libphobos.phobos/std_functional.d: New test. * testsuite/libphobos.phobos/std_getopt.d: New test. * testsuite/libphobos.phobos/std_int128.d: New test. * testsuite/libphobos.phobos/std_internal_cstring.d: New test. * testsuite/libphobos.phobos/std_internal_scopebuffer.d: New test. * testsuite/libphobos.phobos/std_json.d: New test. * testsuite/libphobos.phobos/std_logger_core.d: New test. * testsuite/libphobos.phobos/std_logger_nulllogger.d: New test. * testsuite/libphobos.phobos/std_math_algebraic.d: New test. * testsuite/libphobos.phobos/std_math_exponential.d: New test. * testsuite/libphobos.phobos/std_math_hardware.d: New test. * testsuite/libphobos.phobos/std_math_operations.d: New test. * testsuite/libphobos.phobos/std_math_remainder.d: New test. * testsuite/libphobos.phobos/std_math_rounding.d: New test. * testsuite/libphobos.phobos/std_math_traits.d: New test. * testsuite/libphobos.phobos/std_math_trigonometry.d: New test. * testsuite/libphobos.phobos/std_meta.d: New test. * testsuite/libphobos.phobos/std_mmfile.d: New test. * testsuite/libphobos.phobos/std_numeric.d: New test. * testsuite/libphobos.phobos/std_outbuffer.d: New test. * testsuite/libphobos.phobos/std_package.d: New test. * testsuite/libphobos.phobos/std_parallelism.d: New test. * testsuite/libphobos.phobos/std_path.d: New test. * testsuite/libphobos.phobos/std_random.d: New test. * testsuite/libphobos.phobos/std_range_interfaces.d: New test. * testsuite/libphobos.phobos/std_range_package.d: New test. * testsuite/libphobos.phobos/std_range_primitives.d: New test. * testsuite/libphobos.phobos/std_regex_package.d: New test. * testsuite/libphobos.phobos/std_signals.d: New test. * testsuite/libphobos.phobos/std_socket.d: New test. * testsuite/libphobos.phobos/std_stdio.d: New test. * testsuite/libphobos.phobos/std_string.d: New test. * testsuite/libphobos.phobos/std_sumtype.d: New test. * testsuite/libphobos.phobos/std_traits.d: New test. * testsuite/libphobos.phobos/std_typecons.d: New test. * testsuite/libphobos.phobos/std_typetuple.d: New test. * testsuite/libphobos.phobos/std_uni_package.d: New test. * testsuite/libphobos.phobos/std_uri.d: New test. * testsuite/libphobos.phobos/std_utf.d: New test. * testsuite/libphobos.phobos/std_uuid.d: New test. * testsuite/libphobos.phobos/std_variant.d: New test. * testsuite/libphobos.phobos/std_zlib.d: New test. --- .../testsuite/libphobos.phobos/phobos.exp | 50 + .../libphobos.phobos/shared/phobos-shared.exp | 5 + .../libphobos.phobos/static/phobos-static.exp | 5 + .../std_algorithm_comparison.d | 454 ++++ .../std_algorithm_iteration.d | 1004 +++++++ .../libphobos.phobos/std_algorithm_mutation.d | 627 +++++ .../std_algorithm_searching.d | 668 +++++ .../libphobos.phobos/std_algorithm_setops.d | 281 ++ .../libphobos.phobos/std_algorithm_sorting.d | 462 ++++ .../testsuite/libphobos.phobos/std_array.d | 560 ++++ .../testsuite/libphobos.phobos/std_ascii.d | 262 ++ .../testsuite/libphobos.phobos/std_base64.d | 180 ++ .../testsuite/libphobos.phobos/std_bigint.d | 465 ++++ .../testsuite/libphobos.phobos/std_bitmanip.d | 1628 +++++++++++ .../libphobos.phobos/std_checkedint.d | 628 +++++ .../testsuite/libphobos.phobos/std_complex.d | 403 +++ .../libphobos.phobos/std_concurrency.d | 235 ++ .../libphobos.phobos/std_container_array.d | 56 + .../std_container_binaryheap.d | 102 + .../libphobos.phobos/std_container_dlist.d | 47 + .../libphobos.phobos/std_container_rbtree.d | 60 + .../libphobos.phobos/std_container_slist.d | 28 + .../libphobos.phobos/std_container_util.d | 51 + .../testsuite/libphobos.phobos/std_conv.d | 511 ++++ .../testsuite/libphobos.phobos/std_csv.d | 228 ++ .../libphobos.phobos/std_datetime_date.d | 992 +++++++ .../libphobos.phobos/std_datetime_interval.d | 112 + .../libphobos.phobos/std_datetime_package.d | 34 + .../libphobos.phobos/std_datetime_stopwatch.d | 210 ++ .../libphobos.phobos/std_datetime_systime.d | 750 +++++ .../libphobos.phobos/std_datetime_timezone.d | 15 + .../testsuite/libphobos.phobos/std_demangle.d | 33 + .../libphobos.phobos/std_digest_crc.d | 207 ++ .../libphobos.phobos/std_digest_hmac.d | 145 + .../libphobos.phobos/std_digest_md.d | 124 + .../libphobos.phobos/std_digest_murmurhash.d | 82 + .../libphobos.phobos/std_digest_package.d | 492 ++++ .../libphobos.phobos/std_digest_ripemd.d | 127 + .../libphobos.phobos/std_digest_sha.d | 163 ++ .../testsuite/libphobos.phobos/std_encoding.d | 167 ++ .../libphobos.phobos/std_exception.d | 543 ++++ ...llocator_building_blocks_affix_allocator.d | 14 + ...cator_building_blocks_aligned_block_list.d | 139 + ...allocator_building_blocks_allocator_list.d | 45 + ...building_blocks_ascending_page_allocator.d | 52 + ...llocator_building_blocks_bitmapped_block.d | 139 + ...tal_allocator_building_blocks_bucketizer.d | 23 + ...cator_building_blocks_fallback_allocator.d | 16 + ...ntal_allocator_building_blocks_free_list.d | 45 + ...ocator_building_blocks_kernighan_ritchie.d | 40 + ...ntal_allocator_building_blocks_quantizer.d | 23 + ...imental_allocator_building_blocks_region.d | 90 + ...locator_building_blocks_scoped_allocator.d | 13 + ...tal_allocator_building_blocks_segregator.d | 43 + ...llocator_building_blocks_stats_collector.d | 33 + .../std_experimental_allocator_common.d | 33 + .../std_experimental_allocator_gc_allocator.d | 10 + .../std_experimental_allocator_mallocator.d | 19 + .../std_experimental_allocator_package.d | 263 ++ .../std_experimental_allocator_showcase.d | 22 + .../std_experimental_allocator_typed.d | 34 + .../testsuite/libphobos.phobos/std_file.d | 756 ++++++ .../libphobos.phobos/std_format_package.d | 139 + .../libphobos.phobos/std_format_read.d | 275 ++ .../libphobos.phobos/std_format_spec.d | 43 + .../libphobos.phobos/std_format_write.d | 421 +++ .../libphobos.phobos/std_functional.d | 360 +++ .../testsuite/libphobos.phobos/std_getopt.d | 18 + .../testsuite/libphobos.phobos/std_int128.d | 128 + .../libphobos.phobos/std_internal_cstring.d | 47 + .../std_internal_scopebuffer.d | 9 + .../testsuite/libphobos.phobos/std_json.d | 252 ++ .../libphobos.phobos/std_logger_core.d | 22 + .../libphobos.phobos/std_logger_nulllogger.d | 10 + .../libphobos.phobos/std_math_algebraic.d | 163 ++ .../libphobos.phobos/std_math_exponential.d | 279 ++ .../libphobos.phobos/std_math_hardware.d | 18 + .../libphobos.phobos/std_math_operations.d | 217 ++ .../libphobos.phobos/std_math_remainder.d | 54 + .../libphobos.phobos/std_math_rounding.d | 171 ++ .../libphobos.phobos/std_math_traits.d | 189 ++ .../libphobos.phobos/std_math_trigonometry.d | 168 ++ .../testsuite/libphobos.phobos/std_meta.d | 525 ++++ .../testsuite/libphobos.phobos/std_mmfile.d | 43 + .../testsuite/libphobos.phobos/std_numeric.d | 203 ++ .../libphobos.phobos/std_outbuffer.d | 95 + .../testsuite/libphobos.phobos/std_package.d | 27 + .../libphobos.phobos/std_parallelism.d | 37 + .../testsuite/libphobos.phobos/std_path.d | 611 +++++ .../testsuite/libphobos.phobos/std_random.d | 578 ++++ .../libphobos.phobos/std_range_interfaces.d | 32 + .../libphobos.phobos/std_range_package.d | 1346 +++++++++ .../libphobos.phobos/std_range_primitives.d | 591 ++++ .../libphobos.phobos/std_regex_package.d | 175 ++ .../testsuite/libphobos.phobos/std_signals.d | 85 + .../testsuite/libphobos.phobos/std_socket.d | 66 + .../testsuite/libphobos.phobos/std_stdio.d | 185 ++ .../testsuite/libphobos.phobos/std_string.d | 892 ++++++ .../testsuite/libphobos.phobos/std_sumtype.d | 301 ++ .../testsuite/libphobos.phobos/std_traits.d | 2419 +++++++++++++++++ .../testsuite/libphobos.phobos/std_typecons.d | 1931 +++++++++++++ .../libphobos.phobos/std_typetuple.d | 24 + .../libphobos.phobos/std_uni_package.d | 547 ++++ .../testsuite/libphobos.phobos/std_uri.d | 71 + .../testsuite/libphobos.phobos/std_utf.d | 474 ++++ .../testsuite/libphobos.phobos/std_uuid.d | 252 ++ .../testsuite/libphobos.phobos/std_variant.d | 291 ++ .../testsuite/libphobos.phobos/std_zlib.d | 29 + 108 files changed, 29861 insertions(+) create mode 100644 libphobos/testsuite/libphobos.phobos/phobos.exp create mode 100644 libphobos/testsuite/libphobos.phobos/std_algorithm_comparison.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_algorithm_iteration.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_algorithm_mutation.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_algorithm_searching.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_algorithm_setops.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_algorithm_sorting.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_array.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_ascii.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_base64.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_bigint.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_bitmanip.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_checkedint.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_complex.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_concurrency.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_container_array.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_container_binaryheap.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_container_dlist.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_container_rbtree.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_container_slist.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_container_util.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_conv.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_csv.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_datetime_date.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_datetime_interval.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_datetime_package.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_datetime_stopwatch.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_datetime_systime.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_datetime_timezone.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_demangle.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_digest_crc.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_digest_hmac.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_digest_md.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_digest_murmurhash.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_digest_package.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_digest_ripemd.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_digest_sha.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_encoding.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_exception.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_affix_allocator.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_aligned_block_list.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_allocator_list.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_ascending_page_allocator.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_bitmapped_block.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_bucketizer.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_fallback_allocator.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_free_list.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_kernighan_ritchie.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_quantizer.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_region.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_scoped_allocator.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_segregator.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_stats_collector.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_experimental_allocator_common.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_experimental_allocator_gc_allocator.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_experimental_allocator_mallocator.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_experimental_allocator_package.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_experimental_allocator_showcase.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_experimental_allocator_typed.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_file.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_format_package.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_format_read.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_format_spec.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_format_write.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_functional.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_getopt.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_int128.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_internal_cstring.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_internal_scopebuffer.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_json.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_logger_core.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_logger_nulllogger.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_math_algebraic.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_math_exponential.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_math_hardware.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_math_operations.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_math_remainder.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_math_rounding.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_math_traits.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_math_trigonometry.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_meta.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_mmfile.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_numeric.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_outbuffer.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_package.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_parallelism.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_path.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_random.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_range_interfaces.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_range_package.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_range_primitives.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_regex_package.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_signals.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_socket.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_stdio.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_string.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_sumtype.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_traits.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_typecons.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_typetuple.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_uni_package.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_uri.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_utf.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_uuid.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_variant.d create mode 100644 libphobos/testsuite/libphobos.phobos/std_zlib.d diff --git a/libphobos/testsuite/libphobos.phobos/phobos.exp b/libphobos/testsuite/libphobos.phobos/phobos.exp new file mode 100644 index 000000000000..21ce4cea4482 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/phobos.exp @@ -0,0 +1,50 @@ +# Copyright (C) 2019-2025 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# Immediately exit if we can't run target executables. +if { ![isnative] } { + return +} + +# Skip running test if phobos was not built on the target. +if { ![is-effective-target d_runtime_has_std_library] } { + return +} + +# Gather a list of all tests. +set tests [lsort [find $srcdir/$subdir *.d]] + +set version_flags "-fversion=StdUnittest" + +if { [is-effective-target linux_pre_2639] } { + lappend version_flags "-fversion=Linux_Pre_2639" +} + +set libphobos_skip_tests { + # Skip concurrency.d test: SEGVs or hangs on macOS 13+ (PR d/111628). + { libphobos.phobos/std_concurrency.d { x86_64-apple-darwin2[2-9]* } } +} + +# Initialize dg. +dg-init + +# Main loop. +foreach test $tests { + dg-runtest $test "" "-Wno-deprecated -fmain $version_flags" +} + +# All done. +dg-finish diff --git a/libphobos/testsuite/libphobos.phobos/shared/phobos-shared.exp b/libphobos/testsuite/libphobos.phobos/shared/phobos-shared.exp index 31cc13dd9ae2..3f62864b42a2 100644 --- a/libphobos/testsuite/libphobos.phobos/shared/phobos-shared.exp +++ b/libphobos/testsuite/libphobos.phobos/shared/phobos-shared.exp @@ -24,6 +24,11 @@ if { ![is-effective-target d_runtime_has_std_library] } { return } +# Skip running test if not doing expensive tests. +if { ![is-effective-target run_expensive_tests] } { + return +} + # Gather a list of all tests. set tests [lsort [filter_libphobos_unittests [find $srcdir/../src "*.d"]]] diff --git a/libphobos/testsuite/libphobos.phobos/static/phobos-static.exp b/libphobos/testsuite/libphobos.phobos/static/phobos-static.exp index 642019c7f6d7..ecccbc952cf8 100644 --- a/libphobos/testsuite/libphobos.phobos/static/phobos-static.exp +++ b/libphobos/testsuite/libphobos.phobos/static/phobos-static.exp @@ -24,6 +24,11 @@ if { ![is-effective-target d_runtime_has_std_library] } { return } +# Skip running test if not doing expensive tests. +if { ![is-effective-target run_expensive_tests] } { + return +} + # Gather a list of all tests. set tests [lsort [filter_libphobos_unittests [find $srcdir/../src "*.d"]]] diff --git a/libphobos/testsuite/libphobos.phobos/std_algorithm_comparison.d b/libphobos/testsuite/libphobos.phobos/std_algorithm_comparison.d new file mode 100644 index 000000000000..800694039a09 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_algorithm_comparison.d @@ -0,0 +1,454 @@ +@safe @nogc unittest +{ + import std.algorithm.comparison; + + assert(3.among(1, 42, 24, 3, 2)); + + if (auto pos = "bar".among("foo", "bar", "baz")) + assert(pos == 2); + else + assert(false); + + // 42 is larger than 24 + assert(42.among!((lhs, rhs) => lhs > rhs)(43, 24, 100) == 2); +} + +@safe @nogc unittest +{ + import std.algorithm.comparison; + + assert(3.among!(2, 3, 4)); + assert("bar".among!("foo", "bar", "baz") == 2); +} + +@system unittest +{ + import std.algorithm.comparison; + + import std.algorithm.iteration : map; + import std.format : format; + + class A + { + int a; + this(int a) {this.a = a;} + @property int i() { return a; } + } + interface I { } + class B : I { } + + Object[] arr = [new A(1), new B(), null]; + + auto results = arr.map!(castSwitch!( + (A a) => "A with a value of %d".format(a.a), + (I i) => "derived from I", + () => "null reference", + ))(); + + // A is handled directly: + assert(results[0] == "A with a value of 1"); + // B has no handler - it is handled by the handler of I: + assert(results[1] == "derived from I"); + // null is handled by the null handler: + assert(results[2] == "null reference"); +} + +@system unittest +{ + import std.algorithm.comparison; + + import std.exception : assertThrown; + + class A { } + class B { } + // Void handlers are allowed if they throw: + assertThrown!Exception( + new B().castSwitch!( + (A a) => 1, + (B d) { throw new Exception("B is not allowed!"); } + )() + ); + + // Void handlers are also allowed if all the handlers are void: + new A().castSwitch!( + (A a) { }, + (B b) { assert(false); }, + )(); +} + +@safe @nogc unittest +{ + import std.algorithm.comparison; + + assert(clamp(2, 1, 3) == 2); + assert(clamp(0, 1, 3) == 1); + assert(clamp(4, 1, 3) == 3); + + assert(clamp(1, 1, 1) == 1); + + assert(clamp(5, -1, 2u) == 2); + + auto x = clamp(42, uint.max, uint.max); + static assert(is(typeof(x) == int)); + assert(x == -1); +} + +pure @safe unittest +{ + import std.algorithm.comparison; + + int result; + + result = cmp("abc", "abc"); + assert(result == 0); + result = cmp("", ""); + assert(result == 0); + result = cmp("abc", "abcd"); + assert(result < 0); + result = cmp("abcd", "abc"); + assert(result > 0); + result = cmp("abc"d, "abd"); + assert(result < 0); + result = cmp("bbc", "abc"w); + assert(result > 0); + result = cmp("aaa", "aaaa"d); + assert(result < 0); + result = cmp("aaaa", "aaa"d); + assert(result > 0); + result = cmp("aaa", "aaa"d); + assert(result == 0); + result = cmp("aaa"d, "aaa"d); + assert(result == 0); + result = cmp(cast(int[])[], cast(int[])[]); + assert(result == 0); + result = cmp([1, 2, 3], [1, 2, 3]); + assert(result == 0); + result = cmp([1, 3, 2], [1, 2, 3]); + assert(result > 0); + result = cmp([1, 2, 3], [1L, 2, 3, 4]); + assert(result < 0); + result = cmp([1L, 2, 3], [1, 2]); + assert(result > 0); +} + +pure @safe unittest +{ + import std.algorithm.comparison; + + int result; + + result = cmp!"a > b"("abc", "abc"); + assert(result == 0); + result = cmp!"a > b"("", ""); + assert(result == 0); + result = cmp!"a > b"("abc", "abcd"); + assert(result < 0); + result = cmp!"a > b"("abcd", "abc"); + assert(result > 0); + result = cmp!"a > b"("abc"d, "abd"); + assert(result > 0); + result = cmp!"a > b"("bbc", "abc"w); + assert(result < 0); + result = cmp!"a > b"("aaa", "aaaa"d); + assert(result < 0); + result = cmp!"a > b"("aaaa", "aaa"d); + assert(result > 0); + result = cmp!"a > b"("aaa", "aaa"d); + assert(result == 0); + result = cmp("aaa"d, "aaa"d); + assert(result == 0); + result = cmp!"a > b"(cast(int[])[], cast(int[])[]); + assert(result == 0); + result = cmp!"a > b"([1, 2, 3], [1, 2, 3]); + assert(result == 0); + result = cmp!"a > b"([1, 3, 2], [1, 2, 3]); + assert(result < 0); + result = cmp!"a > b"([1, 2, 3], [1L, 2, 3, 4]); + assert(result < 0); + result = cmp!"a > b"([1L, 2, 3], [1, 2]); + assert(result > 0); +} + +@safe @nogc unittest +{ + import std.algorithm.comparison; + + import std.algorithm.comparison : equal; + import std.math.operations : isClose; + + int[4] a = [ 1, 2, 4, 3 ]; + assert(!equal(a[], a[1..$])); + assert(equal(a[], a[])); + assert(equal!((a, b) => a == b)(a[], a[])); + + // different types + double[4] b = [ 1.0, 2, 4, 3]; + assert(!equal(a[], b[1..$])); + assert(equal(a[], b[])); + + // predicated: ensure that two vectors are approximately equal + double[4] c = [ 1.0000000005, 2, 4, 3]; + assert(equal!isClose(b[], c[])); +} + +@safe unittest +{ + import std.algorithm.comparison; + + import std.algorithm.comparison : equal; + import std.range : iota, chunks; + assert(equal!(equal!equal)( + [[[0, 1], [2, 3]], [[4, 5], [6, 7]]], + iota(0, 8).chunks(2).chunks(2) + )); +} + +@safe unittest +{ + import std.algorithm.comparison; + + with(EditOp) + { + assert(levenshteinDistanceAndPath("foo", "foobar")[1] == [none, none, none, insert, insert, insert]); + assert(levenshteinDistanceAndPath("banana", "fazan")[1] == [substitute, none, substitute, none, none, remove]); + } +} + +@safe unittest +{ + import std.algorithm.comparison; + + import std.algorithm.iteration : filter; + import std.uni : toUpper; + + assert(levenshteinDistance("cat", "rat") == 1); + assert(levenshteinDistance("parks", "spark") == 2); + assert(levenshteinDistance("abcde", "abcde") == 0); + assert(levenshteinDistance("abcde", "abCde") == 1); + assert(levenshteinDistance("kitten", "sitting") == 3); + assert(levenshteinDistance!((a, b) => toUpper(a) == toUpper(b)) + ("parks", "SPARK") == 2); + assert(levenshteinDistance("parks".filter!"true", "spark".filter!"true") == 2); + assert(levenshteinDistance("ID", "I♥D") == 1); +} + +@safe unittest +{ + import std.algorithm.comparison; + + string a = "Saturday", b = "Sundays"; + auto p = levenshteinDistanceAndPath(a, b); + assert(p[0] == 4); + assert(equal(p[1], "nrrnsnnni")); +} + +@safe @nogc unittest +{ + import std.algorithm.comparison; + + int a = 5; + short b = 6; + double c = 2; + auto d = max(a, b); + assert(is(typeof(d) == int)); + assert(d == 6); + auto e = min(a, b, c); + assert(is(typeof(e) == double)); + assert(e == 2); +} + +@safe @nogc unittest +{ + import std.algorithm.comparison; + + int a = 5; + short b = 6; + double c = 2; + auto d = min(a, b); + static assert(is(typeof(d) == int)); + assert(d == 5); + auto e = min(a, b, c); + static assert(is(typeof(e) == double)); + assert(e == 2); + ulong f = 0xffff_ffff_ffff; + const uint g = min(f, 0xffff_0000); + assert(g == 0xffff_0000); + dchar h = 100; + uint i = 101; + static assert(is(typeof(min(h, i)) == dchar)); + static assert(is(typeof(min(i, h)) == uint)); + assert(min(h, i) == 100); +} + +@safe @nogc unittest +{ + import std.algorithm.comparison; + + int a = -10; + uint f = 10; + static assert(is(typeof(min(a, f)) == int)); + assert(min(a, f) == -10); +} + +@safe unittest +{ + import std.algorithm.comparison; + + import std.datetime; + assert(min(Date(2012, 12, 21), Date(1982, 1, 4)) == Date(1982, 1, 4)); + assert(min(Date(1982, 1, 4), Date(2012, 12, 21)) == Date(1982, 1, 4)); + assert(min(Date(1982, 1, 4), Date.min) == Date.min); + assert(min(Date.min, Date(1982, 1, 4)) == Date.min); + assert(min(Date(1982, 1, 4), Date.max) == Date(1982, 1, 4)); + assert(min(Date.max, Date(1982, 1, 4)) == Date(1982, 1, 4)); + assert(min(Date.min, Date.max) == Date.min); + assert(min(Date.max, Date.min) == Date.min); +} + +@safe @nogc unittest +{ + import std.algorithm.comparison; + + int[6] x = [ 1, 5, 2, 7, 4, 3 ]; + double[6] y = [ 1.0, 5, 2, 7.3, 4, 8 ]; + auto m = mismatch(x[], y[]); + assert(m[0] == x[3 .. $]); + assert(m[1] == y[3 .. $]); + + auto m2 = mismatch(x[], y[], x[], y[]); + assert(m2[0] == x[3 .. $]); + assert(m2[1] == y[3 .. $]); + assert(m2[2] == x[3 .. $]); + assert(m2[3] == y[3 .. $]); +} + +@safe unittest +{ + import std.algorithm.comparison; + + string res = 2.predSwitch!"a < b"( + 1, "less than 1", + 5, "less than 5", + 10, "less than 10", + "greater or equal to 10"); + + assert(res == "less than 5"); + + //The arguments are lazy, which allows us to use predSwitch to create + //recursive functions: + int factorial(int n) + { + return n.predSwitch!"a <= b"( + -1, {throw new Exception("Can not calculate n! for n < 0");}(), + 0, 1, // 0! = 1 + n * factorial(n - 1) // n! = n * (n - 1)! for n >= 0 + ); + } + assert(factorial(3) == 6); + + //Void return expressions are allowed if they always throw: + import std.exception : assertThrown; + assertThrown!Exception(factorial(-9)); +} + +@safe nothrow pure unittest +{ + import std.algorithm.comparison; + + assert(isSameLength([1, 2, 3], [4, 5, 6])); + assert(isSameLength([1, 2, 3], [4, 5, 6], [7, 8, 9])); + assert(isSameLength([0.3, 90.4, 23.7, 119.2], [42.6, 23.6, 95.5, 6.3])); + assert(isSameLength("abc", "xyz")); + assert(isSameLength("abc", "xyz", [1, 2, 3])); + + int[] a; + int[] b; + assert(isSameLength(a, b)); + assert(isSameLength(a, b, a, a, b, b, b)); + + assert(!isSameLength([1, 2, 3], [4, 5])); + assert(!isSameLength([1, 2, 3], [4, 5, 6], [7, 8])); + assert(!isSameLength([0.3, 90.4, 23.7], [42.6, 23.6, 95.5, 6.3])); + assert(!isSameLength("abcd", "xyz")); + assert(!isSameLength("abcd", "xyz", "123")); + assert(!isSameLength("abcd", "xyz", "1234")); +} + +@safe pure unittest +{ + import std.algorithm.comparison; + + import std.typecons : Yes; + + assert(isPermutation([1, 2, 3], [3, 2, 1])); + assert(isPermutation([1.1, 2.3, 3.5], [2.3, 3.5, 1.1])); + assert(isPermutation("abc", "bca")); + + assert(!isPermutation([1, 2], [3, 4])); + assert(!isPermutation([1, 1, 2, 3], [1, 2, 2, 3])); + assert(!isPermutation([1, 1], [1, 1, 1])); + + // Faster, but allocates GC handled memory + assert(isPermutation!(Yes.allocateGC)([1.1, 2.3, 3.5], [2.3, 3.5, 1.1])); + assert(!isPermutation!(Yes.allocateGC)([1, 2], [3, 4])); +} + +@safe pure unittest +{ + import std.algorithm.comparison; + + const a = 1; + const b = 2; + auto ab = either(a, b); + static assert(is(typeof(ab) == const(int))); + assert(ab == a); + + auto c = 2; + const d = 3; + auto cd = either!(a => a == 3)(c, d); // use predicate + static assert(is(typeof(cd) == int)); + assert(cd == d); + + auto e = 0; + const f = 2; + auto ef = either(e, f); + static assert(is(typeof(ef) == int)); + assert(ef == f); +} + +@safe pure unittest +{ + import std.algorithm.comparison; + + immutable p = 1; + immutable q = 2; + auto pq = either(p, q); + static assert(is(typeof(pq) == immutable(int))); + assert(pq == p); + + assert(either(3, 4) == 3); + assert(either(0, 4) == 4); + assert(either(0, 0) == 0); + assert(either("", "a") == ""); +} + +@safe pure unittest +{ + import std.algorithm.comparison; + + string r = null; + assert(either(r, "a") == "a"); + assert(either("a", "") == "a"); + + immutable s = [1, 2]; + assert(either(s, s) == s); + + assert(either([0, 1], [1, 2]) == [0, 1]); + assert(either([0, 1], [1]) == [0, 1]); + assert(either("a", "b") == "a"); + + static assert(!__traits(compiles, either(1, "a"))); + static assert(!__traits(compiles, either(1.0, "a"))); + static assert(!__traits(compiles, either('a', "a"))); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_algorithm_iteration.d b/libphobos/testsuite/libphobos.phobos/std_algorithm_iteration.d new file mode 100644 index 000000000000..a4f74fb9394a --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_algorithm_iteration.d @@ -0,0 +1,1004 @@ +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range, std.stdio; + import std.typecons : tuple; + + ulong counter = 0; + double fun(int x) + { + ++counter; + // http://en.wikipedia.org/wiki/Quartic_function + return ( (x + 4.0) * (x + 1.0) * (x - 1.0) * (x - 3.0) ) / 14.0 + 0.5; + } + // Without cache, with array (greedy) + auto result1 = iota(-4, 5).map!(a =>tuple(a, fun(a)))() + .filter!(a => a[1] < 0)() + .map!(a => a[0])() + .array(); + + // the values of x that have a negative y are: + assert(equal(result1, [-3, -2, 2])); + + // Check how many times fun was evaluated. + // As many times as the number of items in both source and result. + assert(counter == iota(-4, 5).length + result1.length); + + counter = 0; + // Without array, with cache (lazy) + auto result2 = iota(-4, 5).map!(a =>tuple(a, fun(a)))() + .cache() + .filter!(a => a[1] < 0)() + .map!(a => a[0])(); + + // the values of x that have a negative y are: + assert(equal(result2, [-3, -2, 2])); + + // Check how many times fun was evaluated. + // Only as many times as the number of items in source. + assert(counter == iota(-4, 5).length); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range; + int i = 0; + + auto r = iota(0, 4).tee!((a){i = a;}, No.pipeOnPop); + auto r1 = r.take(3).cache(); + auto r2 = r.cache().take(3); + + assert(equal(r1, [0, 1, 2])); + assert(i == 2); //The last "seen" element was 2. The data in cache has been cleared. + + assert(equal(r2, [0, 1, 2])); + assert(i == 3); //cache has accessed 3. It is still stored internally by cache. +} + +@safe @nogc unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range : chain, only; + auto squares = + chain(only(1, 2, 3, 4), only(5, 6)).map!(a => a * a); + assert(equal(squares, only(1, 4, 9, 16, 25, 36))); +} + +@safe unittest +{ + import std.algorithm.iteration; + + auto sums = [2, 4, 6, 8]; + auto products = [1, 4, 9, 16]; + + size_t i = 0; + foreach (result; [ 1, 2, 3, 4 ].map!("a + a", "a * a")) + { + assert(result[0] == sums[i]); + assert(result[1] == products[i]); + ++i; + } +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.conv : to; + + alias stringize = map!(to!string); + assert(equal(stringize([ 1, 2, 3, 4 ]), [ "1", "2", "3", "4" ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.range : iota; + import std.typecons : No; + + int[] arr; + iota(5).each!(n => arr ~= n); + assert(arr == [0, 1, 2, 3, 4]); + + // stop iterating early + iota(5).each!((n) { arr ~= n; return No.each; }); + assert(arr == [0, 1, 2, 3, 4, 0]); + + // If the range supports it, the value can be mutated in place + arr.each!((ref n) => n++); + assert(arr == [1, 2, 3, 4, 5, 1]); + + arr.each!"a++"; + assert(arr == [2, 3, 4, 5, 6, 2]); + + auto m = arr.map!(n => n); + // by-ref lambdas are not allowed for non-ref ranges + static assert(!__traits(compiles, m.each!((ref n) => n++))); + + // The default predicate consumes the range + (&m).each(); + assert(m.empty); +} + +@safe unittest +{ + import std.algorithm.iteration; + + auto arr = new size_t[4]; + + arr.each!"a=i"(); + assert(arr == [0, 1, 2, 3]); + + arr.each!((i, ref e) => e = i * 2); + assert(arr == [0, 2, 4, 6]); +} + +@system unittest +{ + import std.algorithm.iteration; + + static class S + { + int x; + int opApply(scope int delegate(ref int _x) dg) { return dg(x); } + } + + auto s = new S; + s.each!"a++"; + assert(s.x == 1); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.math.operations : isClose; + import std.range; + + int[] arr = [ 1, 2, 3, 4, 5 ]; + + // Filter below 3 + auto small = filter!(a => a < 3)(arr); + assert(equal(small, [ 1, 2 ])); + + // Filter again, but with Uniform Function Call Syntax (UFCS) + auto sum = arr.filter!(a => a < 3); + assert(equal(sum, [ 1, 2 ])); + + // In combination with chain() to span multiple ranges + int[] a = [ 3, -2, 400 ]; + int[] b = [ 100, -101, 102 ]; + auto r = chain(a, b).filter!(a => a > 0); + assert(equal(r, [ 3, 400, 100, 102 ])); + + // Mixing convertible types is fair game, too + double[] c = [ 2.5, 3.0 ]; + auto r1 = chain(c, a, b).filter!(a => cast(int) a != a); + assert(isClose(r1, [ 2.5 ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range; + + int[] arr = [ 1, 2, 3, 4, 5 ]; + auto small = filterBidirectional!("a < 3")(arr); + static assert(isBidirectionalRange!(typeof(small))); + assert(small.back == 2); + assert(equal(small, [ 1, 2 ])); + assert(equal(retro(small), [ 2, 1 ])); + // In combination with chain() to span multiple ranges + int[] a = [ 3, -2, 400 ]; + int[] b = [ 100, -101, 102 ]; + auto r = filterBidirectional!("a > 0")(chain(a, b)); + assert(r.back == 102); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.typecons : tuple, Tuple; + + int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ]; + assert(equal(group(arr), [ tuple(1, 1u), tuple(2, 4u), tuple(3, 1u), + tuple(4, 3u), tuple(5, 1u) ][])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.sorting : sort; + import std.array : assocArray; + + uint[string] result; + auto range = ["a", "b", "a", "c", "b", "c", "c", "d", "e"]; + result = range.sort!((a, b) => a < b) + .group + .assocArray; + + assert(result == ["a": 2U, "b": 2U, "c": 3U, "d": 1U, "e": 1U]); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + + // Grouping by particular attribute of each element: + auto data = [ + [1, 1], + [1, 2], + [2, 2], + [2, 3] + ]; + + auto r1 = data.chunkBy!((a,b) => a[0] == b[0]); + assert(r1.equal!equal([ + [[1, 1], [1, 2]], + [[2, 2], [2, 3]] + ])); + + auto r2 = data.chunkBy!((a,b) => a[1] == b[1]); + assert(r2.equal!equal([ + [[1, 1]], + [[1, 2], [2, 2]], + [[2, 3]] + ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range.primitives; + import std.typecons : tuple; + + // Grouping by particular attribute of each element: + auto range = + [ + [1, 1], + [1, 1], + [1, 2], + [2, 2], + [2, 3], + [2, 3], + [3, 3] + ]; + + auto byX = chunkBy!(a => a[0])(range); + auto expected1 = + [ + tuple(1, [[1, 1], [1, 1], [1, 2]]), + tuple(2, [[2, 2], [2, 3], [2, 3]]), + tuple(3, [[3, 3]]) + ]; + foreach (e; byX) + { + assert(!expected1.empty); + assert(e[0] == expected1.front[0]); + assert(e[1].equal(expected1.front[1])); + expected1.popFront(); + } + + auto byY = chunkBy!(a => a[1])(range); + auto expected2 = + [ + tuple(1, [[1, 1], [1, 1]]), + tuple(2, [[1, 2], [2, 2]]), + tuple(3, [[2, 3], [2, 3], [3, 3]]) + ]; + foreach (e; byY) + { + assert(!expected2.empty); + assert(e[0] == expected2.front[0]); + assert(e[1].equal(expected2.front[1])); + expected2.popFront(); + } +} + +nothrow pure @safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range : dropExactly; + auto source = [4, 3, 2, 11, 0, -3, -3, 5, 3, 0]; + + auto result1 = source.splitWhen!((a,b) => a <= b); + assert(result1.save.equal!equal([ + [4, 3, 2], + [11, 0, -3], + [-3], + [5, 3, 0] + ])); + + //splitWhen, like chunkBy, is currently a reference range (this may change + //in future). Remember to call `save` when appropriate. + auto result2 = result1.dropExactly(2); + assert(result1.save.equal!equal([ + [-3], + [5, 3, 0] + ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.conv : text; + + assert(["abc", "def"].joiner.equal("abcdef")); + assert(["Mary", "has", "a", "little", "lamb"] + .joiner("...") + .equal("Mary...has...a...little...lamb")); + assert(["", "abc"].joiner("xyz").equal("xyzabc")); + assert([""].joiner("xyz").equal("")); + assert(["", ""].joiner("xyz").equal("xyz")); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range : repeat; + + assert([""].joiner.equal("")); + assert(["", ""].joiner.equal("")); + assert(["", "abc"].joiner.equal("abc")); + assert(["abc", ""].joiner.equal("abc")); + assert(["abc", "def"].joiner.equal("abcdef")); + assert(["Mary", "has", "a", "little", "lamb"].joiner.equal("Maryhasalittlelamb")); + assert("abc".repeat(3).joiner.equal("abcabcabc")); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + auto a = [ [1, 2, 3], [42, 43] ]; + auto j = joiner(a); + j.front = 44; + assert(a == [ [44, 2, 3], [42, 43] ]); + assert(equal(j, [44, 2, 3, 42, 43])); +} + +@safe pure unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range : chain, cycle, iota, only, retro, take, zip; + import std.format : format; + + static immutable number = "12345678"; + static immutable delimiter = ","; + auto formatted = number.retro + .zip(3.iota.cycle.take(number.length)) + .map!(z => chain(z[0].only, z[1] == 2 ? delimiter : null)) + .joiner + .retro; + static immutable expected = "12,345,678"; + assert(formatted.equal(expected)); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range : retro; + + auto a = [[1, 2, 3], [4, 5]]; + auto j = a.joiner; + j.back = 44; + assert(a == [[1, 2, 3], [4, 44]]); + assert(equal(j.retro, [44, 4, 3, 2, 1])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : max, min; + import std.math.operations : isClose; + import std.range; + + int[] arr = [ 1, 2, 3, 4, 5 ]; + // Sum all elements + auto sum = reduce!((a,b) => a + b)(0, arr); + assert(sum == 15); + + // Sum again, using a string predicate with "a" and "b" + sum = reduce!"a + b"(0, arr); + assert(sum == 15); + + // Compute the maximum of all elements + auto largest = reduce!(max)(arr); + assert(largest == 5); + + // Max again, but with Uniform Function Call Syntax (UFCS) + largest = arr.reduce!(max); + assert(largest == 5); + + // Compute the number of odd elements + auto odds = reduce!((a,b) => a + (b & 1))(0, arr); + assert(odds == 3); + + // Compute the sum of squares + auto ssquares = reduce!((a,b) => a + b * b)(0, arr); + assert(ssquares == 55); + + // Chain multiple ranges into seed + int[] a = [ 3, 4 ]; + int[] b = [ 100 ]; + auto r = reduce!("a + b")(chain(a, b)); + assert(r == 107); + + // Mixing convertible types is fair game, too + double[] c = [ 2.5, 3.0 ]; + auto r1 = reduce!("a + b")(chain(a, b, c)); + assert(isClose(r1, 112.5)); + + // To minimize nesting of parentheses, Uniform Function Call Syntax can be used + auto r2 = chain(a, b, c).reduce!("a + b"); + assert(isClose(r2, 112.5)); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : max, min; + import std.math.operations : isClose; + import std.math.algebraic : sqrt; + import std.typecons : tuple, Tuple; + + double[] a = [ 3.0, 4, 7, 11, 3, 2, 5 ]; + // Compute minimum and maximum in one pass + auto r = reduce!(min, max)(a); + // The type of r is Tuple!(int, int) + assert(isClose(r[0], 2)); // minimum + assert(isClose(r[1], 11)); // maximum + + // Compute sum and sum of squares in one pass + r = reduce!("a + b", "a + b * b")(tuple(0.0, 0.0), a); + assert(isClose(r[0], 35)); // sum + assert(isClose(r[1], 233)); // sum of squares + // Compute average and standard deviation from the above + auto avg = r[0] / a.length; + assert(avg == 5); + auto stdev = sqrt(r[1] / a.length - avg * avg); + assert(cast(int) stdev == 2); +} + +@safe pure unittest +{ + import std.algorithm.iteration; + + immutable arr = [1, 2, 3, 4, 5]; + + // Sum all elements + assert(arr.fold!((a, e) => a + e) == 15); + + // Sum all elements with explicit seed + assert(arr.fold!((a, e) => a + e)(6) == 21); + + import std.algorithm.comparison : min, max; + import std.typecons : tuple; + + // Compute minimum and maximum at the same time + assert(arr.fold!(min, max) == tuple(1, 5)); + + // Compute minimum and maximum at the same time with seeds + assert(arr.fold!(min, max)(0, 7) == tuple(0, 7)); + + // Can be used in a UFCS chain + assert(arr.map!(a => a + 1).fold!((a, e) => a + e) == 20); + + // Return the last element of any range + assert(arr.fold!((a, e) => e) == 5); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : max, min; + import std.array : array; + import std.math.operations : isClose; + import std.range : chain; + + int[] arr = [1, 2, 3, 4, 5]; + // Partial sum of all elements + auto sum = cumulativeFold!((a, b) => a + b)(arr, 0); + assert(sum.array == [1, 3, 6, 10, 15]); + + // Partial sum again, using a string predicate with "a" and "b" + auto sum2 = cumulativeFold!"a + b"(arr, 0); + assert(sum2.array == [1, 3, 6, 10, 15]); + + // Compute the partial maximum of all elements + auto largest = cumulativeFold!max(arr); + assert(largest.array == [1, 2, 3, 4, 5]); + + // Partial max again, but with Uniform Function Call Syntax (UFCS) + largest = arr.cumulativeFold!max; + assert(largest.array == [1, 2, 3, 4, 5]); + + // Partial count of odd elements + auto odds = arr.cumulativeFold!((a, b) => a + (b & 1))(0); + assert(odds.array == [1, 1, 2, 2, 3]); + + // Compute the partial sum of squares + auto ssquares = arr.cumulativeFold!((a, b) => a + b * b)(0); + assert(ssquares.array == [1, 5, 14, 30, 55]); + + // Chain multiple ranges into seed + int[] a = [3, 4]; + int[] b = [100]; + auto r = cumulativeFold!"a + b"(chain(a, b)); + assert(r.array == [3, 7, 107]); + + // Mixing convertible types is fair game, too + double[] c = [2.5, 3.0]; + auto r1 = cumulativeFold!"a + b"(chain(a, b, c)); + assert(isClose(r1, [3, 7, 107, 109.5, 112.5])); + + // To minimize nesting of parentheses, Uniform Function Call Syntax can be used + auto r2 = chain(a, b, c).cumulativeFold!"a + b"; + assert(isClose(r2, [3, 7, 107, 109.5, 112.5])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : max, min; + import std.algorithm.iteration : map; + import std.math.operations : isClose; + import std.typecons : tuple; + + double[] a = [3.0, 4, 7, 11, 3, 2, 5]; + // Compute minimum and maximum in one pass + auto r = a.cumulativeFold!(min, max); + // The type of r is Tuple!(int, int) + assert(isClose(r.map!"a[0]", [3, 3, 3, 3, 3, 2, 2])); // minimum + assert(isClose(r.map!"a[1]", [3, 4, 7, 11, 11, 11, 11])); // maximum + + // Compute sum and sum of squares in one pass + auto r2 = a.cumulativeFold!("a + b", "a + b * b")(tuple(0.0, 0.0)); + assert(isClose(r2.map!"a[0]", [3, 7, 14, 25, 28, 30, 35])); // sum + assert(isClose(r2.map!"a[1]", [9, 25, 74, 195, 204, 208, 233])); // sum of squares +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + + assert("a|bc|def".splitter('|').equal([ "a", "bc", "def" ])); + + int[] a = [1, 0, 2, 3, 0, 4, 5, 6]; + int[][] w = [ [1], [2, 3], [4, 5, 6] ]; + assert(a.splitter(0).equal(w)); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.typecons : Yes; + + assert("a|bc|def".splitter!("a == b", Yes.keepSeparators)('|') + .equal([ "a", "|", "bc", "|", "def" ])); + + int[] a = [1, 0, 2, 3, 0, 4, 5, 6]; + int[][] w = [ [1], [0], [2, 3], [0], [4, 5, 6] ]; + assert(a.splitter!("a == b", Yes.keepSeparators)(0).equal(w)); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + + assert("|ab|".splitter('|').equal([ "", "ab", "" ])); + assert("ab".splitter('|').equal([ "ab" ])); + + assert("a|b||c".splitter('|').equal([ "a", "b", "", "c" ])); + assert("hello world".splitter(' ').equal([ "hello", "", "world" ])); + + auto a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; + auto w = [ [1, 2], [], [3], [4, 5], [] ]; + assert(a.splitter(0).equal(w)); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.typecons : Yes; + + assert("|ab|".splitter!("a == b", Yes.keepSeparators)('|') + .equal([ "", "|", "ab", "|", "" ])); + assert("ab".splitter!("a == b", Yes.keepSeparators)('|') + .equal([ "ab" ])); + + assert("a|b||c".splitter!("a == b", Yes.keepSeparators)('|') + .equal([ "a", "|", "b", "|", "", "|", "c" ])); + assert("hello world".splitter!("a == b", Yes.keepSeparators)(' ') + .equal([ "hello", " ", "", " ", "world" ])); + + auto a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; + auto w = [ [1, 2], [0], [], [0], [3], [0], [4, 5], [0], [] ]; + assert(a.splitter!("a == b", Yes.keepSeparators)(0).equal(w)); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range : empty; + + assert("".splitter('|').empty); + assert("|".splitter('|').equal([ "", "" ])); + assert("||".splitter('|').equal([ "", "", "" ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.typecons : Yes; + import std.range : empty; + + assert("".splitter!("a == b", Yes.keepSeparators)('|').empty); + assert("|".splitter!("a == b", Yes.keepSeparators)('|') + .equal([ "", "|", "" ])); + assert("||".splitter!("a == b", Yes.keepSeparators)('|') + .equal([ "", "|", "", "|", "" ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + + assert("a=>bc=>def".splitter("=>").equal([ "a", "bc", "def" ])); + assert("a|b||c".splitter("||").equal([ "a|b", "c" ])); + assert("hello world".splitter(" ").equal([ "hello", "world" ])); + + int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; + int[][] w = [ [1, 2], [3, 0, 4, 5, 0] ]; + assert(a.splitter([0, 0]).equal(w)); + + a = [ 0, 0 ]; + assert(a.splitter([0, 0]).equal([ (int[]).init, (int[]).init ])); + + a = [ 0, 0, 1 ]; + assert(a.splitter([0, 0]).equal([ [], [1] ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.typecons : Yes; + + assert("a=>bc=>def".splitter!("a == b", Yes.keepSeparators)("=>") + .equal([ "a", "=>", "bc", "=>", "def" ])); + assert("a|b||c".splitter!("a == b", Yes.keepSeparators)("||") + .equal([ "a|b", "||", "c" ])); + assert("hello world".splitter!("a == b", Yes.keepSeparators)(" ") + .equal([ "hello", " ", "world" ])); + + int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; + int[][] w = [ [1, 2], [0, 0], [3, 0, 4, 5, 0] ]; + assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0]).equal(w)); + + a = [ 0, 0 ]; + assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0]) + .equal([ (int[]).init, [0, 0], (int[]).init ])); + + a = [ 0, 0, 1 ]; + assert(a.splitter!("a == b", Yes.keepSeparators)([0, 0]) + .equal([ [], [0, 0], [1] ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.ascii : toLower; + + assert("abXcdxef".splitter!"a.toLower == b"('x').equal( + [ "ab", "cd", "ef" ])); + + auto w = [ [0], [1], [2] ]; + assert(w.splitter!"a.front == b"(1).equal([ [[0]], [[2]] ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.typecons : Yes; + import std.ascii : toLower; + + assert("abXcdxef".splitter!("a.toLower == b", Yes.keepSeparators)('x') + .equal([ "ab", "X", "cd", "x", "ef" ])); + + auto w = [ [0], [1], [2] ]; + assert(w.splitter!("a.front == b", Yes.keepSeparators)(1) + .equal([ [[0]], [[1]], [[2]] ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range.primitives : front; + + assert(equal(splitter!(a => a == '|')("a|bc|def"), [ "a", "bc", "def" ])); + assert(equal(splitter!(a => a == ' ')("hello world"), [ "hello", "", "world" ])); + + int[] a = [ 1, 2, 0, 0, 3, 0, 4, 5, 0 ]; + int[][] w = [ [1, 2], [], [3], [4, 5], [] ]; + assert(equal(splitter!(a => a == 0)(a), w)); + + a = [ 0 ]; + assert(equal(splitter!(a => a == 0)(a), [ (int[]).init, (int[]).init ])); + + a = [ 0, 1 ]; + assert(equal(splitter!(a => a == 0)(a), [ [], [1] ])); + + w = [ [0], [1], [2] ]; + assert(equal(splitter!(a => a.front == 1)(w), [ [[0]], [[2]] ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + + assert("|ab|".splitter('|').equal([ "", "ab", "" ])); + assert("ab".splitter('|').equal([ "ab" ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.typecons : Yes; + + assert("|ab|".splitter!("a == b", Yes.keepSeparators)('|') + .equal([ "", "|", "ab", "|", "" ])); + assert("ab".splitter!("a == b", Yes.keepSeparators)('|') + .equal([ "ab" ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range : retro; + assert("a|bc|def".splitter('|').retro.equal([ "def", "bc", "a" ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.typecons : Yes; + import std.range : retro; + assert("a|bc|def".splitter!("a == b", Yes.keepSeparators)('|') + .retro.equal([ "def", "|", "bc", "|", "a" ])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.ascii : isWhite; + import std.algorithm.comparison : equal; + import std.algorithm.iteration : splitter; + + string str = "Hello World!"; + assert(str.splitter!(isWhite).equal(["Hello", "World!"])); +} + +@safe pure unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + auto a = " a bcd ef gh "; + assert(equal(splitter(a), ["a", "bcd", "ef", "gh"][])); +} + +@safe pure unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + + // substitute single elements + assert("do_it".substitute('_', ' ').equal("do it")); + + // substitute multiple, single elements + assert("do_it".substitute('_', ' ', + 'd', 'g', + 'i', 't', + 't', 'o') + .equal("go to")); + + // substitute subranges + assert("do_it".substitute("_", " ", + "do", "done") + .equal("done it")); + + // substitution works for any ElementType + int[] x = [1, 2, 3]; + auto y = x.substitute(1, 0.1); + assert(y.equal([0.1, 2, 3])); + static assert(is(typeof(y.front) == double)); + + import std.range : retro; + assert([1, 2, 3].substitute(1, 0.1).retro.equal([3, 2, 0.1])); +} + +@safe pure unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + + // substitute subranges of a range + assert("apple_tree".substitute!("apple", "banana", + "tree", "shrub").equal("banana_shrub")); + + // substitute subranges of a range + assert("apple_tree".substitute!('a', 'b', + 't', 'f').equal("bpple_free")); + + // substitute values + assert('a'.substitute!('a', 'b', 't', 'f') == 'b'); +} + +@safe pure unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range.primitives : ElementType; + + int[3] x = [1, 2, 3]; + auto y = x[].substitute(1, 0.1) + .substitute(0.1, 0.2); + static assert(is(typeof(y.front) == double)); + assert(y.equal([0.2, 2, 3])); + + auto z = "42".substitute('2', '3') + .substitute('3', '1'); + static assert(is(ElementType!(typeof(z)) == dchar)); + assert(equal(z, "41")); +} + +@safe pure nothrow unittest +{ + import std.algorithm.iteration; + + import std.range; + + //simple integral sumation + assert(sum([ 1, 2, 3, 4]) == 10); + + //with integral promotion + assert(sum([false, true, true, false, true]) == 3); + assert(sum(ubyte.max.repeat(100)) == 25500); + + //The result may overflow + assert(uint.max.repeat(3).sum() == 4294967293U ); + //But a seed can be used to change the sumation primitive + assert(uint.max.repeat(3).sum(ulong.init) == 12884901885UL); + + //Floating point sumation + assert(sum([1.0, 2.0, 3.0, 4.0]) == 10); + + //Floating point operations have double precision minimum + static assert(is(typeof(sum([1F, 2F, 3F, 4F])) == double)); + assert(sum([1F, 2, 3, 4]) == 10); + + //Force pair-wise floating point sumation on large integers + import std.math.operations : isClose; + assert(iota(ulong.max / 2, ulong.max / 2 + 4096).sum(0.0) + .isClose((ulong.max / 2) * 4096.0 + 4096^^2 / 2)); +} + +@safe @nogc pure nothrow unittest +{ + import std.algorithm.iteration; + + import std.math.operations : isClose; + import std.math.traits : isNaN; + + static immutable arr1 = [1, 2, 3]; + static immutable arr2 = [1.5, 2.5, 12.5]; + + assert(arr1.mean.isClose(2)); + assert(arr2.mean.isClose(5.5)); + + assert(arr1[0 .. 0].mean.isNaN); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.algorithm.mutation : copy; + + int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ]; + assert(equal(uniq(arr), [ 1, 2, 3, 4, 5 ][])); + + // Filter duplicates in-place using copy + arr.length -= arr.uniq().copy(arr).length; + assert(arr == [ 1, 2, 3, 4, 5 ]); + + // Note that uniqueness is only determined consecutively; duplicated + // elements separated by an intervening different element will not be + // eliminated: + assert(equal(uniq([ 1, 1, 2, 1, 1, 3, 1]), [1, 2, 1, 3, 1])); +} + +@safe unittest +{ + import std.algorithm.iteration; + + import std.algorithm.comparison : equal; + import std.range : iota; + assert(equal!equal(iota(3).permutations, + [[0, 1, 2], + [1, 0, 2], + [2, 0, 1], + [0, 2, 1], + [1, 2, 0], + [2, 1, 0]])); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_algorithm_mutation.d b/libphobos/testsuite/libphobos.phobos/std_algorithm_mutation.d new file mode 100644 index 000000000000..3f38d60b8596 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_algorithm_mutation.d @@ -0,0 +1,627 @@ +@safe unittest +{ + import std.algorithm.mutation; + + auto arr = [4, 5, 6, 7, 1, 2, 3]; + auto p = bringToFront(arr[0 .. 4], arr[4 .. $]); + assert(p == arr.length - 4); + assert(arr == [ 1, 2, 3, 4, 5, 6, 7 ]); +} + +@safe unittest +{ + import std.algorithm.mutation; + + import std.algorithm.comparison : equal; + import std.container : SList; + import std.range.primitives : popFrontN; + + auto list = SList!(int)(4, 5, 6, 7, 1, 2, 3); + auto r1 = list[]; + auto r2 = list[]; popFrontN(r2, 4); + assert(equal(r2, [ 1, 2, 3 ])); + bringToFront(r1, r2); + assert(equal(list[], [ 1, 2, 3, 4, 5, 6, 7 ])); +} + +@safe unittest +{ + import std.algorithm.mutation; + + import std.algorithm.comparison : equal; + import std.container : SList; + + auto list = SList!(int)(4, 5, 6, 7); + auto vec = [ 1, 2, 3 ]; + bringToFront(list[], vec); + assert(equal(list[], [ 1, 2, 3, 4 ])); + assert(equal(vec, [ 5, 6, 7 ])); +} + +@safe unittest +{ + import std.algorithm.mutation; + + import std.string : representation; + auto ar = representation("a".dup); + auto br = representation("ç".dup); + + bringToFront(ar, br); + + auto a = cast(char[]) ar; + auto b = cast(char[]) br; + + // Illegal UTF-8 + assert(a == "\303"); + // Illegal UTF-8 + assert(b == "\247a"); +} + +@safe unittest +{ + import std.algorithm.mutation; + + int[] a = [ 1, 5 ]; + int[] b = [ 9, 8 ]; + int[] buf = new int[](a.length + b.length + 10); + auto rem = a.copy(buf); // copy a into buf + rem = b.copy(rem); // copy b into remainder of buf + assert(buf[0 .. a.length + b.length] == [1, 5, 9, 8]); + assert(rem.length == 10); // unused slots in buf +} + +@safe unittest +{ + import std.algorithm.mutation; + + float[] src = [ 1.0f, 5 ]; + double[] dest = new double[src.length]; + src.copy(dest); +} + +@safe unittest +{ + import std.algorithm.mutation; + + import std.range; + int[] src = [ 1, 5, 8, 9, 10 ]; + auto dest = new int[](3); + src.take(dest.length).copy(dest); + assert(dest == [ 1, 5, 8 ]); +} + +@safe unittest +{ + import std.algorithm.mutation; + + import std.algorithm.iteration : filter; + int[] src = [ 1, 5, 8, 9, 10, 1, 2, 0 ]; + auto dest = new int[src.length]; + auto rem = src + .filter!(a => (a & 1) == 1) + .copy(dest); + assert(dest[0 .. $ - rem.length] == [ 1, 5, 9, 1 ]); +} + +@safe unittest +{ + import std.algorithm.mutation; + + import std.algorithm, std.range; + int[] src = [1, 2, 4]; + int[] dest = [0, 0, 0, 0, 0]; + src.retro.copy(dest.retro); + assert(dest == [0, 0, 1, 2, 4]); +} + +@safe unittest +{ + import std.algorithm.mutation; + + int[] a = [ 1, 2, 3, 4 ]; + fill(a, 5); + assert(a == [ 5, 5, 5, 5 ]); +} + +@safe unittest +{ + import std.algorithm.mutation; + + int[] a = [ 1, 2, 3, 4, 5 ]; + int[] b = [ 8, 9 ]; + fill(a, b); + assert(a == [ 8, 9, 8, 9, 8 ]); +} + +@system unittest +{ + import std.algorithm.mutation; + + import core.stdc.stdlib : malloc, free; + + struct S + { + int a = 10; + } + + auto s = (cast(S*) malloc(5 * S.sizeof))[0 .. 5]; + initializeAll(s); + assert(s == [S(10), S(10), S(10), S(10), S(10)]); + + scope(exit) free(s.ptr); +} + +@safe unittest +{ + import std.algorithm.mutation; + + Object obj1 = new Object; + Object obj2 = obj1; + Object obj3; + + move(obj2, obj3); + assert(obj3 is obj1); + // obj2 unchanged + assert(obj2 is obj1); +} + +pure nothrow @safe @nogc unittest +{ + import std.algorithm.mutation; + + // Structs without destructors are simply copied + struct S1 + { + int a = 1; + int b = 2; + } + S1 s11 = { 10, 11 }; + S1 s12; + + move(s11, s12); + + assert(s12 == S1(10, 11)); + assert(s11 == s12); + + // But structs with destructors or postblits are reset to their .init value + // after copying to the target. + struct S2 + { + int a = 1; + int b = 2; + + ~this() pure nothrow @safe @nogc { } + } + S2 s21 = { 3, 4 }; + S2 s22; + + move(s21, s22); + + assert(s21 == S2(1, 2)); + assert(s22 == S2(3, 4)); +} + +pure nothrow @safe @nogc unittest +{ + import std.algorithm.mutation; + + struct S + { + int a = 1; + @disable this(this); + ~this() pure nothrow @safe @nogc {} + } + S s1; + s1.a = 2; + S s2 = move(s1); + assert(s1.a == 1); + assert(s2.a == 2); +} + +pure nothrow @safe @nogc unittest +{ + import std.algorithm.mutation; + + struct S + { + int a; + void opPostMove(const ref S old) + { + assert(a == old.a); + a++; + } + } + S s1; + s1.a = 41; + S s2 = move(s1); + assert(s2.a == 42); +} + +pure nothrow @nogc @system unittest +{ + import std.algorithm.mutation; + + static struct Foo + { + pure nothrow @nogc: + this(int* ptr) { _ptr = ptr; } + ~this() { if (_ptr) ++*_ptr; } + int* _ptr; + } + + int val; + Foo foo1 = void; // uninitialized + auto foo2 = Foo(&val); // initialized + assert(foo2._ptr is &val); + + // Using `move(foo2, foo1)` would have an undefined effect because it would destroy + // the uninitialized foo1. + // moveEmplace directly overwrites foo1 without destroying or initializing it first. + moveEmplace(foo2, foo1); + assert(foo1._ptr is &val); + assert(foo2._ptr is null); + assert(val == 0); +} + +pure nothrow @safe @nogc unittest +{ + import std.algorithm.mutation; + + int[3] a = [ 1, 2, 3 ]; + int[5] b; + assert(moveAll(a[], b[]) is b[3 .. $]); + assert(a[] == b[0 .. 3]); + int[3] cmp = [ 1, 2, 3 ]; + assert(a[] == cmp[]); +} + +pure nothrow @nogc @system unittest +{ + import std.algorithm.mutation; + + static struct Foo + { + ~this() pure nothrow @nogc { if (_ptr) ++*_ptr; } + int* _ptr; + } + int[3] refs = [0, 1, 2]; + Foo[3] src = [Foo(&refs[0]), Foo(&refs[1]), Foo(&refs[2])]; + Foo[5] dst = void; + + auto tail = moveEmplaceAll(src[], dst[]); // move 3 value from src over dst + assert(tail.length == 2); // returns remaining uninitialized values + initializeAll(tail); + + import std.algorithm.searching : all; + assert(src[].all!(e => e._ptr is null)); + assert(dst[0 .. 3].all!(e => e._ptr !is null)); +} + +pure nothrow @safe @nogc unittest +{ + import std.algorithm.mutation; + + int[5] a = [ 1, 2, 3, 4, 5 ]; + int[3] b; + assert(moveSome(a[], b[])[0] is a[3 .. $]); + assert(a[0 .. 3] == b); + assert(a == [ 1, 2, 3, 4, 5 ]); +} + +pure nothrow @nogc @system unittest +{ + import std.algorithm.mutation; + + static struct Foo + { + ~this() pure nothrow @nogc { if (_ptr) ++*_ptr; } + int* _ptr; + } + int[4] refs = [0, 1, 2, 3]; + Foo[4] src = [Foo(&refs[0]), Foo(&refs[1]), Foo(&refs[2]), Foo(&refs[3])]; + Foo[3] dst = void; + + auto res = moveEmplaceSome(src[], dst[]); + assert(res.length == 2); + + import std.algorithm.searching : all; + assert(src[0 .. 3].all!(e => e._ptr is null)); + assert(src[3]._ptr !is null); + assert(dst[].all!(e => e._ptr !is null)); +} + +@safe unittest +{ + import std.algorithm.mutation; + + int[] a = [0, 1, 2, 3]; + assert(remove!(SwapStrategy.stable)(a, 1) == [0, 2, 3]); + a = [0, 1, 2, 3]; + assert(remove!(SwapStrategy.unstable)(a, 1) == [0, 3, 2]); +} + +@safe unittest +{ + import std.algorithm.mutation; + + import std.algorithm.sorting : partition; + + // Put stuff greater than 3 on the left + auto arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert(partition!(a => a > 3, SwapStrategy.stable)(arr) == [1, 2, 3]); + assert(arr == [4, 5, 6, 7, 8, 9, 10, 1, 2, 3]); + + arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert(partition!(a => a > 3, SwapStrategy.semistable)(arr) == [2, 3, 1]); + assert(arr == [4, 5, 6, 7, 8, 9, 10, 2, 3, 1]); + + arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert(partition!(a => a > 3, SwapStrategy.unstable)(arr) == [3, 2, 1]); + assert(arr == [10, 9, 8, 4, 5, 6, 7, 3, 2, 1]); +} + +@safe pure unittest +{ + import std.algorithm.mutation; + + import std.typecons : tuple; + + auto a = [ 0, 1, 2, 3, 4, 5 ]; + assert(remove!(SwapStrategy.stable)(a, 1) == [ 0, 2, 3, 4, 5 ]); + a = [ 0, 1, 2, 3, 4, 5 ]; + assert(remove!(SwapStrategy.stable)(a, 1, 3) == [ 0, 2, 4, 5] ); + a = [ 0, 1, 2, 3, 4, 5 ]; + assert(remove!(SwapStrategy.stable)(a, 1, tuple(3, 6)) == [ 0, 2 ]); + + a = [ 0, 1, 2, 3, 4, 5 ]; + assert(remove!(SwapStrategy.unstable)(a, 1) == [0, 5, 2, 3, 4]); + a = [ 0, 1, 2, 3, 4, 5 ]; + assert(remove!(SwapStrategy.unstable)(a, tuple(1, 4)) == [0, 5, 4]); +} + +@safe pure unittest +{ + import std.algorithm.mutation; + + import std.typecons : tuple; + + // Delete an index + assert([4, 5, 6].remove(1) == [4, 6]); + + // Delete multiple indices + assert([4, 5, 6, 7, 8].remove(1, 3) == [4, 6, 8]); + + // Use an indices range + assert([4, 5, 6, 7, 8].remove(tuple(1, 3)) == [4, 7, 8]); + + // Use an indices range and individual indices + assert([4, 5, 6, 7, 8].remove(0, tuple(1, 3), 4) == [7]); +} + +@safe pure unittest +{ + import std.algorithm.mutation; + + assert([5, 6, 7, 8].remove!(SwapStrategy.stable)(1) == [5, 7, 8]); + assert([5, 6, 7, 8].remove!(SwapStrategy.unstable)(1) == [5, 8, 7]); +} + +@safe unittest +{ + import std.algorithm.mutation; + + static immutable base = [1, 2, 3, 2, 4, 2, 5, 2]; + + int[] arr = base[].dup; + + // using a string-based predicate + assert(remove!("a == 2")(arr) == [ 1, 3, 4, 5 ]); + + // The original array contents have been modified, + // so we need to reset it to its original state. + // The length is unmodified however. + arr[] = base[]; + + // using a lambda predicate + assert(remove!(a => a == 2)(arr) == [ 1, 3, 4, 5 ]); +} + +@safe unittest +{ + import std.algorithm.mutation; + + int[] arr = [ 1, 2, 3 ]; + assert(arr.reverse == [ 3, 2, 1 ]); +} + +@safe unittest +{ + import std.algorithm.mutation; + + char[] arr = "hello\U00010143\u0100\U00010143".dup; + assert(arr.reverse == "\U00010143\u0100\U00010143olleh"); +} + +@safe pure unittest +{ + import std.algorithm.mutation; + + assert(" foobar ".strip(' ') == "foobar"); + assert("00223.444500".strip('0') == "223.4445"); + assert("ëëêéüŗÅpéêëë".strip('ë') == "êéüŗÅpéê"); + assert([1, 1, 0, 1, 1].strip(1) == [0]); + assert([0.0, 0.01, 0.01, 0.0].strip(0).length == 2); +} + +@safe pure unittest +{ + import std.algorithm.mutation; + + assert(" foobar ".strip!(a => a == ' ')() == "foobar"); + assert("00223.444500".strip!(a => a == '0')() == "223.4445"); + assert("ëëêéüŗÅpéêëë".strip!(a => a == 'ë')() == "êéüŗÅpéê"); + assert([1, 1, 0, 1, 1].strip!(a => a == 1)() == [0]); + assert([0.0, 0.01, 0.5, 0.6, 0.01, 0.0].strip!(a => a < 0.4)().length == 2); +} + +@safe pure unittest +{ + import std.algorithm.mutation; + + assert(" foobar ".stripLeft(' ') == "foobar "); + assert("00223.444500".stripLeft('0') == "223.444500"); + assert("ůůűniçodêéé".stripLeft('ů') == "űniçodêéé"); + assert([1, 1, 0, 1, 1].stripLeft(1) == [0, 1, 1]); + assert([0.0, 0.01, 0.01, 0.0].stripLeft(0).length == 3); +} + +@safe pure unittest +{ + import std.algorithm.mutation; + + assert(" foobar ".stripLeft!(a => a == ' ')() == "foobar "); + assert("00223.444500".stripLeft!(a => a == '0')() == "223.444500"); + assert("ůůűniçodêéé".stripLeft!(a => a == 'ů')() == "űniçodêéé"); + assert([1, 1, 0, 1, 1].stripLeft!(a => a == 1)() == [0, 1, 1]); + assert([0.0, 0.01, 0.10, 0.5, 0.6].stripLeft!(a => a < 0.4)().length == 2); +} + +@safe pure unittest +{ + import std.algorithm.mutation; + + assert(" foobar ".stripRight(' ') == " foobar"); + assert("00223.444500".stripRight('0') == "00223.4445"); + assert("ùniçodêéé".stripRight('é') == "ùniçodê"); + assert([1, 1, 0, 1, 1].stripRight(1) == [1, 1, 0]); + assert([0.0, 0.01, 0.01, 0.0].stripRight(0).length == 3); +} + +@safe pure unittest +{ + import std.algorithm.mutation; + + assert(" foobar ".stripRight!(a => a == ' ')() == " foobar"); + assert("00223.444500".stripRight!(a => a == '0')() == "00223.4445"); + assert("ùniçodêéé".stripRight!(a => a == 'é')() == "ùniçodê"); + assert([1, 1, 0, 1, 1].stripRight!(a => a == 1)() == [1, 1, 0]); + assert([0.0, 0.01, 0.10, 0.5, 0.6].stripRight!(a => a > 0.4)().length == 3); +} + +@safe unittest +{ + import std.algorithm.mutation; + + // Swapping POD (plain old data) types: + int a = 42, b = 34; + swap(a, b); + assert(a == 34 && b == 42); + + // Swapping structs with indirection: + static struct S { int x; char c; int[] y; } + S s1 = { 0, 'z', [ 1, 2 ] }; + S s2 = { 42, 'a', [ 4, 6 ] }; + swap(s1, s2); + assert(s1.x == 42); + assert(s1.c == 'a'); + assert(s1.y == [ 4, 6 ]); + + assert(s2.x == 0); + assert(s2.c == 'z'); + assert(s2.y == [ 1, 2 ]); + + // Immutables cannot be swapped: + immutable int imm1 = 1, imm2 = 2; + static assert(!__traits(compiles, swap(imm1, imm2))); + + int c = imm1 + 0; + int d = imm2 + 0; + swap(c, d); + assert(c == 2); + assert(d == 1); +} + +@safe unittest +{ + import std.algorithm.mutation; + + // Non-copyable types can still be swapped. + static struct NoCopy + { + this(this) { assert(0); } + int n; + string s; + } + NoCopy nc1, nc2; + nc1.n = 127; nc1.s = "abc"; + nc2.n = 513; nc2.s = "uvwxyz"; + + swap(nc1, nc2); + assert(nc1.n == 513 && nc1.s == "uvwxyz"); + assert(nc2.n == 127 && nc2.s == "abc"); + + swap(nc1, nc1); + swap(nc2, nc2); + assert(nc1.n == 513 && nc1.s == "uvwxyz"); + assert(nc2.n == 127 && nc2.s == "abc"); + + // Types containing non-copyable fields can also be swapped. + static struct NoCopyHolder + { + NoCopy noCopy; + } + NoCopyHolder h1, h2; + h1.noCopy.n = 31; h1.noCopy.s = "abc"; + h2.noCopy.n = 65; h2.noCopy.s = null; + + swap(h1, h2); + assert(h1.noCopy.n == 65 && h1.noCopy.s == null); + assert(h2.noCopy.n == 31 && h2.noCopy.s == "abc"); + + swap(h1, h1); + swap(h2, h2); + assert(h1.noCopy.n == 65 && h1.noCopy.s == null); + assert(h2.noCopy.n == 31 && h2.noCopy.s == "abc"); + + // Const types cannot be swapped. + const NoCopy const1, const2; + assert(const1.n == 0 && const2.n == 0); + static assert(!__traits(compiles, swap(const1, const2))); +} + +pure @safe nothrow unittest +{ + import std.algorithm.mutation; + + import std.algorithm.comparison : equal; + auto a = [1, 2, 3]; + a.swapAt(1, 2); + assert(a.equal([1, 3, 2])); +} + +@safe unittest +{ + import std.algorithm.mutation; + + import std.range : empty; + int[] a = [ 100, 101, 102, 103 ]; + int[] b = [ 0, 1, 2, 3 ]; + auto c = swapRanges(a[1 .. 3], b[2 .. 4]); + assert(c[0].empty && c[1].empty); + assert(a == [ 100, 2, 3, 103 ]); + assert(b == [ 0, 1, 101, 102 ]); +} + +nothrow @system unittest +{ + import std.algorithm.mutation; + + import core.stdc.stdlib : malloc, free; + + auto s = (cast(int*) malloc(5 * int.sizeof))[0 .. 5]; + uninitializedFill(s, 42); + assert(s == [ 42, 42, 42, 42, 42 ]); + + scope(exit) free(s.ptr); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_algorithm_searching.d b/libphobos/testsuite/libphobos.phobos/std_algorithm_searching.d new file mode 100644 index 000000000000..fd09d0abcd44 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_algorithm_searching.d @@ -0,0 +1,668 @@ +@safe unittest +{ + import std.algorithm.searching; + + assert( all!"a & 1"([1, 3, 5, 7, 9])); + assert(!all!"a & 1"([1, 2, 3, 5, 7, 9])); +} + +@safe unittest +{ + import std.algorithm.searching; + + int[3] vals = [5, 3, 18]; + assert( all(vals[])); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.ascii : isWhite; + assert( all!(any!isWhite)(["a a", "b b"])); + assert(!any!(all!isWhite)(["a a", "b b"])); +} + +@safe unittest +{ + import std.algorithm.searching; + + int[3] vals1 = [0, 0, 0]; + assert(!any(vals1[])); //none of vals1 evaluate to true + + int[3] vals2 = [2, 0, 2]; + assert( any(vals2[])); + assert(!all(vals2[])); + + int[3] vals3 = [3, 3, 3]; + assert( any(vals3[])); + assert( all(vals3[])); +} + +@safe pure unittest +{ + import std.algorithm.searching; + + auto s = "1 + (2 * (3 + 1 / 2)"; + assert(!balancedParens(s, '(', ')')); + s = "1 + (2 * (3 + 1) / 2)"; + assert(balancedParens(s, '(', ')')); + s = "1 + (2 * (3 + 1) / 2)"; + assert(!balancedParens(s, '(', ')', 0)); + s = "1 + (2 * 3 + 1) / (2 - 5)"; + assert(balancedParens(s, '(', ')', 0)); + s = "f(x) = ⌈x⌉"; + assert(balancedParens(s, '⌈', '⌉')); +} + +@safe pure nothrow unittest +{ + import std.algorithm.searching; + + auto bmFinder = boyerMooreFinder("TG"); + + string r = "TAGTGCCTGA"; + // search for the first match in the haystack r + r = bmFinder.beFound(r); + assert(r == "TGCCTGA"); + + // continue search in haystack + r = bmFinder.beFound(r[2 .. $]); + assert(r == "TGA"); +} + +@safe unittest +{ + import std.algorithm.searching; + + assert(commonPrefix("hello, world", "hello, there") == "hello, "); +} + +@safe unittest +{ + import std.algorithm.searching; + + // count elements in range + int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ]; + assert(count(a, 2) == 3); + assert(count!("a > b")(a, 2) == 5); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.uni : toLower; + // count range in range + assert(count("abcadfabf", "ab") == 2); + assert(count("ababab", "abab") == 1); + assert(count("ababab", "abx") == 0); + // fuzzy count range in range + assert(count!((a, b) => toLower(a) == toLower(b))("AbcAdFaBf", "ab") == 2); +} + +@safe unittest +{ + import std.algorithm.searching; + + // count elements in range + int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ]; + assert(count(a) == 9); + // count predicate in range + assert(count!("a > 2")(a) == 5); +} + +@safe unittest +{ + import std.algorithm.searching; + + assert(countUntil("hello world", "world") == 6); + assert(countUntil("hello world", 'r') == 8); + assert(countUntil("hello world", "programming") == -1); + assert(countUntil("日本語", "本語") == 1); + assert(countUntil("日本語", '語') == 2); + assert(countUntil("日本語", "五") == -1); + assert(countUntil("日本語", '五') == -1); + assert(countUntil([0, 7, 12, 22, 9], [12, 22]) == 2); + assert(countUntil([0, 7, 12, 22, 9], 9) == 4); + assert(countUntil!"a > b"([0, 7, 12, 22, 9], 20) == 3); + + // supports multiple needles + auto res = "...hello".countUntil("ha", "he"); + assert(res.steps == 3); + assert(res.needle == 1); + + // returns -1 if no needle was found + res = "hello".countUntil("ha", "hu"); + assert(res.steps == -1); + assert(res.needle == -1); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.ascii : isDigit; + import std.uni : isWhite; + + assert(countUntil!(isWhite)("hello world") == 5); + assert(countUntil!(isDigit)("hello world") == -1); + assert(countUntil!"a > 20"([0, 7, 12, 22, 9]) == 3); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.ascii : isAlpha; + assert("abc".endsWith!(a => a.isAlpha)); + assert("abc".endsWith!isAlpha); + + assert(!"ab1".endsWith!(a => a.isAlpha)); + + assert(!"ab1".endsWith!isAlpha); + assert(!"".endsWith!(a => a.isAlpha)); + + import std.algorithm.comparison : among; + assert("abc".endsWith!(a => a.among('c', 'd') != 0)); + assert(!"abc".endsWith!(a => a.among('a', 'b') != 0)); + + assert(endsWith("abc", "")); + assert(!endsWith("abc", "b")); + assert(endsWith("abc", "a", 'c') == 2); + assert(endsWith("abc", "c", "a") == 1); + assert(endsWith("abc", "c", "c") == 1); + assert(endsWith("abc", "bc", "c") == 2); + assert(endsWith("abc", "x", "c", "b") == 2); + assert(endsWith("abc", "x", "aa", "bc") == 3); + assert(endsWith("abc", "x", "aaa", "sab") == 0); + assert(endsWith("abc", "x", "aaa", 'c', "sab") == 3); +} + +@safe unittest +{ + import std.algorithm.searching; + + auto arr = [ 1, 2, 3, 4, 1 ]; + assert(find!("a > 2")(arr) == [ 3, 4, 1 ]); + + // with predicate alias + bool pred(int e) => e + 1 > 1.5; + assert(find!(pred)(arr) == arr); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.range.primitives; + + auto arr = [1, 2, 4, 4, 4, 4, 5, 6, 9]; + assert(arr.find(4) == [4, 4, 4, 4, 5, 6, 9]); + assert(arr.find(1) == arr); + assert(arr.find(9) == [9]); + assert(arr.find!((e, n) => e > n)(4) == [5, 6, 9]); + assert(arr.find!((e, n) => e < n)(4) == arr); + assert(arr.find(0).empty); + assert(arr.find(10).empty); + assert(arr.find(8).empty); + + assert(find("hello, world", ',') == ", world"); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.range.primitives; + import std.uni : toLower; + + string[] s = ["Hello", "world", "!"]; + assert(s.find!((e, n) => toLower(e) == n)("hello") == s); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.container : SList; + import std.range.primitives : empty; + import std.typecons : Tuple; + + assert(find("hello, world", "World").empty); + assert(find("hello, world", "wo") == "world"); + assert([1, 2, 3, 4].find(SList!int(2, 3)[]) == [2, 3, 4]); + alias C = Tuple!(int, "x", int, "y"); + auto a = [C(1,0), C(2,0), C(3,1), C(4,0)]; + assert(a.find!"a.x == b"([2, 3]) == [C(2,0), C(3,1), C(4,0)]); + assert(a[1 .. $].find!"a.x == b"([2, 3]) == [C(2,0), C(3,1), C(4,0)]); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.typecons : tuple; + int[] a = [ 1, 4, 2, 3 ]; + assert(find(a, 4) == [ 4, 2, 3 ]); + assert(find(a, [ 1, 4 ]) == [ 1, 4, 2, 3 ]); + assert(find(a, [ 1, 3 ], 4) == tuple([ 4, 2, 3 ], 2)); + // Mixed types allowed if comparable + assert(find(a, 5, [ 1.2, 3.5 ], 2.0) == tuple([ 2, 3 ], 3)); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.range.primitives : empty; + int[] a = [ -1, 0, 1, 2, 3, 4, 5 ]; + int[] b = [ 1, 2, 3 ]; + + assert(find(a, boyerMooreFinder(b)) == [ 1, 2, 3, 4, 5 ]); + assert(find(b, boyerMooreFinder(a)).empty); +} + +@safe unittest +{ + import std.algorithm.searching; + + const arr = [0, 1, 2, 3]; + assert(canFind(arr, 2)); + assert(!canFind(arr, 4)); + + // find one of several needles + assert(arr.canFind(3, 2)); + assert(arr.canFind(3, 2) == 2); // second needle found + assert(arr.canFind([1, 3], 2) == 2); + + assert(canFind(arr, [1, 2], [2, 3])); + assert(canFind(arr, [1, 2], [2, 3]) == 1); + assert(canFind(arr, [1, 7], [2, 3])); + assert(canFind(arr, [1, 7], [2, 3]) == 2); + assert(!canFind(arr, [1, 3], [2, 4])); + assert(canFind(arr, [1, 3], [2, 4]) == 0); +} + +@safe unittest +{ + import std.algorithm.searching; + + auto words = [ + "apple", + "beeswax", + "cardboard" + ]; + assert(!canFind(words, "bees")); + assert( canFind!((string elem, string needle) => elem.startsWith(needle))(words, "bees")); +} + +@safe unittest +{ + import std.algorithm.searching; + + string s1 = "aaa111aaa"; + string s2 = "aaa222aaa"; + string s3 = "aaa333aaa"; + string s4 = "aaa444aaa"; + const hay = [s1, s2, s3, s4]; + assert(hay.canFind!(e => e.canFind("111", "222"))); +} + +@safe unittest +{ + import std.algorithm.searching; + + int[] a = [ 11, 10, 10, 9, 8, 8, 7, 8, 9 ]; + auto r = findAdjacent(a); + assert(r == [ 10, 10, 9, 8, 8, 7, 8, 9 ]); + auto p = findAdjacent!("a < b")(a); + assert(p == [ 7, 8, 9 ]); + +} + +@safe unittest +{ + import std.algorithm.searching; + + int[] a = [ -1, 0, 1, 2, 3, 4, 5 ]; + int[] b = [ 3, 1, 2 ]; + assert(findAmong(a, b) == a[2 .. $]); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.range.primitives : empty; + // Needle is found; s is replaced by the substring following the first + // occurrence of the needle. + string s = "abcdef"; + assert(findSkip(s, "cd") && s == "ef"); + + // Needle is not found; s is left untouched. + s = "abcdef"; + assert(!findSkip(s, "cxd") && s == "abcdef"); + + // If the needle occurs at the end of the range, the range is left empty. + s = "abcdef"; + assert(findSkip(s, "def") && s.empty); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.ascii : isWhite; + string s = " abc"; + assert(findSkip!isWhite(s) && s == "abc"); + assert(!findSkip!isWhite(s) && s == "abc"); + + s = " "; + assert(findSkip!isWhite(s) == 2); +} + +@safe pure nothrow unittest +{ + import std.algorithm.searching; + + // findSplit returns a triplet + if (auto split = "dlang-rocks".findSplit("-")) + { + assert(split[0] == "dlang"); + assert(split[1] == "-"); + assert(split[2] == "rocks"); + } + else assert(0); + + // findSplitBefore returns 2 ranges + if (const split = [2, 3, 2, 3, 4, 1].findSplitBefore!"a > b"([2, 2])) + { + assert(split[0] == [2, 3, 2]); + // [3, 4] each greater than [2, 2] + assert(split[1] == [3, 4, 1]); + } + else assert(0); +} + +@safe pure nothrow unittest +{ + import std.algorithm.searching; + + import std.range.primitives : empty; + + auto a = "Carl Sagan Memorial Station"; + auto r = findSplit(a, "Velikovsky"); + import std.typecons : isTuple; + static assert(isTuple!(typeof(r.asTuple))); + static assert(isTuple!(typeof(r))); + assert(!r); + assert(r[0] == a); + assert(r[1].empty); + assert(r[2].empty); + r = findSplit(a, " "); + assert(r[0] == "Carl"); + assert(r[1] == " "); + assert(r[2] == "Sagan Memorial Station"); + if (const r1 = findSplitBefore(a, "Sagan")) + { + assert(r1); + assert(r1[0] == "Carl "); + assert(r1[1] == "Sagan Memorial Station"); + } + if (const r2 = findSplitAfter(a, "Sagan")) + { + assert(r2); + assert(r2[0] == "Carl Sagan"); + assert(r2[1] == " Memorial Station"); + } +} + +@safe pure nothrow unittest +{ + import std.algorithm.searching; + + import std.range : only; + assert([1, 2, 3, 4].findSplitBefore(only(3))[0] == [1, 2]); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.conv : text; + import std.typecons : tuple; + + int[] a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ]; + // Minimum is 1 and occurs 3 times + assert(a.minCount == tuple(1, 3)); + // Maximum is 4 and occurs 2 times + assert(a.maxCount == tuple(4, 2)); +} + +@safe pure unittest +{ + import std.algorithm.searching; + + import std.range : enumerate; + import std.typecons : tuple; + + assert([2, 7, 1, 3].minElement == 1); + + // allows to get the index of an element too + assert([5, 3, 7, 9].enumerate.minElement!"a.value" == tuple(1, 3)); + + // any custom accessor can be passed + assert([[0, 4], [1, 2]].minElement!"a[1]" == [1, 2]); + + // can be seeded + int[] arr; + assert(arr.minElement(1) == 1); +} + +@safe pure unittest +{ + import std.algorithm.searching; + + import std.range : enumerate; + import std.typecons : tuple; + assert([2, 1, 4, 3].maxElement == 4); + + // allows to get the index of an element too + assert([2, 1, 4, 3].enumerate.maxElement!"a.value" == tuple(2, 4)); + + // any custom accessor can be passed + assert([[0, 4], [1, 2]].maxElement!"a[1]" == [0, 4]); + + // can be seeded + int[] arr; + assert(arr.minElement(1) == 1); +} + +@safe unittest +{ + import std.algorithm.searching; + + assert(extrema([5,2,9,4,1]) == [1, 9]); +} + +@safe unittest +{ + import std.algorithm.searching; + + int[] a = [ 2, 3, 4, 1, 2, 4, 1, 1, 2 ]; + // Minimum is 1 and first occurs in position 3 + assert(a.minPos == [ 1, 2, 4, 1, 1, 2 ]); + // Maximum is 4 and first occurs in position 2 + assert(a.maxPos == [ 4, 1, 2, 4, 1, 1, 2 ]); +} + +@safe pure nothrow unittest +{ + import std.algorithm.searching; + + int[] a = [2, 3, 4, 1, 2, 4, 1, 1, 2]; + + // Minimum is 1 and first occurs in position 3 + assert(a.minIndex == 3); + // Get maximum index with minIndex + assert(a.minIndex!"a > b" == 2); + + // Range is empty, so return value is -1 + int[] b; + assert(b.minIndex == -1); + + // Works with more custom types + struct Dog { int age; } + Dog[] dogs = [Dog(10), Dog(5), Dog(15)]; + assert(dogs.minIndex!"a.age < b.age" == 1); +} + +@safe pure nothrow unittest +{ + import std.algorithm.searching; + + // Maximum is 4 and first occurs in position 2 + int[] a = [2, 3, 4, 1, 2, 4, 1, 1, 2]; + assert(a.maxIndex == 2); + + // Empty range + int[] b; + assert(b.maxIndex == -1); + + // Works with more custom types + struct Dog { int age; } + Dog[] dogs = [Dog(10), Dog(15), Dog(5)]; + assert(dogs.maxIndex!"a.age < b.age" == 1); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.algorithm.comparison : equal; + + auto s1 = "Hello world"; + assert(!skipOver(s1, "Ha")); + assert(s1 == "Hello world"); + assert(skipOver(s1, "Hell") && s1 == "o world", s1); + + string[] r1 = ["abc", "def", "hij"]; + dstring[] r2 = ["abc"d]; + assert(!skipOver!((a, b) => a.equal(b))(r1, ["def"d]), r1[0]); + assert(r1 == ["abc", "def", "hij"]); + assert(skipOver!((a, b) => a.equal(b))(r1, r2)); + assert(r1 == ["def", "hij"]); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.ascii : isWhite; + import std.range.primitives : empty; + + auto s2 = "\t\tvalue"; + auto s3 = ""; + auto s4 = "\t\t\t"; + assert(s2.skipOver!isWhite && s2 == "value"); + assert(!s3.skipOver!isWhite); + assert(s4.skipOver!isWhite && s3.empty); +} + +@safe unittest +{ + import std.algorithm.searching; + + auto s = "Hello world"; + assert(!skipOver(s, "hello", "HellO")); + assert(s == "Hello world"); + + // the range is skipped over the longest matching needle is skipped + assert(skipOver(s, "foo", "hell", "Hello ")); + assert(s == "world"); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.algorithm.comparison : equal; + + auto s1 = "Hello world"; + assert(!skipOver(s1, 'a')); + assert(s1 == "Hello world"); + assert(skipOver(s1, 'H') && s1 == "ello world"); + + string[] r = ["abc", "def", "hij"]; + dstring e = "abc"d; + assert(!skipOver!((a, b) => a.equal(b))(r, "def"d)); + assert(r == ["abc", "def", "hij"]); + assert(skipOver!((a, b) => a.equal(b))(r, e)); + assert(r == ["def", "hij"]); + + auto s2 = ""; + assert(!s2.skipOver('a')); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.ascii : isWhite; + import std.range.primitives : empty; + + alias whitespaceSkiper = skipOver!isWhite; + + auto s2 = "\t\tvalue"; + auto s3 = ""; + auto s4 = "\t\t\t"; + assert(whitespaceSkiper(s2) && s2 == "value"); + assert(!whitespaceSkiper(s2)); + assert(whitespaceSkiper(s4) && s3.empty); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.ascii : isAlpha; + + assert("abc".startsWith!(a => a.isAlpha)); + assert("abc".startsWith!isAlpha); + assert(!"1ab".startsWith!(a => a.isAlpha)); + assert(!"".startsWith!(a => a.isAlpha)); + + import std.algorithm.comparison : among; + assert("abc".startsWith!(a => a.among('a', 'b') != 0)); + assert(!"abc".startsWith!(a => a.among('b', 'c') != 0)); + + assert(startsWith("abc", "")); + assert(startsWith("abc", "a")); + assert(!startsWith("abc", "b")); + assert(startsWith("abc", 'a', "b") == 1); + assert(startsWith("abc", "b", "a") == 2); + assert(startsWith("abc", "a", "a") == 1); + assert(startsWith("abc", "ab", "a") == 2); + assert(startsWith("abc", "x", "a", "b") == 2); + assert(startsWith("abc", "x", "aa", "ab") == 3); + assert(startsWith("abc", "x", "aaa", "sab") == 0); + assert(startsWith("abc", "x", "aaa", "a", "sab") == 3); + + import std.typecons : Tuple; + alias C = Tuple!(int, "x", int, "y"); + assert(startsWith!"a.x == b"([ C(1,1), C(1,2), C(2,2) ], [1, 1])); + assert(startsWith!"a.x == b"([ C(1,1), C(2,1), C(2,2) ], [1, 1], [1, 2], [1, 3]) == 2); +} + +@safe unittest +{ + import std.algorithm.searching; + + import std.algorithm.comparison : equal; + import std.typecons : No; + int[] a = [ 1, 2, 4, 7, 7, 2, 4, 7, 3, 5]; + assert(equal(a.until(7), [1, 2, 4])); + assert(equal(a.until(7, No.openRight), [1, 2, 4, 7])); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_algorithm_setops.d b/libphobos/testsuite/libphobos.phobos/std_algorithm_setops.d new file mode 100644 index 000000000000..ecbfc5857a87 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_algorithm_setops.d @@ -0,0 +1,281 @@ +@safe unittest +{ + import std.algorithm.setops; + + import std.algorithm.searching : canFind; + import std.range; + import std.typecons : tuple; + + auto N = sequence!"n"(0); // the range of natural numbers + auto N2 = cartesianProduct(N, N); // the range of all pairs of natural numbers + + // Various arbitrary number pairs can be found in the range in finite time. + assert(canFind(N2, tuple(0, 0))); + assert(canFind(N2, tuple(123, 321))); + assert(canFind(N2, tuple(11, 35))); + assert(canFind(N2, tuple(279, 172))); +} + +@safe unittest +{ + import std.algorithm.setops; + + import std.algorithm.searching : canFind; + import std.typecons : tuple; + + auto B = [ 1, 2, 3 ]; + auto C = [ 4, 5, 6 ]; + auto BC = cartesianProduct(B, C); + + foreach (n; [[1, 4], [2, 4], [3, 4], [1, 5], [2, 5], [3, 5], [1, 6], + [2, 6], [3, 6]]) + { + assert(canFind(BC, tuple(n[0], n[1]))); + } +} + +@safe unittest +{ + import std.algorithm.setops; + + import std.algorithm.comparison : equal; + import std.typecons : tuple; + + auto A = [ 1, 2, 3 ]; + auto B = [ 'a', 'b', 'c' ]; + auto C = [ "x", "y", "z" ]; + auto ABC = cartesianProduct(A, B, C); + + assert(ABC.equal([ + tuple(1, 'a', "x"), tuple(1, 'a', "y"), tuple(1, 'a', "z"), + tuple(1, 'b', "x"), tuple(1, 'b', "y"), tuple(1, 'b', "z"), + tuple(1, 'c', "x"), tuple(1, 'c', "y"), tuple(1, 'c', "z"), + tuple(2, 'a', "x"), tuple(2, 'a', "y"), tuple(2, 'a', "z"), + tuple(2, 'b', "x"), tuple(2, 'b', "y"), tuple(2, 'b', "z"), + tuple(2, 'c', "x"), tuple(2, 'c', "y"), tuple(2, 'c', "z"), + tuple(3, 'a', "x"), tuple(3, 'a', "y"), tuple(3, 'a', "z"), + tuple(3, 'b', "x"), tuple(3, 'b', "y"), tuple(3, 'b', "z"), + tuple(3, 'c', "x"), tuple(3, 'c', "y"), tuple(3, 'c', "z") + ])); +} + +@system unittest +{ + import std.algorithm.setops; + + import std.typecons : tuple, Tuple; + + // Figure which number can be found in most arrays of the set of + // arrays below. + double[][] a = + [ + [ 1, 4, 7, 8 ], + [ 1, 7 ], + [ 1, 7, 8], + [ 4 ], + [ 7 ], + ]; + auto b = new Tuple!(double, uint)[1]; + // it will modify the input range, hence we need to create a duplicate + largestPartialIntersection(a.dup, b); + // First member is the item, second is the occurrence count + assert(b[0] == tuple(7.0, 4u)); + // 7.0 occurs in 4 out of 5 inputs, more than any other number + + // If more of the top-frequent numbers are needed, just create a larger + // tgt range + auto c = new Tuple!(double, uint)[2]; + largestPartialIntersection(a, c); + assert(c[0] == tuple(1.0, 3u)); + // 1.0 occurs in 3 inputs + + // multiset + double[][] x = + [ + [1, 1, 1, 1, 4, 7, 8], + [1, 7], + [1, 7, 8], + [4, 7], + [7] + ]; + auto y = new Tuple!(double, uint)[2]; + largestPartialIntersection(x.dup, y); + // 7.0 occurs 5 times + assert(y[0] == tuple(7.0, 5u)); + // 1.0 occurs 6 times + assert(y[1] == tuple(1.0, 6u)); +} + +@system unittest +{ + import std.algorithm.setops; + + import std.typecons : tuple, Tuple; + + // Figure which number can be found in most arrays of the set of + // arrays below, with specific per-element weights + double[][] a = + [ + [ 1, 4, 7, 8 ], + [ 1, 7 ], + [ 1, 7, 8], + [ 4 ], + [ 7 ], + ]; + auto b = new Tuple!(double, uint)[1]; + double[double] weights = [ 1:1.2, 4:2.3, 7:1.1, 8:1.1 ]; + largestPartialIntersectionWeighted(a, b, weights); + // First member is the item, second is the occurrence count + assert(b[0] == tuple(4.0, 2u)); + // 4.0 occurs 2 times -> 4.6 (2 * 2.3) + // 7.0 occurs 3 times -> 4.4 (3 * 1.1) + + // multiset + double[][] x = + [ + [ 1, 1, 1, 4, 7, 8 ], + [ 1, 7 ], + [ 1, 7, 8], + [ 4 ], + [ 7 ], + ]; + auto y = new Tuple!(double, uint)[1]; + largestPartialIntersectionWeighted(x, y, weights); + assert(y[0] == tuple(1.0, 5u)); + // 1.0 occurs 5 times -> 1.2 * 5 = 6 +} + +@system unittest +{ + import std.algorithm.setops; + + import std.algorithm.comparison : equal; + + double[][] a = + [ + [ 1, 4, 7, 8 ], + [ 1, 7 ], + [ 1, 7, 8], + [ 4 ], + [ 7 ], + ]; + auto witness = [ + 1, 1, 1, 4, 4, 7, 7, 7, 7, 8, 8 + ]; + assert(equal(multiwayMerge(a), witness)); + + double[][] b = + [ + // range with duplicates + [ 1, 1, 4, 7, 8 ], + [ 7 ], + [ 1, 7, 8], + [ 4 ], + [ 7 ], + ]; + // duplicates are propagated to the resulting range + assert(equal(multiwayMerge(b), witness)); +} + +@system unittest +{ + import std.algorithm.setops; + + import std.algorithm.comparison : equal; + + // sets + double[][] a = + [ + [ 1, 4, 7, 8 ], + [ 1, 7 ], + [ 1, 7, 8], + [ 4 ], + [ 7 ], + ]; + + auto witness = [1, 4, 7, 8]; + assert(equal(multiwayUnion(a), witness)); + + // multisets + double[][] b = + [ + [ 1, 1, 1, 4, 7, 8 ], + [ 1, 7 ], + [ 1, 7, 7, 8], + [ 4 ], + [ 7 ], + ]; + assert(equal(multiwayUnion(b), witness)); + + double[][] c = + [ + [9, 8, 8, 8, 7, 6], + [9, 8, 6], + [9, 8, 5] + ]; + auto witness2 = [9, 8, 7, 6, 5]; + assert(equal(multiwayUnion!"a > b"(c), witness2)); +} + +@safe unittest +{ + import std.algorithm.setops; + + import std.algorithm.comparison : equal; + import std.range.primitives : isForwardRange; + + //sets + int[] a = [ 1, 2, 4, 5, 7, 9 ]; + int[] b = [ 0, 1, 2, 4, 7, 8 ]; + assert(equal(setDifference(a, b), [5, 9])); + static assert(isForwardRange!(typeof(setDifference(a, b)))); + + // multisets + int[] x = [1, 1, 1, 2, 3]; + int[] y = [1, 1, 2, 4, 5]; + auto r = setDifference(x, y); + assert(equal(r, [1, 3])); + assert(setDifference(r, x).empty); +} + +@safe unittest +{ + import std.algorithm.setops; + + import std.algorithm.comparison : equal; + + // sets + int[] a = [ 1, 2, 4, 5, 7, 9 ]; + int[] b = [ 0, 1, 2, 4, 7, 8 ]; + int[] c = [ 0, 1, 4, 5, 7, 8 ]; + assert(equal(setIntersection(a, a), a)); + assert(equal(setIntersection(a, b), [1, 2, 4, 7])); + assert(equal(setIntersection(a, b, c), [1, 4, 7])); + + // multisets + int[] d = [ 1, 1, 2, 2, 7, 7 ]; + int[] e = [ 1, 1, 1, 7]; + assert(equal(setIntersection(a, d), [1, 2, 7])); + assert(equal(setIntersection(d, e), [1, 1, 7])); +} + +@safe unittest +{ + import std.algorithm.setops; + + import std.algorithm.comparison : equal; + import std.range.primitives : isForwardRange; + + // sets + int[] a = [ 1, 2, 4, 5, 7, 9 ]; + int[] b = [ 0, 1, 2, 4, 7, 8 ]; + assert(equal(setSymmetricDifference(a, b), [0, 5, 8, 9][])); + static assert(isForwardRange!(typeof(setSymmetricDifference(a, b)))); + + //mutisets + int[] c = [1, 1, 1, 1, 2, 2, 2, 4, 5, 6]; + int[] d = [1, 1, 2, 2, 2, 2, 4, 7, 9]; + assert(equal(setSymmetricDifference(c, d), setSymmetricDifference(d, c))); + assert(equal(setSymmetricDifference(c, d), [1, 1, 2, 5, 6, 7, 9])); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_algorithm_sorting.d b/libphobos/testsuite/libphobos.phobos/std_algorithm_sorting.d new file mode 100644 index 000000000000..df4bca62761a --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_algorithm_sorting.d @@ -0,0 +1,462 @@ +@safe unittest +{ + import std.algorithm.sorting; + + import std.range : assumeSorted; + int[] a = [ 1, 2, 3 ]; + int[] b = [ 4, 0, 6, 5 ]; + completeSort(assumeSorted(a), b); + assert(a == [ 0, 1, 2 ]); + assert(b == [ 3, 4, 5, 6 ]); +} + +@safe unittest +{ + import std.algorithm.sorting; + + assert([1, 1, 2].isSorted); + // strictly monotonic doesn't allow duplicates + assert(![1, 1, 2].isStrictlyMonotonic); + + int[] arr = [4, 3, 2, 1]; + assert(!isSorted(arr)); + assert(!isStrictlyMonotonic(arr)); + + assert(isSorted!"a > b"(arr)); + assert(isStrictlyMonotonic!"a > b"(arr)); + + sort(arr); + assert(isSorted(arr)); + assert(isStrictlyMonotonic(arr)); +} + +@safe unittest +{ + import std.algorithm.sorting; + + assert(ordered(42, 42, 43)); + assert(!strictlyOrdered(43, 42, 45)); + assert(ordered(42, 42, 43)); + assert(!strictlyOrdered(42, 42, 43)); + assert(!ordered(43, 42, 45)); + // Ordered lexicographically + assert(ordered("Jane", "Jim", "Joe")); + assert(strictlyOrdered("Jane", "Jim", "Joe")); + // Incidentally also ordered by length decreasing + assert(ordered!((a, b) => a.length > b.length)("Jane", "Jim", "Joe")); + // ... but not strictly so: "Jim" and "Joe" have the same length + assert(!strictlyOrdered!((a, b) => a.length > b.length)("Jane", "Jim", "Joe")); +} + +@safe unittest +{ + import std.algorithm.sorting; + + import std.algorithm.mutation : SwapStrategy; + import std.algorithm.searching : count, find; + import std.conv : text; + import std.range.primitives : empty; + + auto Arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + auto arr = Arr.dup; + static bool even(int a) { return (a & 1) == 0; } + // Partition arr such that even numbers come first + auto r = partition!(even)(arr); + // Now arr is separated in evens and odds. + // Numbers may have become shuffled due to instability + assert(r == arr[5 .. $]); + assert(count!(even)(arr[0 .. 5]) == 5); + assert(find!(even)(r).empty); + + // Can also specify the predicate as a string. + // Use 'a' as the predicate argument name + arr[] = Arr[]; + r = partition!(q{(a & 1) == 0})(arr); + assert(r == arr[5 .. $]); + + // Now for a stable partition: + arr[] = Arr[]; + r = partition!(q{(a & 1) == 0}, SwapStrategy.stable)(arr); + // Now arr is [2 4 6 8 10 1 3 5 7 9], and r points to 1 + assert(arr == [2, 4, 6, 8, 10, 1, 3, 5, 7, 9] && r == arr[5 .. $]); + + // In case the predicate needs to hold its own state, use a delegate: + arr[] = Arr[]; + int x = 3; + // Put stuff greater than 3 on the left + bool fun(int a) { return a > x; } + r = partition!(fun, SwapStrategy.semistable)(arr); + // Now arr is [4 5 6 7 8 9 10 2 3 1] and r points to 2 + assert(arr == [4, 5, 6, 7, 8, 9, 10, 2, 3, 1] && r == arr[7 .. $]); +} + +@safe nothrow unittest +{ + import std.algorithm.sorting; + + int[] a = [5, 3, 2, 6, 4, 1, 3, 7]; + size_t pivot = pivotPartition(a, a.length / 2); + import std.algorithm.searching : all; + assert(a[0 .. pivot].all!(x => x <= a[pivot])); + assert(a[pivot .. $].all!(x => x >= a[pivot])); +} + +@safe unittest +{ + import std.algorithm.sorting; + + int[] r = [ 1, 3, 5, 7, 8, 2, 4, ]; + assert(isPartitioned!"a & 1"(r)); +} + +@safe unittest +{ + import std.algorithm.sorting; + + auto a = [ 8, 3, 4, 1, 4, 7, 4 ]; + auto pieces = partition3(a, 4); + assert(pieces[0] == [ 1, 3 ]); + assert(pieces[1] == [ 4, 4, 4 ]); + assert(pieces[2] == [ 8, 7 ]); +} + +@system unittest +{ + import std.algorithm.sorting; + + immutable(int[]) arr = [ 2, 3, 1, 5, 0 ]; + // index using pointers + auto index1 = new immutable(int)*[arr.length]; + makeIndex!("a < b")(arr, index1); + assert(isSorted!("*a < *b")(index1)); + // index using offsets + auto index2 = new size_t[arr.length]; + makeIndex!("a < b")(arr, index2); + assert(isSorted! + ((size_t a, size_t b){ return arr[a] < arr[b];}) + (index2)); +} + +@safe pure nothrow unittest +{ + import std.algorithm.sorting; + + import std.algorithm.comparison : equal; + import std.range : retro; + + int[] a = [1, 3, 5]; + int[] b = [2, 3, 4]; + + assert(a.merge(b).equal([1, 2, 3, 3, 4, 5])); + assert(a.merge(b).retro.equal([5, 4, 3, 3, 2, 1])); +} + +@safe pure nothrow unittest +{ + import std.algorithm.sorting; + + import std.algorithm.comparison : equal; + import std.range : retro; + import std.traits : CommonType; + + alias S = short; + alias I = int; + alias D = double; + + S[] a = [1, 2, 3]; + I[] b = [50, 60]; + D[] c = [10, 20, 30, 40]; + + auto m = merge(a, b, c); + + static assert(is(typeof(m.front) == CommonType!(S, I, D))); + + assert(equal(m, [1, 2, 3, 10, 20, 30, 40, 50, 60])); + assert(equal(m.retro, [60, 50, 40, 30, 20, 10, 3, 2, 1])); + + m.popFront(); + assert(equal(m, [2, 3, 10, 20, 30, 40, 50, 60])); + m.popBack(); + assert(equal(m, [2, 3, 10, 20, 30, 40, 50])); + m.popFront(); + assert(equal(m, [3, 10, 20, 30, 40, 50])); + m.popBack(); + assert(equal(m, [3, 10, 20, 30, 40])); + m.popFront(); + assert(equal(m, [10, 20, 30, 40])); + m.popBack(); + assert(equal(m, [10, 20, 30])); + m.popFront(); + assert(equal(m, [20, 30])); + m.popBack(); + assert(equal(m, [20])); + m.popFront(); + assert(m.empty); +} + +@safe unittest +{ + import std.algorithm.sorting; + + import std.algorithm.mutation : SwapStrategy; + static struct Point { int x, y; } + auto pts1 = [ Point(0, 0), Point(5, 5), Point(0, 1), Point(0, 2) ]; + auto pts2 = [ Point(0, 0), Point(0, 1), Point(0, 2), Point(5, 5) ]; + multiSort!("a.x < b.x", "a.y < b.y", SwapStrategy.unstable)(pts1); + assert(pts1 == pts2); +} + +@safe pure nothrow unittest +{ + import std.algorithm.sorting; + + int[] array = [ 1, 2, 3, 4 ]; + + // sort in descending order + array.sort!("a > b"); + assert(array == [ 4, 3, 2, 1 ]); + + // sort in ascending order + array.sort(); + assert(array == [ 1, 2, 3, 4 ]); + + // sort with reusable comparator and chain + alias myComp = (x, y) => x > y; + assert(array.sort!(myComp).release == [ 4, 3, 2, 1 ]); +} + +@safe unittest +{ + import std.algorithm.sorting; + + // Showcase stable sorting + import std.algorithm.mutation : SwapStrategy; + string[] words = [ "aBc", "a", "abc", "b", "ABC", "c" ]; + sort!("toUpper(a) < toUpper(b)", SwapStrategy.stable)(words); + assert(words == [ "a", "aBc", "abc", "ABC", "b", "c" ]); +} + +@safe unittest +{ + import std.algorithm.sorting; + + // Sorting floating-point numbers in presence of NaN + double[] numbers = [-0.0, 3.0, -2.0, double.nan, 0.0, -double.nan]; + + import std.algorithm.comparison : equal; + import std.math.operations : cmp; + import std.math.traits : isIdentical; + + sort!((a, b) => cmp(a, b) < 0)(numbers); + + double[] sorted = [-double.nan, -2.0, -0.0, 0.0, 3.0, double.nan]; + assert(numbers.equal!isIdentical(sorted)); +} + +@safe pure unittest +{ + import std.algorithm.sorting; + + import std.algorithm.iteration : map; + import std.numeric : entropy; + + auto lowEnt = [ 1.0, 0, 0 ], + midEnt = [ 0.1, 0.1, 0.8 ], + highEnt = [ 0.31, 0.29, 0.4 ]; + auto arr = new double[][3]; + arr[0] = midEnt; + arr[1] = lowEnt; + arr[2] = highEnt; + + schwartzSort!(entropy, "a > b")(arr); + + assert(arr[0] == highEnt); + assert(arr[1] == midEnt); + assert(arr[2] == lowEnt); + assert(isSorted!("a > b")(map!(entropy)(arr))); +} + +@system unittest +{ + import std.algorithm.sorting; + + int[] a = [ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 ]; + partialSort(a, 5); + assert(a[0 .. 5] == [ 0, 1, 2, 3, 4 ]); +} + +@system unittest +{ + import std.algorithm.sorting; + + int[] a = [5, 7, 2, 6, 7]; + int[] b = [2, 1, 5, 6, 7, 3, 0]; + + partialSort(a, b); + assert(a == [0, 1, 2, 2, 3]); +} + +@safe unittest +{ + import std.algorithm.sorting; + + int[] v = [ 25, 7, 9, 2, 0, 5, 21 ]; + topN!"a < b"(v, 100); + assert(v == [ 25, 7, 9, 2, 0, 5, 21 ]); + auto n = 4; + topN!((a, b) => a < b)(v, n); + assert(v[n] == 9); +} + +@system unittest +{ + import std.algorithm.sorting; + + int[] a = [ 5, 7, 2, 6, 7 ]; + int[] b = [ 2, 1, 5, 6, 7, 3, 0 ]; + topN(a, b); + sort(a); + assert(a == [0, 1, 2, 2, 3]); +} + +@system unittest +{ + import std.algorithm.sorting; + + import std.typecons : Yes; + + int[] a = [ 10, 16, 2, 3, 1, 5, 0 ]; + int[] b = new int[3]; + topNCopy(a, b, Yes.sortOutput); + assert(b == [ 0, 1, 2 ]); +} + +@system unittest +{ + import std.algorithm.sorting; + + import std.typecons : Yes; + + // Construct index to top 3 elements using numerical indices: + int[] a = [ 10, 2, 7, 5, 8, 1 ]; + int[] index = new int[3]; + topNIndex(a, index, Yes.sortOutput); + assert(index == [5, 1, 3]); // because a[5]==1, a[1]==2, a[3]==5 + + // Construct index to top 3 elements using pointer indices: + int*[] ptrIndex = new int*[3]; + topNIndex(a, ptrIndex, Yes.sortOutput); + assert(ptrIndex == [ &a[5], &a[1], &a[3] ]); +} + +@safe unittest +{ + import std.algorithm.sorting; + + // Step through all permutations of a sorted array in lexicographic order + int[] a = [1,2,3]; + assert(nextPermutation(a) == true); + assert(a == [1,3,2]); + assert(nextPermutation(a) == true); + assert(a == [2,1,3]); + assert(nextPermutation(a) == true); + assert(a == [2,3,1]); + assert(nextPermutation(a) == true); + assert(a == [3,1,2]); + assert(nextPermutation(a) == true); + assert(a == [3,2,1]); + assert(nextPermutation(a) == false); + assert(a == [1,2,3]); +} + +@safe unittest +{ + import std.algorithm.sorting; + + // Step through permutations of an array containing duplicate elements: + int[] a = [1,1,2]; + assert(nextPermutation(a) == true); + assert(a == [1,2,1]); + assert(nextPermutation(a) == true); + assert(a == [2,1,1]); + assert(nextPermutation(a) == false); + assert(a == [1,1,2]); +} + +@safe unittest +{ + import std.algorithm.sorting; + + // Step through even permutations of a sorted array in lexicographic order + int[] a = [1,2,3]; + assert(nextEvenPermutation(a) == true); + assert(a == [2,3,1]); + assert(nextEvenPermutation(a) == true); + assert(a == [3,1,2]); + assert(nextEvenPermutation(a) == false); + assert(a == [1,2,3]); +} + +@safe unittest +{ + import std.algorithm.sorting; + + import std.math.algebraic : sqrt; + + // Print the 60 vertices of a uniform truncated icosahedron (soccer ball) + enum real Phi = (1.0 + sqrt(5.0)) / 2.0; // Golden ratio + real[][] seeds = [ + [0.0, 1.0, 3.0*Phi], + [1.0, 2.0+Phi, 2.0*Phi], + [Phi, 2.0, Phi^^3] + ]; + size_t n; + foreach (seed; seeds) + { + // Loop over even permutations of each seed + do + { + // Loop over all sign changes of each permutation + size_t i; + do + { + // Generate all possible sign changes + for (i=0; i < seed.length; i++) + { + if (seed[i] != 0.0) + { + seed[i] = -seed[i]; + if (seed[i] < 0.0) + break; + } + } + n++; + } while (i < seed.length); + } while (nextEvenPermutation(seed)); + } + assert(n == 60); +} + +pure @safe unittest +{ + import std.algorithm.sorting; + + auto src = [0, 1, 2, 3, 4, 5, 6]; + auto rslt = [4, 0, 6, 2, 1, 3, 5]; + + src = nthPermutation(src, 2982); + assert(src == rslt); +} + +pure @safe unittest +{ + import std.algorithm.sorting; + + auto src = [0, 1, 2, 3, 4, 5, 6]; + auto rslt = [4, 0, 6, 2, 1, 3, 5]; + + bool worked = nthPermutationImpl(src, 2982); + assert(worked); + assert(src == rslt); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_array.d b/libphobos/testsuite/libphobos.phobos/std_array.d new file mode 100644 index 000000000000..1370d0899433 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_array.d @@ -0,0 +1,560 @@ +@safe pure nothrow unittest +{ + import std.array; + + auto a = array([1, 2, 3, 4, 5][]); + assert(a == [ 1, 2, 3, 4, 5 ]); +} + +@safe pure nothrow unittest +{ + import std.array; + + import std.range.primitives : isRandomAccessRange; + import std.traits : isAutodecodableString; + + // note that if autodecoding is turned off, `array` will not transcode these. + static if (isAutodecodableString!string) + assert("Hello D".array == "Hello D"d); + else + assert("Hello D".array == "Hello D"); + + static if (isAutodecodableString!wstring) + assert("Hello D"w.array == "Hello D"d); + else + assert("Hello D"w.array == "Hello D"w); + + static assert(isRandomAccessRange!dstring == true); +} + +@safe pure unittest +{ + import std.array; + + import std.range : repeat, zip; + import std.typecons : tuple; + import std.range.primitives : autodecodeStrings; + auto a = assocArray(zip([0, 1, 2], ["a", "b", "c"])); // aka zipMap + static assert(is(typeof(a) == string[int])); + assert(a == [0:"a", 1:"b", 2:"c"]); + + auto b = assocArray([ tuple("foo", "bar"), tuple("baz", "quux") ]); + static assert(is(typeof(b) == string[string])); + assert(b == ["foo":"bar", "baz":"quux"]); + + static if (autodecodeStrings) + alias achar = dchar; + else + alias achar = immutable(char); + auto c = assocArray("ABCD", true.repeat); + static assert(is(typeof(c) == bool[achar])); + bool[achar] expected = ['D':true, 'A':true, 'B':true, 'C':true]; + assert(c == expected); +} + +@safe pure nothrow unittest +{ + import std.array; + + import std.algorithm.sorting : sort; + import std.typecons : tuple, Tuple; + + auto aa = ["a": 1, "b": 2, "c": 3]; + Tuple!(string, int)[] pairs; + + // Iteration over key/value pairs. + foreach (pair; aa.byPair) + { + if (pair.key == "b") + pairs ~= tuple("B", pair.value); + else + pairs ~= pair; + } + + // Iteration order is implementation-dependent, so we should sort it to get + // a fixed order. + pairs.sort(); + assert(pairs == [ + tuple("B", 2), + tuple("a", 1), + tuple("c", 3) + ]); +} + +@system nothrow pure unittest +{ + import std.array; + + double[] arr = uninitializedArray!(double[])(100); + assert(arr.length == 100); + + double[][] matrix = uninitializedArray!(double[][])(42, 31); + assert(matrix.length == 42); + assert(matrix[0].length == 31); + + char*[] ptrs = uninitializedArray!(char*[])(100); + assert(ptrs.length == 100); +} + +@safe pure nothrow unittest +{ + import std.array; + + import std.algorithm.comparison : equal; + import std.range : repeat; + + auto arr = minimallyInitializedArray!(int[])(42); + assert(arr.length == 42); + + // Elements aren't necessarily initialized to 0, so don't do this: + // assert(arr.equal(0.repeat(42))); + // If that is needed, initialize the array normally instead: + auto arr2 = new int[42]; + assert(arr2.equal(0.repeat(42))); +} + +@safe pure nothrow unittest +{ + import std.array; + + int[] a = [ 10, 11, 12, 13, 14 ]; + int[] b = a[1 .. 3]; + assert(overlap(a, b) == [ 11, 12 ]); + b = b.dup; + // overlap disappears even though the content is the same + assert(overlap(a, b).empty); + + static test()() @nogc + { + auto a = "It's three o'clock"d; + auto b = a[5 .. 10]; + return b.overlap(a); + } + + //works at compile-time + static assert(test == "three"d); +} + +@safe pure nothrow unittest +{ + import std.array; + + import std.meta : AliasSeq; + + // can be used as an alternative implementation of overlap that returns + // `true` or `false` instead of a slice of the overlap + bool isSliceOf(T)(const scope T[] part, const scope T[] whole) + { + return part.overlap(whole) is part; + } + + auto x = [1, 2, 3, 4, 5]; + + assert(isSliceOf(x[3..$], x)); + assert(isSliceOf(x[], x)); + assert(!isSliceOf(x, x[3..$])); + assert(!isSliceOf([7, 8], x)); + assert(isSliceOf(null, x)); + + // null is a slice of itself + assert(isSliceOf(null, null)); + + foreach (T; AliasSeq!(int[], const(int)[], immutable(int)[], const int[], immutable int[])) + { + T a = [1, 2, 3, 4, 5]; + T b = a; + T c = a[1 .. $]; + T d = a[0 .. 1]; + T e = null; + + assert(isSliceOf(a, a)); + assert(isSliceOf(b, a)); + assert(isSliceOf(a, b)); + + assert(isSliceOf(c, a)); + assert(isSliceOf(c, b)); + assert(!isSliceOf(a, c)); + assert(!isSliceOf(b, c)); + + assert(isSliceOf(d, a)); + assert(isSliceOf(d, b)); + assert(!isSliceOf(a, d)); + assert(!isSliceOf(b, d)); + + assert(isSliceOf(e, a)); + assert(isSliceOf(e, b)); + assert(isSliceOf(e, c)); + assert(isSliceOf(e, d)); + + //verifies R-value compatibilty + assert(!isSliceOf(a[$ .. $], a)); + assert(isSliceOf(a[0 .. 0], a)); + assert(isSliceOf(a, a[0.. $])); + assert(isSliceOf(a[0 .. $], a)); + } +} + +@safe pure unittest +{ + import std.array; + + int[] a = [ 1, 2, 3, 4 ]; + a.insertInPlace(2, [ 1, 2 ]); + assert(a == [ 1, 2, 1, 2, 3, 4 ]); + a.insertInPlace(3, 10u, 11); + assert(a == [ 1, 2, 1, 10, 11, 2, 3, 4]); + + union U + { + float a = 3.0; + int b; + } + + U u1 = { b : 3 }; + U u2 = { b : 4 }; + U u3 = { b : 5 }; + U[] unionArr = [u2, u3]; + unionArr.insertInPlace(2, [u1]); + assert(unionArr == [u2, u3, u1]); + unionArr.insertInPlace(0, [u3, u2]); + assert(unionArr == [u3, u2, u2, u3, u1]); + + static class C + { + int a; + float b; + + this(int a, float b) { this.a = a; this.b = b; } + } + + C c1 = new C(42, 1.0); + C c2 = new C(0, 0.0); + C c3 = new C(int.max, float.init); + + C[] classArr = [c1, c2, c3]; + insertInPlace(classArr, 3, [c2, c3]); + C[5] classArr1 = classArr; + assert(classArr1 == [c1, c2, c3, c2, c3]); + insertInPlace(classArr, 0, c3, c1); + C[7] classArr2 = classArr; + assert(classArr2 == [c3, c1, c1, c2, c3, c2, c3]); +} + +@safe pure nothrow unittest +{ + import std.array; + + auto a = [1, 2, 3, 4, 5]; + auto b = a[0 .. 2]; + + assert(a.sameHead(b)); +} + +@safe pure nothrow unittest +{ + import std.array; + + auto a = [1, 2, 3, 4, 5]; + auto b = a[3..$]; + + assert(a.sameTail(b)); +} + +@safe unittest +{ + import std.array; + + auto a = "abc"; + auto s = replicate(a, 3); + + assert(s == "abcabcabc"); + + auto b = [1, 2, 3]; + auto c = replicate(b, 3); + + assert(c == [1, 2, 3, 1, 2, 3, 1, 2, 3]); + + auto d = replicate(b, 0); + + assert(d == []); +} + +@safe unittest +{ + import std.array; + + import std.uni : isWhite; + assert("Learning,D,is,fun".split(",") == ["Learning", "D", "is", "fun"]); + assert("Learning D is fun".split!isWhite == ["Learning", "D", "is", "fun"]); + assert("Learning D is fun".split(" D ") == ["Learning", "is fun"]); +} + +@safe unittest +{ + import std.array; + + string str = "Hello World!"; + assert(str.split == ["Hello", "World!"]); + + string str2 = "Hello\t\tWorld\t!"; + assert(str2.split == ["Hello", "World", "!"]); +} + +@safe unittest +{ + import std.array; + + assert(split("hello world") == ["hello","world"]); + assert(split("192.168.0.1", ".") == ["192", "168", "0", "1"]); + + auto a = split([1, 2, 3, 4, 5, 1, 2, 3, 4, 5], [2, 3]); + assert(a == [[1], [4, 5, 1], [4, 5]]); +} + +@safe pure nothrow unittest +{ + import std.array; + + assert(join(["hello", "silly", "world"], " ") == "hello silly world"); + assert(join(["hello", "silly", "world"]) == "hellosillyworld"); + + assert(join([[1, 2, 3], [4, 5]], [72, 73]) == [1, 2, 3, 72, 73, 4, 5]); + assert(join([[1, 2, 3], [4, 5]]) == [1, 2, 3, 4, 5]); + + const string[] arr = ["apple", "banana"]; + assert(arr.join(",") == "apple,banana"); + assert(arr.join() == "applebanana"); +} + +@safe unittest +{ + import std.array; + + assert("Hello Wörld".replace("o Wö", "o Wo") == "Hello World"); + assert("Hello Wörld".replace("l", "h") == "Hehho Wörhd"); +} + +@safe unittest +{ + import std.array; + + size_t changed = 0; + assert("Hello Wörld".replace("o Wö", "o Wo", changed) == "Hello World"); + assert(changed == 1); + + changed = 0; + assert("Hello Wörld".replace("l", "h", changed) == "Hehho Wörhd"); + import std.stdio : writeln; + writeln(changed); + assert(changed == 3); +} + +@safe unittest +{ + import std.array; + + auto arr = [1, 2, 3, 4, 5]; + auto from = [2, 3]; + auto to = [4, 6]; + auto sink = appender!(int[])(); + + replaceInto(sink, arr, from, to); + + assert(sink.data == [1, 4, 6, 4, 5]); +} + +@safe unittest +{ + import std.array; + + auto arr = [1, 2, 3, 4, 5]; + auto from = [2, 3]; + auto to = [4, 6]; + auto sink = appender!(int[])(); + + size_t changed = 0; + replaceInto(sink, arr, from, to, changed); + + assert(sink.data == [1, 4, 6, 4, 5]); + assert(changed == 1); +} + +@safe unittest +{ + import std.array; + + auto a = [ 1, 2, 3, 4 ]; + auto b = a.replace(1, 3, [ 9, 9, 9 ]); + assert(a == [ 1, 2, 3, 4 ]); + assert(b == [ 1, 9, 9, 9, 4 ]); +} + +@safe unittest +{ + import std.array; + + int[] a = [1, 4, 5]; + replaceInPlace(a, 1u, 2u, [2, 3, 4]); + assert(a == [1, 2, 3, 4, 5]); + replaceInPlace(a, 1u, 2u, cast(int[])[]); + assert(a == [1, 3, 4, 5]); + replaceInPlace(a, 1u, 3u, a[2 .. 4]); + assert(a == [1, 4, 5, 5]); +} + +@safe unittest +{ + import std.array; + + auto a = [1, 2, 2, 3, 4, 5]; + auto b = a.replaceFirst([2], [1337]); + assert(b == [1, 1337, 2, 3, 4, 5]); + + auto s = "This is a foo foo list"; + auto r = s.replaceFirst("foo", "silly"); + assert(r == "This is a silly foo list"); +} + +@safe unittest +{ + import std.array; + + auto a = [1, 2, 2, 3, 4, 5]; + auto b = a.replaceLast([2], [1337]); + assert(b == [1, 2, 1337, 3, 4, 5]); + + auto s = "This is a foo foo list"; + auto r = s.replaceLast("foo", "silly"); + assert(r == "This is a foo silly list", r); +} + +@safe unittest +{ + import std.array; + + auto a = [1, 2, 3, 4, 5]; + auto b = replaceSlice(a, a[1 .. 4], [0, 0, 0]); + + assert(b == [1, 0, 0, 0, 5]); +} + +@safe pure nothrow unittest +{ + import std.array; + + auto app = appender!string(); + string b = "abcdefg"; + foreach (char c; b) + app.put(c); + assert(app[] == "abcdefg"); + + int[] a = [ 1, 2 ]; + auto app2 = appender(a); + app2.put(3); + assert(app2.length == 3); + app2.put([ 4, 5, 6 ]); + assert(app2[] == [ 1, 2, 3, 4, 5, 6 ]); +} + +@safe pure nothrow unittest +{ + import std.array; + + int[] a = [1, 2]; + auto app2 = appender(&a); + assert(app2[] == [1, 2]); + assert(a == [1, 2]); + app2 ~= 3; + assert(app2.length == 3); + app2 ~= [4, 5, 6]; + assert(app2[] == [1, 2, 3, 4, 5, 6]); + assert(a == [1, 2, 3, 4, 5, 6]); + + app2.reserve(5); + assert(app2.capacity >= 5); +} + +@safe pure nothrow unittest +{ + import std.array; + + auto w = appender!string; + // pre-allocate space for at least 10 elements (this avoids costly reallocations) + w.reserve(10); + assert(w.capacity >= 10); + + w.put('a'); // single elements + w.put("bc"); // multiple elements + + // use the append syntax + w ~= 'd'; + w ~= "ef"; + + assert(w[] == "abcdef"); +} + +@safe pure nothrow unittest +{ + import std.array; + + int[] a = [1, 2]; + auto app2 = appender(&a); + assert(app2[] == [1, 2]); + assert(a == [1, 2]); + app2 ~= 3; + app2 ~= [4, 5, 6]; + assert(app2[] == [1, 2, 3, 4, 5, 6]); + assert(a == [1, 2, 3, 4, 5, 6]); + + app2.reserve(5); + assert(app2.capacity >= 5); +} + +nothrow pure @safe @nogc unittest +{ + import std.array; + + auto a = [0, 1].staticArray; + static assert(is(typeof(a) == int[2])); + assert(a == [0, 1]); +} + +nothrow pure @safe @nogc unittest +{ + import std.array; + + auto b = [0, 1].staticArray!long; + static assert(is(typeof(b) == long[2])); + assert(b == [0, 1]); +} + +nothrow pure @safe @nogc unittest +{ + import std.array; + + import std.range : iota; + + auto input = 3.iota; + auto a = input.staticArray!2; + static assert(is(typeof(a) == int[2])); + assert(a == [0, 1]); + auto b = input.staticArray!(long[4]); + static assert(is(typeof(b) == long[4])); + assert(b == [0, 1, 2, 0]); +} + +nothrow pure @safe @nogc unittest +{ + import std.array; + + import std.range : iota; + + enum a = staticArray!(2.iota); + static assert(is(typeof(a) == int[2])); + assert(a == [0, 1]); + + enum b = staticArray!(long, 2.iota); + static assert(is(typeof(b) == long[2])); + assert(b == [0, 1]); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_ascii.d b/libphobos/testsuite/libphobos.phobos/std_ascii.d new file mode 100644 index 000000000000..dcdc5fd28c48 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_ascii.d @@ -0,0 +1,262 @@ +@safe unittest +{ + import std.ascii; + + import std.conv : to; + + assert(42.to!string(16, LetterCase.upper) == "2A"); + assert(42.to!string(16, LetterCase.lower) == "2a"); +} + +@safe unittest +{ + import std.ascii; + + import std.digest.hmac : hmac; + import std.digest : toHexString; + import std.digest.sha : SHA1; + import std.string : representation; + + const sha1HMAC = "A very long phrase".representation + .hmac!SHA1("secret".representation) + .toHexString!(LetterCase.lower); + assert(sha1HMAC == "49f2073c7bf58577e8c9ae59fe8cfd37c9ab94e5"); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + import std.algorithm.comparison, std.algorithm.searching, std.range, std.traits; + + // Because all ASCII characters fit in char, so do these + static assert(ControlChar.ack.sizeof == 1); + + // All control characters except del are in row starting from 0 + static assert(EnumMembers!ControlChar.only.until(ControlChar.del).equal(iota(32))); + + static assert(ControlChar.nul == '\0'); + static assert(ControlChar.bel == '\a'); + static assert(ControlChar.bs == '\b'); + static assert(ControlChar.ff == '\f'); + static assert(ControlChar.lf == '\n'); + static assert(ControlChar.cr == '\r'); + static assert(ControlChar.tab == '\t'); + static assert(ControlChar.vt == '\v'); +} + +@safe pure nothrow unittest +{ + import std.ascii; + + import std.conv; + //Control character table can be used in place of hexcodes. + with (ControlChar) assert(text("Phobos", us, "Deimos", us, "Tango", rs) == "Phobos\x1FDeimos\x1FTango\x1E"); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isAlphaNum('A')); + assert( isAlphaNum('1')); + assert(!isAlphaNum('#')); + + // N.B.: does not return true for non-ASCII Unicode alphanumerics: + assert(!isAlphaNum('á')); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isAlpha('A')); + assert(!isAlpha('1')); + assert(!isAlpha('#')); + + // N.B.: does not return true for non-ASCII Unicode alphabetic characters: + assert(!isAlpha('á')); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isLower('a')); + assert(!isLower('A')); + assert(!isLower('#')); + + // N.B.: does not return true for non-ASCII Unicode lowercase letters + assert(!isLower('á')); + assert(!isLower('Ã')); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isUpper('A')); + assert(!isUpper('a')); + assert(!isUpper('#')); + + // N.B.: does not return true for non-ASCII Unicode uppercase letters + assert(!isUpper('á')); + assert(!isUpper('Ã')); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isDigit('3')); + assert( isDigit('8')); + assert(!isDigit('B')); + assert(!isDigit('#')); + + // N.B.: does not return true for non-ASCII Unicode numbers + assert(!isDigit('ï¼')); // full-width digit zero (U+FF10) + assert(!isDigit('ï¼”')); // full-width digit four (U+FF14) +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isOctalDigit('0')); + assert( isOctalDigit('7')); + assert(!isOctalDigit('8')); + assert(!isOctalDigit('A')); + assert(!isOctalDigit('#')); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isHexDigit('0')); + assert( isHexDigit('A')); + assert( isHexDigit('f')); // lowercase hex digits are accepted + assert(!isHexDigit('g')); + assert(!isHexDigit('G')); + assert(!isHexDigit('#')); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isWhite(' ')); + assert( isWhite('\t')); + assert( isWhite('\n')); + assert(!isWhite('1')); + assert(!isWhite('a')); + assert(!isWhite('#')); + + // N.B.: Does not return true for non-ASCII Unicode whitespace characters. + static import std.uni; + assert(std.uni.isWhite('\u00A0')); + assert(!isWhite('\u00A0')); // std.ascii.isWhite +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isControl('\0')); + assert( isControl('\022')); + assert( isControl('\n')); // newline is both whitespace and control + assert(!isControl(' ')); + assert(!isControl('1')); + assert(!isControl('a')); + assert(!isControl('#')); + + // N.B.: non-ASCII Unicode control characters are not recognized: + assert(!isControl('\u0080')); + assert(!isControl('\u2028')); + assert(!isControl('\u2029')); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isPunctuation('.')); + assert( isPunctuation(',')); + assert( isPunctuation(':')); + assert( isPunctuation('!')); + assert( isPunctuation('#')); + assert( isPunctuation('~')); + assert( isPunctuation('+')); + assert( isPunctuation('_')); + + assert(!isPunctuation('1')); + assert(!isPunctuation('a')); + assert(!isPunctuation(' ')); + assert(!isPunctuation('\n')); + assert(!isPunctuation('\0')); + + // N.B.: Non-ASCII Unicode punctuation characters are not recognized. + assert(!isPunctuation('\u2012')); // (U+2012 = en-dash) +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isGraphical('1')); + assert( isGraphical('a')); + assert( isGraphical('#')); + assert(!isGraphical(' ')); // whitespace is not graphical + assert(!isGraphical('\n')); + assert(!isGraphical('\0')); + + // N.B.: Unicode graphical characters are not regarded as such. + assert(!isGraphical('á')); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isPrintable(' ')); // whitespace is printable + assert( isPrintable('1')); + assert( isPrintable('a')); + assert( isPrintable('#')); + assert(!isPrintable('\0')); // control characters are not printable + + // N.B.: Printable non-ASCII Unicode characters are not recognized. + assert(!isPrintable('á')); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert( isASCII('a')); + assert(!isASCII('á')); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert(toLower('a') == 'a'); + assert(toLower('A') == 'a'); + assert(toLower('#') == '#'); + + // N.B.: Non-ASCII Unicode uppercase letters are not converted. + assert(toLower('Ã') == 'Ã'); +} + +@safe pure nothrow @nogc unittest +{ + import std.ascii; + + assert(toUpper('a') == 'A'); + assert(toUpper('A') == 'A'); + assert(toUpper('#') == '#'); + + // N.B.: Non-ASCII Unicode lowercase letters are not converted. + assert(toUpper('á') == 'á'); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_base64.d b/libphobos/testsuite/libphobos.phobos/std_base64.d new file mode 100644 index 000000000000..3a49eeaacaaa --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_base64.d @@ -0,0 +1,180 @@ +pure @safe unittest +{ + import std.base64; + + ubyte[] data = [0x83, 0xd7, 0x30, 0x7a, 0x01, 0x3f]; + assert(Base64.encode(data) == "g9cwegE/"); + assert(Base64.decode("g9cwegE/") == data); +} + +pure @safe unittest +{ + import std.base64; + + ubyte[] data = [0x83, 0xd7, 0x30, 0x7a, 0x01, 0x3f]; + assert(Base64URL.encode(data) == "g9cwegE_"); + assert(Base64URL.decode("g9cwegE_") == data); +} + +pure @safe unittest +{ + import std.base64; + + ubyte[] data = [0x83, 0xd7, 0x30, 0x7b, 0xef]; + assert(Base64URLNoPadding.encode(data) == "g9cwe-8"); + assert(Base64URLNoPadding.decode("g9cwe-8") == data); +} + +@safe unittest +{ + import std.base64; + + ubyte[] data = [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]; + + // Allocate a buffer large enough to hold the encoded string. + auto buf = new char[Base64.encodeLength(data.length)]; + + Base64.encode(data, buf); + assert(buf == "Gis8TV1u"); + +} + +@nogc nothrow @safe unittest +{ + import std.base64; + + ubyte[6] data = [0x83, 0xd7, 0x30, 0x7a, 0x01, 0x3f]; + char[32] buffer; // much bigger than necessary + + // Just to be sure... + auto encodedLength = Base64.encodeLength(data.length); + assert(buffer.length >= encodedLength); + + // encode() returns a slice to the provided buffer. + auto encoded = Base64.encode(data[], buffer[]); + assert(encoded is buffer[0 .. encodedLength]); + assert(encoded == "g9cwegE/"); + +} + +@safe pure nothrow unittest +{ + import std.base64; + + import std.array : appender; + + auto output = appender!string(); + ubyte[] data = [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]; + + // This overload of encode() returns the number of calls to the output + // range's put method. + assert(Base64.encode(data, output) == 8); + assert(output.data == "Gis8TV1u"); + +} + +@safe unittest +{ + import std.base64; + + ubyte[] data = [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]; + assert(Base64.encode(data) == "Gis8TV1u"); + +} + +@safe unittest +{ + import std.base64; + + auto encoded = "Gis8TV1u"; + + // Allocate a sufficiently large buffer to hold to decoded result. + auto buffer = new ubyte[Base64.decodeLength(encoded.length)]; + + Base64.decode(encoded, buffer); + assert(buffer == [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]); + +} + +@safe unittest +{ + import std.base64; + + auto encoded = "Gis8TV1u"; + ubyte[32] buffer; // much bigger than necessary + + // Just to be sure... + auto decodedLength = Base64.decodeLength(encoded.length); + assert(buffer.length >= decodedLength); + + // decode() returns a slice of the given buffer. + auto decoded = Base64.decode(encoded, buffer[]); + assert(decoded is buffer[0 .. decodedLength]); + assert(decoded == [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]); + +} + +@system unittest +{ + import std.base64; + + struct OutputRange + { + ubyte[] result; + void put(ubyte b) { result ~= b; } + } + OutputRange output; + + // This overload of decode() returns the number of calls to put(). + assert(Base64.decode("Gis8TV1u", output) == 6); + assert(output.result == [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]); + +} + +@safe unittest +{ + import std.base64; + + auto data = "Gis8TV1u"; + assert(Base64.decode(data) == [0x1a, 0x2b, 0x3c, 0x4d, 0x5d, 0x6e]); + +} + +@safe pure unittest +{ + import std.base64; + + import std.algorithm.comparison : equal; + string encoded = + "VGhvdSBzaGFsdCBuZXZlciBjb250aW51ZSBhZnRlciBhc3NlcnRpbmcgbnVsbA=="; + + assert(Base64.decoder(encoded) + .equal("Thou shalt never continue after asserting null")); + +} + +@safe unittest +{ + import std.base64; + + import std.string : representation; + + // pre-defined: alias Base64 = Base64Impl!('+', '/'); + ubyte[] emptyArr; + assert(Base64.encode(emptyArr) == ""); + assert(Base64.encode("f".representation) == "Zg=="); + assert(Base64.encode("foo".representation) == "Zm9v"); + + alias Base64Re = Base64Impl!('!', '=', Base64.NoPadding); + assert(Base64Re.encode("f".representation) == "Zg"); + assert(Base64Re.encode("foo".representation) == "Zm9v"); +} + +@safe unittest +{ + import std.base64; + + import std.exception : assertThrown; + assertThrown!Base64Exception(Base64.decode("ab|c")); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_bigint.d b/libphobos/testsuite/libphobos.phobos/std_bigint.d new file mode 100644 index 000000000000..627d15c04698 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_bigint.d @@ -0,0 +1,465 @@ +pure @safe unittest +{ + import std.bigint; + + ubyte[] magnitude = [1, 2, 3, 4, 5, 6]; + auto b1 = BigInt(false, magnitude); + assert(cast(long) b1 == 0x01_02_03_04_05_06L); + auto b2 = BigInt(true, magnitude); + assert(cast(long) b2 == -0x01_02_03_04_05_06L); + +} + +@safe unittest +{ + import std.bigint; + + ulong data = 1_000_000_000_000; + auto bigData = BigInt(data); + assert(bigData == BigInt("1_000_000_000_000")); + +} + +@safe unittest +{ + import std.bigint; + + const(BigInt) b1 = BigInt("1_234_567_890"); + BigInt b2 = BigInt(b1); + assert(b2 == BigInt("1_234_567_890")); + +} + +@safe unittest +{ + import std.bigint; + + auto b = BigInt("123"); + b = 456; + assert(b == BigInt("456")); + +} + +@safe unittest +{ + import std.bigint; + + auto b1 = BigInt("123"); + auto b2 = BigInt("456"); + b2 = b1; + assert(b2 == BigInt("123")); + +} + +@safe unittest +{ + import std.bigint; + + auto b = BigInt("1_000_000_000"); + + b += 12345; + assert(b == BigInt("1_000_012_345")); + + b /= 5; + assert(b == BigInt("200_002_469")); + +} + +@safe unittest +{ + import std.bigint; + + auto x = BigInt("123"); + auto y = BigInt("321"); + x += y; + assert(x == BigInt("444")); + +} + +@safe unittest +{ + import std.bigint; + + auto x = BigInt("123"); + auto y = BigInt("456"); + BigInt z = x * y; + assert(z == BigInt("56088")); + +} + +@safe unittest +{ + import std.bigint; + + auto x = BigInt("123"); + x *= 300; + assert(x == BigInt("36900")); + +} + +@safe unittest +{ + import std.bigint; + + auto x = BigInt("1_000_000_500"); + long l = 1_000_000L; + ulong ul = 2_000_000UL; + int i = 500_000; + short s = 30_000; + + assert(is(typeof(x % l) == long) && x % l == 500L); + assert(is(typeof(x % ul) == BigInt) && x % ul == BigInt(500)); + assert(is(typeof(x % i) == int) && x % i == 500); + assert(is(typeof(x % s) == int) && x % s == 10500); + +} + +@safe unittest +{ + import std.bigint; + + auto x = BigInt("100"); + BigInt y = 123 + x; + assert(y == BigInt("223")); + + BigInt z = 123 - x; + assert(z == BigInt("23")); + + // Dividing a built-in integer type by BigInt always results in + // something that fits in a built-in type, so the built-in type is + // returned, not BigInt. + assert(is(typeof(1000 / x) == int)); + assert(1000 / x == 10); + +} + +@safe unittest +{ + import std.bigint; + + auto x = BigInt("1234"); + assert(-x == BigInt("-1234")); + + ++x; + assert(x == BigInt("1235")); + +} + +@safe unittest +{ + import std.bigint; + + // Note that when comparing a BigInt to a float or double the + // full precision of the BigInt is always considered, unlike + // when comparing an int to a float or a long to a double. + assert(BigInt(123456789) != cast(float) 123456789); + +} + +@safe unittest +{ + import std.bigint; + + // Non-zero values are regarded as true + auto x = BigInt("1"); + auto y = BigInt("10"); + assert(x); + assert(y); + + // Zero value is regarded as false + auto z = BigInt("0"); + assert(!z); + +} + +@safe unittest +{ + import std.bigint; + + import std.conv : to, ConvOverflowException; + import std.exception : assertThrown; + + assert(BigInt("0").to!int == 0); + + assert(BigInt("0").to!ubyte == 0); + assert(BigInt("255").to!ubyte == 255); + assertThrown!ConvOverflowException(BigInt("256").to!ubyte); + assertThrown!ConvOverflowException(BigInt("-1").to!ubyte); + +} + +@system unittest +{ + import std.bigint; + + assert(cast(float) BigInt("35540592535949172786332045140593475584") + == 35540592535949172786332045140593475584.0f); + assert(cast(double) BigInt("35540601499647381470685035515422441472") + == 35540601499647381470685035515422441472.0); + assert(cast(real) BigInt("35540601499647381470685035515422441472") + == 35540601499647381470685035515422441472.0L); + + assert(cast(float) BigInt("-0x1345_6780_0000_0000_0000_0000_0000") == -0x1.3456_78p+108f ); + assert(cast(double) BigInt("-0x1345_678a_bcde_f000_0000_0000_0000") == -0x1.3456_78ab_cdefp+108 ); + assert(cast(real) BigInt("-0x1345_678a_bcde_f000_0000_0000_0000") == -0x1.3456_78ab_cdefp+108L); + +} + +@system unittest +{ + import std.bigint; + + // BigInts whose values cannot be exactly represented as float/double/real + // are rounded when cast to float/double/real. When cast to float or + // double or 64-bit real the rounding is strictly defined. When cast + // to extended-precision real the rounding rules vary by environment. + + // BigInts that fall somewhere between two non-infinite floats/doubles + // are rounded to the closer value when cast to float/double. + assert(cast(float) BigInt(0x1aaa_aae7) == 0x1.aaa_aaep+28f); + assert(cast(float) BigInt(0x1aaa_aaff) == 0x1.aaa_ab0p+28f); + assert(cast(float) BigInt(-0x1aaa_aae7) == -0x1.aaaaaep+28f); + assert(cast(float) BigInt(-0x1aaa_aaff) == -0x1.aaaab0p+28f); + + assert(cast(double) BigInt(0x1aaa_aaaa_aaaa_aa77) == 0x1.aaa_aaaa_aaaa_aa00p+60); + assert(cast(double) BigInt(0x1aaa_aaaa_aaaa_aaff) == 0x1.aaa_aaaa_aaaa_ab00p+60); + assert(cast(double) BigInt(-0x1aaa_aaaa_aaaa_aa77) == -0x1.aaa_aaaa_aaaa_aa00p+60); + assert(cast(double) BigInt(-0x1aaa_aaaa_aaaa_aaff) == -0x1.aaa_aaaa_aaaa_ab00p+60); + + // BigInts that fall exactly between two non-infinite floats/doubles + // are rounded away from zero when cast to float/double. (Note that + // in most environments this is NOT the same rounding rule rule used + // when casting int/long to float/double.) + assert(cast(float) BigInt(0x1aaa_aaf0) == 0x1.aaa_ab0p+28f); + assert(cast(float) BigInt(-0x1aaa_aaf0) == -0x1.aaaab0p+28f); + + assert(cast(double) BigInt(0x1aaa_aaaa_aaaa_aa80) == 0x1.aaa_aaaa_aaaa_ab00p+60); + assert(cast(double) BigInt(-0x1aaa_aaaa_aaaa_aa80) == -0x1.aaa_aaaa_aaaa_ab00p+60); + + // BigInts that are bounded on one side by the largest positive or + // most negative finite float/double and on the other side by infinity + // or -infinity are rounded as if in place of infinity was the value + // `2^^(T.max_exp)` when cast to float/double. + assert(cast(float) BigInt("999_999_999_999_999_999_999_999_999_999_999_999_999") == float.infinity); + assert(cast(float) BigInt("-999_999_999_999_999_999_999_999_999_999_999_999_999") == -float.infinity); + + assert(cast(double) BigInt("999_999_999_999_999_999_999_999_999_999_999_999_999") < double.infinity); + assert(cast(real) BigInt("999_999_999_999_999_999_999_999_999_999_999_999_999") < real.infinity); + +} + +@safe unittest +{ + import std.bigint; + + const(BigInt) x = BigInt("123"); + BigInt y = cast() x; // cast away const + assert(y == x); + +} + +@safe unittest +{ + import std.bigint; + + auto x = BigInt("100"); + auto y = BigInt("10"); + int z = 50; + const int w = 200; + + assert(y < x); + assert(x > z); + assert(z > y); + assert(x < w); + +} + +@safe unittest +{ + import std.bigint; + + auto x = BigInt("0x1abc_de80_0000_0000_0000_0000_0000_0000"); + BigInt y = x - 1; + BigInt z = x + 1; + + double d = 0x1.abcde8p124; + assert(y < d); + assert(z > d); + assert(x >= d && x <= d); + + // Note that when comparing a BigInt to a float or double the + // full precision of the BigInt is always considered, unlike + // when comparing an int to a float or a long to a double. + assert(BigInt(123456789) < cast(float) 123456789); + +} + +@safe unittest +{ + import std.bigint; + + auto b = BigInt("12345"); + long l = b.toLong(); + assert(l == 12345); + +} + +@safe unittest +{ + import std.bigint; + + auto big = BigInt("5_000_000"); + auto i = big.toInt(); + assert(i == 5_000_000); + + // Numbers that are too big to fit into an int will be clamped to int.max. + auto tooBig = BigInt("5_000_000_000"); + i = tooBig.toInt(); + assert(i == int.max); + +} + +@safe unittest +{ + import std.bigint; + + import std.format : format; + + auto x = BigInt("1_000_000"); + x *= 12345; + + assert(format("%d", x) == "12345000000"); + assert(format("%x", x) == "2_dfd1c040"); + assert(format("%X", x) == "2_DFD1C040"); + assert(format("%o", x) == "133764340100"); + +} + +@safe pure unittest +{ + import std.bigint; + + string[BigInt] aa; + aa[BigInt(123)] = "abc"; + aa[BigInt(456)] = "def"; + + assert(aa[BigInt(123)] == "abc"); + assert(aa[BigInt(456)] == "def"); + +} + +@safe pure unittest +{ + import std.bigint; + + auto a = BigInt("1000"); + assert(a.ulongLength() == 1); + assert(a.getDigit(0) == 1000); + + assert(a.uintLength() == 1); + assert(a.getDigit!uint(0) == 1000); + + auto b = BigInt("2_000_000_000_000_000_000_000_000_000"); + assert(b.ulongLength() == 2); + assert(b.getDigit(0) == 4584946418820579328); + assert(b.getDigit(1) == 108420217); + + assert(b.uintLength() == 3); + assert(b.getDigit!uint(0) == 3489660928); + assert(b.getDigit!uint(1) == 1067516025); + assert(b.getDigit!uint(2) == 108420217); + +} + +@safe unittest +{ + import std.bigint; + + BigInt a = "9588669891916142"; + BigInt b = "7452469135154800"; + auto c = a * b; + assert(c == BigInt("71459266416693160362545788781600")); + auto d = b * a; + assert(d == BigInt("71459266416693160362545788781600")); + assert(d == c); + d = c * BigInt("794628672112"); + assert(d == BigInt("56783581982794522489042432639320434378739200")); + auto e = c + d; + assert(e == BigInt("56783581982865981755459125799682980167520800")); + auto f = d + c; + assert(f == e); + auto g = f - c; + assert(g == d); + g = f - d; + assert(g == c); + e = 12345678; + g = c + e; + auto h = g / b; + auto i = g % b; + assert(h == a); + assert(i == e); + BigInt j = "-0x9A56_57f4_7B83_AB78"; + BigInt k = j; + j ^^= 11; + assert(k ^^ 11 == j); +} + +@safe pure unittest +{ + import std.bigint; + + auto x = BigInt("123"); + x *= 1000; + x += 456; + + auto xstr = x.toDecimalString(); + assert(xstr == "123456"); +} + +@safe unittest +{ + import std.bigint; + + auto x = BigInt("123"); + x *= 1000; + x += 456; + + auto xstr = x.toHex(); + assert(xstr == "1E240"); +} + +nothrow pure @safe unittest +{ + import std.bigint; + + assert((-1).absUnsign == 1); + assert(1.absUnsign == 1); +} + +@safe pure nothrow unittest +{ + import std.bigint; + + auto a = BigInt(123); + auto b = BigInt(25); + BigInt q, r; + + divMod(a, b, q, r); + + assert(q == 4); + assert(r == 23); + assert(q * b + r == a); +} + +@safe unittest +{ + import std.bigint; + + BigInt base = BigInt("123456789012345678901234567890"); + BigInt exponent = BigInt("1234567890123456789012345678901234567"); + BigInt modulus = BigInt("1234567"); + + BigInt result = powmod(base, exponent, modulus); + assert(result == 359079); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_bitmanip.d b/libphobos/testsuite/libphobos.phobos/std_bitmanip.d new file mode 100644 index 000000000000..6bd658d01186 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_bitmanip.d @@ -0,0 +1,1628 @@ +@safe unittest +{ + import std.bitmanip; + + struct A + { + int a; + mixin(bitfields!( + uint, "x", 2, + int, "y", 3, + uint, "z", 2, + bool, "flag", 1)); + } + + A obj; + obj.x = 2; + obj.z = obj.x; + + assert(obj.x == 2); + assert(obj.y == 0); + assert(obj.z == 2); + assert(obj.flag == false); +} + +@safe unittest +{ + import std.bitmanip; + + struct A + { + mixin(bitfields!( + bool, "flag1", 1, + bool, "flag2", 1, + uint, "", 6)); + } + + A a; + assert(a.flag1 == 0); + a.flag1 = 1; + assert(a.flag1 == 1); + a.flag1 = 0; + assert(a.flag1 == 0); +} + +@safe unittest +{ + import std.bitmanip; + + enum ABC { A, B, C } + struct EnumTest + { + mixin(bitfields!( + ABC, "x", 2, + bool, "y", 1, + ubyte, "z", 5)); + } +} + +@safe unittest +{ + import std.bitmanip; + + struct A + { + int a; + mixin(taggedPointer!( + uint*, "x", + bool, "b1", 1, + bool, "b2", 1)); + } + A obj; + obj.x = new uint; + obj.b1 = true; + obj.b2 = false; +} + +@safe unittest +{ + import std.bitmanip; + + struct A + { + int a; + mixin(taggedClassRef!( + Object, "o", + uint, "i", 2)); + } + A obj; + obj.o = new Object(); + obj.i = 3; +} + +@safe unittest +{ + import std.bitmanip; + + FloatRep rep = {value: 0}; + assert(rep.fraction == 0); + assert(rep.exponent == 0); + assert(!rep.sign); + + rep.value = 42; + assert(rep.fraction == 2621440); + assert(rep.exponent == 132); + assert(!rep.sign); + + rep.value = 10; + assert(rep.fraction == 2097152); + assert(rep.exponent == 130); +} + +@safe unittest +{ + import std.bitmanip; + + FloatRep rep = {value: 1}; + assert(rep.fraction == 0); + assert(rep.exponent == 127); + assert(!rep.sign); + + rep.exponent = 126; + assert(rep.value == 0.5); + + rep.exponent = 130; + assert(rep.value == 8); +} + +@safe unittest +{ + import std.bitmanip; + + FloatRep rep = {value: 1}; + rep.value = -0.5; + assert(rep.fraction == 0); + assert(rep.exponent == 126); + assert(rep.sign); + + rep.value = -1. / 3; + assert(rep.fraction == 2796203); + assert(rep.exponent == 125); + assert(rep.sign); +} + +@safe unittest +{ + import std.bitmanip; + + DoubleRep rep = {value: 0}; + assert(rep.fraction == 0); + assert(rep.exponent == 0); + assert(!rep.sign); + + rep.value = 42; + assert(rep.fraction == 1407374883553280); + assert(rep.exponent == 1028); + assert(!rep.sign); + + rep.value = 10; + assert(rep.fraction == 1125899906842624); + assert(rep.exponent == 1026); +} + +@safe unittest +{ + import std.bitmanip; + + DoubleRep rep = {value: 1}; + assert(rep.fraction == 0); + assert(rep.exponent == 1023); + assert(!rep.sign); + + rep.exponent = 1022; + assert(rep.value == 0.5); + + rep.exponent = 1026; + assert(rep.value == 8); +} + +@safe unittest +{ + import std.bitmanip; + + DoubleRep rep = {value: 1}; + rep.value = -0.5; + assert(rep.fraction == 0); + assert(rep.exponent == 1022); + assert(rep.sign); + + rep.value = -1. / 3; + assert(rep.fraction == 1501199875790165); + assert(rep.exponent == 1021); + assert(rep.sign); +} + +@safe unittest +{ + import std.bitmanip; + + DoubleRep x; + x.value = 1.0; + assert(x.fraction == 0 && x.exponent == 1023 && !x.sign); + x.value = -0.5; + assert(x.fraction == 0 && x.exponent == 1022 && x.sign); + x.value = 0.5; + assert(x.fraction == 0 && x.exponent == 1022 && !x.sign); +} + +@safe unittest +{ + import std.bitmanip; + + DoubleRep x; + x.fraction = 1125899906842624; + x.exponent = 1025; + x.sign = true; + assert(x.value == -5.0); +} + +@system unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + + bool[] input = [true, false, false, true, true]; + auto a = BitArray(input); + assert(a.length == 5); + assert(a.bitsSet.equal([0, 3, 4])); + + // This also works because an implicit cast to bool[] occurs for this array. + auto b = BitArray([0, 0, 1]); + assert(b.length == 3); + assert(b.bitsSet.equal([2])); + +} + +@system unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + import std.array : array; + import std.range : iota, repeat; + + BitArray a = true.repeat(70).array; + assert(a.length == 70); + assert(a.bitsSet.equal(iota(0, 70))); + +} + +@system unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + + auto a = BitArray([1, 0, 0, 1, 1]); + + // Inverse of the cast. + auto v = cast(void[]) a; + auto b = BitArray(v, a.length); + + assert(b.length == 5); + assert(b.bitsSet.equal([0, 3, 4])); + + // a and b share the underlying data. + a[0] = 0; + assert(b[0] == 0); + assert(a == b); + +} + +@system unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + + size_t[] source = [0b1100, 0b0011]; + enum sbits = size_t.sizeof * 8; + auto ba = BitArray(source, source.length * sbits); + // The least significant bit in each unit is this unit's starting bit. + assert(ba.bitsSet.equal([2, 3, sbits, sbits + 1])); + +} + +@system unittest +{ + import std.bitmanip; + + // Example from the doc for this constructor. + static immutable size_t[] sourceData = [1, 0b101, 3, 3424234, 724398, 230947, 389492]; + size_t[] source = sourceData.dup; + enum sbits = size_t.sizeof * 8; + auto ba = BitArray(source, source.length * sbits); + foreach (n; 0 .. source.length * sbits) + { + auto nth_bit = cast(bool) (source[n / sbits] & (1L << (n % sbits))); + assert(ba[n] == nth_bit); + } + + // Example of mapping only part of the array. + import std.algorithm.comparison : equal; + + auto bc = BitArray(source, sbits + 1); + assert(bc.bitsSet.equal([0, sbits])); + // Source array has not been modified. + assert(source == sourceData); + +} + +@system unittest +{ + import std.bitmanip; + + static void fun(const BitArray arr) + { + auto x = arr[0]; + assert(x == 1); + } + BitArray a; + a.length = 3; + a[0] = 1; + fun(a); + +} + +@system pure nothrow unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + + auto b = BitArray([1, 0, 1, 0, 1, 1]); + + b[] = true; + // all bits are set + assert(b.bitsSet.equal([0, 1, 2, 3, 4, 5])); + + b[] = false; + // none of the bits are set + assert(b.bitsSet.empty); + +} + +@system pure nothrow unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + import std.range : iota; + import std.stdio; + + auto b = BitArray([1, 0, 0, 0, 1, 1, 0]); + b[1 .. 3] = true; + assert(b.bitsSet.equal([0, 1, 2, 4, 5])); + + bool[72] bitArray; + auto b1 = BitArray(bitArray); + b1[63 .. 67] = true; + assert(b1.bitsSet.equal([63, 64, 65, 66])); + b1[63 .. 67] = false; + assert(b1.bitsSet.empty); + b1[0 .. 64] = true; + assert(b1.bitsSet.equal(iota(0, 64))); + b1[0 .. 64] = false; + assert(b1.bitsSet.empty); + + bool[256] bitArray2; + auto b2 = BitArray(bitArray2); + b2[3 .. 245] = true; + assert(b2.bitsSet.equal(iota(3, 245))); + b2[3 .. 245] = false; + assert(b2.bitsSet.empty); + +} + +@system pure nothrow unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + import std.range : iota; + + // positions 0, 2, 4 are set + auto b = BitArray([1, 0, 1, 0, 1, 0]); + b.flip(); + // after flipping, positions 1, 3, 5 are set + assert(b.bitsSet.equal([1, 3, 5])); + + bool[270] bits; + auto b1 = BitArray(bits); + b1.flip(); + assert(b1.bitsSet.equal(iota(0, 270))); + +} + +@system pure nothrow unittest +{ + import std.bitmanip; + + auto ax = BitArray([1, 0, 0, 1]); + ax.flip(0); + assert(ax[0] == 0); + + bool[200] y; + y[90 .. 130] = true; + auto ay = BitArray(y); + ay.flip(100); + assert(ay[100] == 0); + +} + +@system pure nothrow unittest +{ + import std.bitmanip; + + auto a = BitArray([0, 1, 1, 0, 0, 1, 1]); + assert(a.count == 4); + + BitArray b; + assert(b.count == 0); + + bool[200] boolArray; + boolArray[45 .. 130] = true; + auto c = BitArray(boolArray); + assert(c.count == 85); + +} + +@system unittest +{ + import std.bitmanip; + + BitArray a; + BitArray b; + + a.length = 3; + a[0] = 1; a[1] = 0; a[2] = 1; + b = a.dup; + assert(b.length == 3); + foreach (i; 0 .. 3) + assert(b[i] == (((i ^ 1) & 1) ? true : false)); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1]; + + auto a = BitArray(ba); + + int i; + foreach (b;a) + { + switch (i) + { + case 0: assert(b == true); break; + case 1: assert(b == false); break; + case 2: assert(b == true); break; + default: assert(0); + } + i++; + } + + foreach (j,b;a) + { + switch (j) + { + case 0: assert(b == true); break; + case 1: assert(b == false); break; + case 2: assert(b == true); break; + default: assert(0); + } + } + +} + +@system unittest +{ + import std.bitmanip; + + BitArray b; + bool[5] data = [1,0,1,1,0]; + + b = BitArray(data); + b.reverse; + foreach (i; 0 .. data.length) + assert(b[i] == data[4 - i]); + +} + +@system unittest +{ + import std.bitmanip; + + size_t x = 0b1100011000; + auto ba = BitArray(10, &x); + ba.sort; + foreach (i; 0 .. 6) + assert(ba[i] == false); + foreach (i; 6 .. 10) + assert(ba[i] == true); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1]; + bool[] bb = [1,0,1]; + bool[] bc = [1,0,1,0,1,0,1]; + bool[] bd = [1,0,1,1,1]; + bool[] be = [1,0,1,0,1]; + bool[] bf = [1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; + bool[] bg = [1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + auto c = BitArray(bc); + auto d = BitArray(bd); + auto e = BitArray(be); + auto f = BitArray(bf); + auto g = BitArray(bg); + + assert(a != b); + assert(a != c); + assert(a != d); + assert(a == e); + assert(f != g); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1]; + bool[] bb = [1,0,1]; + bool[] bc = [1,0,1,0,1,0,1]; + bool[] bd = [1,0,1,1,1]; + bool[] be = [1,0,1,0,1]; + bool[] bf = [1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]; + bool[] bg = [1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + auto c = BitArray(bc); + auto d = BitArray(bd); + auto e = BitArray(be); + auto f = BitArray(bf); + auto g = BitArray(bg); + + assert(a > b); + assert(a >= b); + assert(a < c); + assert(a <= c); + assert(a < d); + assert(a <= d); + assert(a == e); + assert(a <= e); + assert(a >= e); + assert(f < g); + assert(g <= g); + +} + +@system unittest +{ + import std.bitmanip; + + import std.array : array; + import std.range : repeat, take; + + // bit array with 300 elements + auto a = BitArray(true.repeat.take(300).array); + size_t[] v = cast(size_t[]) a; + const blockSize = size_t.sizeof * 8; + assert(v.length == (a.length + blockSize - 1) / blockSize); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1]; + + auto a = BitArray(ba); + BitArray b = ~a; + + assert(b[0] == 0); + assert(b[1] == 1); + assert(b[2] == 0); + assert(b[3] == 1); + assert(b[4] == 0); + +} + +@system unittest +{ + import std.bitmanip; + + static bool[] ba = [1,0,1,0,1]; + static bool[] bb = [1,0,1,1,0]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + + BitArray c = a & b; + + assert(c[0] == 1); + assert(c[1] == 0); + assert(c[2] == 1); + assert(c[3] == 0); + assert(c[4] == 0); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1]; + bool[] bb = [1,0,1,1,0]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + + BitArray c = a | b; + + assert(c[0] == 1); + assert(c[1] == 0); + assert(c[2] == 1); + assert(c[3] == 1); + assert(c[4] == 1); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1]; + bool[] bb = [1,0,1,1,0]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + + BitArray c = a ^ b; + + assert(c[0] == 0); + assert(c[1] == 0); + assert(c[2] == 0); + assert(c[3] == 1); + assert(c[4] == 1); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1]; + bool[] bb = [1,0,1,1,0]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + + BitArray c = a - b; + + assert(c[0] == 0); + assert(c[1] == 0); + assert(c[2] == 0); + assert(c[3] == 0); + assert(c[4] == 1); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1,1,0,1,0,1]; + bool[] bb = [1,0,1,1,0]; + auto a = BitArray(ba); + auto b = BitArray(bb); + BitArray c = a; + c.length = 5; + c &= b; + assert(a[5] == 1); + assert(a[6] == 0); + assert(a[7] == 1); + assert(a[8] == 0); + assert(a[9] == 1); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1]; + bool[] bb = [1,0,1,1,0]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + + a &= b; + assert(a[0] == 1); + assert(a[1] == 0); + assert(a[2] == 1); + assert(a[3] == 0); + assert(a[4] == 0); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1]; + bool[] bb = [1,0,1,1,0]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + + a |= b; + assert(a[0] == 1); + assert(a[1] == 0); + assert(a[2] == 1); + assert(a[3] == 1); + assert(a[4] == 1); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1]; + bool[] bb = [1,0,1,1,0]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + + a ^= b; + assert(a[0] == 0); + assert(a[1] == 0); + assert(a[2] == 0); + assert(a[3] == 1); + assert(a[4] == 1); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1]; + bool[] bb = [1,0,1,1,0]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + + a -= b; + assert(a[0] == 0); + assert(a[1] == 0); + assert(a[2] == 0); + assert(a[3] == 0); + assert(a[4] == 1); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0,1,0,1]; + + auto a = BitArray(ba); + BitArray b; + + b = (a ~= true); + assert(a[0] == 1); + assert(a[1] == 0); + assert(a[2] == 1); + assert(a[3] == 0); + assert(a[4] == 1); + assert(a[5] == 1); + + assert(b == a); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0]; + bool[] bb = [0,1,0]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + BitArray c; + + c = (a ~= b); + assert(a.length == 5); + assert(a[0] == 1); + assert(a[1] == 0); + assert(a[2] == 0); + assert(a[3] == 1); + assert(a[4] == 0); + + assert(c == a); + +} + +@system unittest +{ + import std.bitmanip; + + bool[] ba = [1,0]; + bool[] bb = [0,1,0]; + + auto a = BitArray(ba); + auto b = BitArray(bb); + BitArray c; + + c = (a ~ b); + assert(c.length == 5); + assert(c[0] == 1); + assert(c[1] == 0); + assert(c[2] == 0); + assert(c[3] == 1); + assert(c[4] == 0); + + c = (a ~ true); + assert(c.length == 3); + assert(c[0] == 1); + assert(c[1] == 0); + assert(c[2] == 1); + + c = (false ~ a); + assert(c.length == 3); + assert(c[0] == 0); + assert(c[1] == 1); + assert(c[2] == 0); + +} + +@system unittest +{ + import std.bitmanip; + + import std.format : format; + + auto b = BitArray([1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1]); + + b <<= 1; + assert(format("%b", b) == "01100_10101101"); + + b >>= 1; + assert(format("%b", b) == "11001_01011010"); + + b <<= 4; + assert(format("%b", b) == "00001_10010101"); + + b >>= 5; + assert(format("%b", b) == "10010_10100000"); + + b <<= 13; + assert(format("%b", b) == "00000_00000000"); + + b = BitArray([1, 0, 1, 1, 0, 1, 1, 1]); + b >>= 8; + assert(format("%b", b) == "00000000"); + + +} + +@system pure unittest +{ + import std.bitmanip; + + import std.format : format; + + auto b = BitArray([0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]); + + auto s1 = format("%s", b); + assert(s1 == "[0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]"); + + auto s2 = format("%b", b); + assert(s2 == "00001111_00001111"); + +} + +@system unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + + auto b1 = BitArray([0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]); + assert(b1.bitsSet.equal([4, 5, 6, 7, 12, 13, 14, 15])); + + BitArray b2; + b2.length = 1000; + b2[333] = true; + b2[666] = true; + b2[999] = true; + assert(b2.bitsSet.equal([333, 666, 999])); + +} + +@system unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + import std.range : iota; + + bool[] buf = new bool[64 * 3]; + buf[0 .. 64] = true; + BitArray b = BitArray(buf); + assert(b.bitsSet.equal(iota(0, 64))); + b <<= 64; + assert(b.bitsSet.equal(iota(64, 128))); +} + +@system unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + + auto b = BitArray([1, 0]); + b ~= true; + assert(b[2] == 1); + b ~= BitArray([0, 1]); + auto c = BitArray([1, 0, 1, 0, 1]); + assert(b == c); + assert(b.bitsSet.equal([0, 2, 4])); +} + +@system unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + + auto b = BitArray([1, 1, 0, 1]); + b &= BitArray([0, 1, 1, 0]); + assert(b.bitsSet.equal([1])); + b.flip; + assert(b.bitsSet.equal([0, 2, 3])); +} + +@system unittest +{ + import std.bitmanip; + + import std.format : format; + auto b = BitArray([1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]); + assert(format("%b", b) == "1_00001111_00001111"); +} + +@system unittest +{ + import std.bitmanip; + + import std.format : format; + + BitArray b; + + b = BitArray([]); + assert(format("%s", b) == "[]"); + assert(format("%b", b) is null); + + b = BitArray([1]); + assert(format("%s", b) == "[1]"); + assert(format("%b", b) == "1"); + + b = BitArray([0, 0, 0, 0]); + assert(format("%b", b) == "0000"); + + b = BitArray([0, 0, 0, 0, 1, 1, 1, 1]); + assert(format("%s", b) == "[0, 0, 0, 0, 1, 1, 1, 1]"); + assert(format("%b", b) == "00001111"); + + b = BitArray([0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]); + assert(format("%s", b) == "[0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]"); + assert(format("%b", b) == "00001111_00001111"); + + b = BitArray([1, 0, 0, 0, 0, 1, 1, 1, 1]); + assert(format("%b", b) == "1_00001111"); + + b = BitArray([1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1]); + assert(format("%b", b) == "1_00001111_00001111"); +} + +@safe unittest +{ + import std.bitmanip; + + assert(42.swapEndian == 704643072); + assert(42.swapEndian.swapEndian == 42); // reflexive + assert(1.swapEndian == 16777216); + + assert(true.swapEndian == true); + assert(byte(10).swapEndian == 10); + assert(char(10).swapEndian == 10); + + assert(ushort(10).swapEndian == 2560); + assert(long(10).swapEndian == 720575940379279360); + assert(ulong(10).swapEndian == 720575940379279360); +} + +@safe unittest +{ + import std.bitmanip; + + int i = 12345; + ubyte[4] swappedI = nativeToBigEndian(i); + assert(i == bigEndianToNative!int(swappedI)); + + float f = 123.45f; + ubyte[4] swappedF = nativeToBigEndian(f); + assert(f == bigEndianToNative!float(swappedF)); + + const float cf = 123.45f; + ubyte[4] swappedCF = nativeToBigEndian(cf); + assert(cf == bigEndianToNative!float(swappedCF)); + + double d = 123.45; + ubyte[8] swappedD = nativeToBigEndian(d); + assert(d == bigEndianToNative!double(swappedD)); + + const double cd = 123.45; + ubyte[8] swappedCD = nativeToBigEndian(cd); + assert(cd == bigEndianToNative!double(swappedCD)); +} + +@safe unittest +{ + import std.bitmanip; + + ushort i = 12345; + ubyte[2] swappedI = nativeToBigEndian(i); + assert(i == bigEndianToNative!ushort(swappedI)); + + dchar c = 'D'; + ubyte[4] swappedC = nativeToBigEndian(c); + assert(c == bigEndianToNative!dchar(swappedC)); +} + +@safe unittest +{ + import std.bitmanip; + + int i = 12345; + ubyte[4] swappedI = nativeToLittleEndian(i); + assert(i == littleEndianToNative!int(swappedI)); + + float f = 123.45f; + ubyte[4] swappedF = nativeToLittleEndian(f); + assert(f == littleEndianToNative!float(swappedF)); + + const float cf = 123.45f; + ubyte[4] swappedCF = nativeToLittleEndian(cf); + assert(cf == littleEndianToNative!float(swappedCF)); + + double d = 123.45; + ubyte[8] swappedD = nativeToLittleEndian(d); + assert(d == littleEndianToNative!double(swappedD)); + + const double cd = 123.45; + ubyte[8] swappedCD = nativeToLittleEndian(cd); + assert(cd == littleEndianToNative!double(swappedCD)); +} + +@safe unittest +{ + import std.bitmanip; + + ushort i = 12345; + ubyte[2] swappedI = nativeToLittleEndian(i); + assert(i == littleEndianToNative!ushort(swappedI)); + + dchar c = 'D'; + ubyte[4] swappedC = nativeToLittleEndian(c); + assert(c == littleEndianToNative!dchar(swappedC)); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [1, 5, 22, 9, 44, 255, 8]; + assert(buffer.peek!uint() == 17110537); + assert(buffer.peek!ushort() == 261); + assert(buffer.peek!ubyte() == 1); + + assert(buffer.peek!uint(2) == 369700095); + assert(buffer.peek!ushort(2) == 5641); + assert(buffer.peek!ubyte(2) == 22); + + size_t index = 0; + assert(buffer.peek!ushort(&index) == 261); + assert(index == 2); + + assert(buffer.peek!uint(&index) == 369700095); + assert(index == 6); + + assert(buffer.peek!ubyte(&index) == 8); + assert(index == 7); +} + +@safe unittest +{ + import std.bitmanip; + + import std.algorithm.iteration : filter; + ubyte[] buffer = [1, 5, 22, 9, 44, 255, 7]; + auto range = filter!"true"(buffer); + assert(range.peek!uint() == 17110537); + assert(range.peek!ushort() == 261); + assert(range.peek!ubyte() == 1); +} + +@safe unittest +{ + import std.bitmanip; + + import std.range.primitives : empty; + ubyte[] buffer = [1, 5, 22, 9, 44, 255, 8]; + assert(buffer.length == 7); + + assert(buffer.read!ushort() == 261); + assert(buffer.length == 5); + + assert(buffer.read!uint() == 369700095); + assert(buffer.length == 1); + + assert(buffer.read!ubyte() == 8); + assert(buffer.empty); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0]; + buffer.write!uint(29110231u, 0); + assert(buffer == [1, 188, 47, 215, 0, 0, 0, 0]); + + buffer.write!ushort(927, 0); + assert(buffer == [3, 159, 47, 215, 0, 0, 0, 0]); + + buffer.write!ubyte(42, 0); + assert(buffer == [42, 159, 47, 215, 0, 0, 0, 0]); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0, 0]; + buffer.write!uint(142700095u, 2); + assert(buffer == [0, 0, 8, 129, 110, 63, 0, 0, 0]); + + buffer.write!ushort(19839, 2); + assert(buffer == [0, 0, 77, 127, 110, 63, 0, 0, 0]); + + buffer.write!ubyte(132, 2); + assert(buffer == [0, 0, 132, 127, 110, 63, 0, 0, 0]); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0]; + size_t index = 0; + buffer.write!ushort(261, &index); + assert(buffer == [1, 5, 0, 0, 0, 0, 0, 0]); + assert(index == 2); + + buffer.write!uint(369700095u, &index); + assert(buffer == [1, 5, 22, 9, 44, 255, 0, 0]); + assert(index == 6); + + buffer.write!ubyte(8, &index); + assert(buffer == [1, 5, 22, 9, 44, 255, 8, 0]); + assert(index == 7); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0]; + buffer.write!bool(false, 0); + assert(buffer == [0, 0]); + + buffer.write!bool(true, 0); + assert(buffer == [1, 0]); + + buffer.write!bool(true, 1); + assert(buffer == [1, 1]); + + buffer.write!bool(false, 1); + assert(buffer == [1, 0]); + + size_t index = 0; + buffer.write!bool(false, &index); + assert(buffer == [0, 0]); + assert(index == 1); + + buffer.write!bool(true, &index); + assert(buffer == [0, 1]); + assert(index == 2); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0]; + + buffer.write!char('a', 0); + assert(buffer == [97, 0, 0]); + + buffer.write!char('b', 1); + assert(buffer == [97, 98, 0]); + + size_t index = 0; + buffer.write!char('a', &index); + assert(buffer == [97, 98, 0]); + assert(index == 1); + + buffer.write!char('b', &index); + assert(buffer == [97, 98, 0]); + assert(index == 2); + + buffer.write!char('c', &index); + assert(buffer == [97, 98, 99]); + assert(index == 3); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0, 0]; + + buffer.write!wchar('Ä…', 0); + assert(buffer == [1, 5, 0, 0]); + + buffer.write!wchar('â€', 2); + assert(buffer == [1, 5, 32, 29]); + + size_t index = 0; + buffer.write!wchar('ć', &index); + assert(buffer == [1, 7, 32, 29]); + assert(index == 2); + + buffer.write!wchar('Ä…', &index); + assert(buffer == [1, 7, 1, 5]); + assert(index == 4); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0]; + + buffer.write!dchar('Ä…', 0); + assert(buffer == [0, 0, 1, 5, 0, 0, 0, 0]); + + buffer.write!dchar('â€', 4); + assert(buffer == [0, 0, 1, 5, 0, 0, 32, 29]); + + size_t index = 0; + buffer.write!dchar('ć', &index); + assert(buffer == [0, 0, 1, 7, 0, 0, 32, 29]); + assert(index == 4); + + buffer.write!dchar('Ä…', &index); + assert(buffer == [0, 0, 1, 7, 0, 0, 1, 5]); + assert(index == 8); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0]; + + buffer.write!float(32.0f, 0); + assert(buffer == [66, 0, 0, 0, 0, 0, 0, 0]); + + buffer.write!float(25.0f, 4); + assert(buffer == [66, 0, 0, 0, 65, 200, 0, 0]); + + size_t index = 0; + buffer.write!float(25.0f, &index); + assert(buffer == [65, 200, 0, 0, 65, 200, 0, 0]); + assert(index == 4); + + buffer.write!float(32.0f, &index); + assert(buffer == [65, 200, 0, 0, 66, 0, 0, 0]); + assert(index == 8); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + buffer.write!double(32.0, 0); + assert(buffer == [64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + + buffer.write!double(25.0, 8); + assert(buffer == [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]); + + size_t index = 0; + buffer.write!double(25.0, &index); + assert(buffer == [64, 57, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]); + assert(index == 8); + + buffer.write!double(32.0, &index); + assert(buffer == [64, 57, 0, 0, 0, 0, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0]); + assert(index == 16); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + enum Foo + { + one = 10, + two = 20, + three = 30 + } + + buffer.write!Foo(Foo.one, 0); + assert(buffer == [0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0]); + + buffer.write!Foo(Foo.two, 4); + assert(buffer == [0, 0, 0, 10, 0, 0, 0, 20, 0, 0, 0, 0]); + + buffer.write!Foo(Foo.three, 8); + assert(buffer == [0, 0, 0, 10, 0, 0, 0, 20, 0, 0, 0, 30]); + + size_t index = 0; + buffer.write!Foo(Foo.three, &index); + assert(buffer == [0, 0, 0, 30, 0, 0, 0, 20, 0, 0, 0, 30]); + assert(index == 4); + + buffer.write!Foo(Foo.one, &index); + assert(buffer == [0, 0, 0, 30, 0, 0, 0, 10, 0, 0, 0, 30]); + assert(index == 8); + + buffer.write!Foo(Foo.two, &index); + assert(buffer == [0, 0, 0, 30, 0, 0, 0, 10, 0, 0, 0, 20]); + assert(index == 12); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0]; + + enum Float: float + { + one = 32.0f, + two = 25.0f + } + + buffer.write!Float(Float.one, 0); + assert(buffer == [66, 0, 0, 0, 0, 0, 0, 0]); + + buffer.write!Float(Float.two, 4); + assert(buffer == [66, 0, 0, 0, 65, 200, 0, 0]); + + size_t index = 0; + buffer.write!Float(Float.two, &index); + assert(buffer == [65, 200, 0, 0, 65, 200, 0, 0]); + assert(index == 4); + + buffer.write!Float(Float.one, &index); + assert(buffer == [65, 200, 0, 0, 66, 0, 0, 0]); + assert(index == 8); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + enum Double: double + { + one = 32.0, + two = 25.0 + } + + buffer.write!Double(Double.one, 0); + assert(buffer == [64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + + buffer.write!Double(Double.two, 8); + assert(buffer == [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]); + + size_t index = 0; + buffer.write!Double(Double.two, &index); + assert(buffer == [64, 57, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]); + assert(index == 8); + + buffer.write!Double(Double.one, &index); + assert(buffer == [64, 57, 0, 0, 0, 0, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0]); + assert(index == 16); +} + +@system unittest +{ + import std.bitmanip; + + ubyte[] buffer = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + + enum Real: real + { + one = 32.0, + two = 25.0 + } + + static assert(!__traits(compiles, buffer.write!Real(Real.one))); +} + +@safe unittest +{ + import std.bitmanip; + + import std.array; + auto buffer = appender!(const ubyte[])(); + buffer.append!ushort(261); + assert(buffer.data == [1, 5]); + + buffer.append!uint(369700095u); + assert(buffer.data == [1, 5, 22, 9, 44, 255]); + + buffer.append!ubyte(8); + assert(buffer.data == [1, 5, 22, 9, 44, 255, 8]); +} + +@safe unittest +{ + import std.bitmanip; + + import std.array : appender; + auto buffer = appender!(const ubyte[])(); + + buffer.append!bool(true); + assert(buffer.data == [1]); + + buffer.append!bool(false); + assert(buffer.data == [1, 0]); +} + +@safe unittest +{ + import std.bitmanip; + + import std.array : appender; + auto buffer = appender!(const ubyte[])(); + + buffer.append!char('a'); + assert(buffer.data == [97]); + + buffer.append!char('b'); + assert(buffer.data == [97, 98]); + + buffer.append!wchar('Ä…'); + assert(buffer.data == [97, 98, 1, 5]); + + buffer.append!dchar('Ä…'); + assert(buffer.data == [97, 98, 1, 5, 0, 0, 1, 5]); +} + +@safe unittest +{ + import std.bitmanip; + + import std.array : appender; + auto buffer = appender!(const ubyte[])(); + + buffer.append!float(32.0f); + assert(buffer.data == [66, 0, 0, 0]); + + buffer.append!double(32.0); + assert(buffer.data == [66, 0, 0, 0, 64, 64, 0, 0, 0, 0, 0, 0]); +} + +@safe unittest +{ + import std.bitmanip; + + import std.array : appender; + auto buffer = appender!(const ubyte[])(); + + enum Foo + { + one = 10, + two = 20, + three = 30 + } + + buffer.append!Foo(Foo.one); + assert(buffer.data == [0, 0, 0, 10]); + + buffer.append!Foo(Foo.two); + assert(buffer.data == [0, 0, 0, 10, 0, 0, 0, 20]); + + buffer.append!Foo(Foo.three); + assert(buffer.data == [0, 0, 0, 10, 0, 0, 0, 20, 0, 0, 0, 30]); +} + +@safe unittest +{ + import std.bitmanip; + + import std.array : appender; + auto buffer = appender!(const ubyte[])(); + + enum Bool: bool + { + bfalse = false, + btrue = true, + } + + buffer.append!Bool(Bool.btrue); + assert(buffer.data == [1]); + + buffer.append!Bool(Bool.bfalse); + assert(buffer.data == [1, 0]); + + buffer.append!Bool(Bool.btrue); + assert(buffer.data == [1, 0, 1]); +} + +@safe unittest +{ + import std.bitmanip; + + import std.array : appender; + auto buffer = appender!(const ubyte[])(); + + enum Float: float + { + one = 32.0f, + two = 25.0f + } + + buffer.append!Float(Float.one); + assert(buffer.data == [66, 0, 0, 0]); + + buffer.append!Float(Float.two); + assert(buffer.data == [66, 0, 0, 0, 65, 200, 0, 0]); +} + +@safe unittest +{ + import std.bitmanip; + + import std.array : appender; + auto buffer = appender!(const ubyte[])(); + + enum Double: double + { + one = 32.0, + two = 25.0 + } + + buffer.append!Double(Double.one); + assert(buffer.data == [64, 64, 0, 0, 0, 0, 0, 0]); + + buffer.append!Double(Double.two); + assert(buffer.data == [64, 64, 0, 0, 0, 0, 0, 0, 64, 57, 0, 0, 0, 0, 0, 0]); +} + +@safe unittest +{ + import std.bitmanip; + + import std.array : appender; + auto buffer = appender!(const ubyte[])(); + + enum Real: real + { + one = 32.0, + two = 25.0 + } + + static assert(!__traits(compiles, buffer.append!Real(Real.one))); +} + +@safe unittest +{ + import std.bitmanip; + + import std.algorithm.comparison : equal; + import std.range : iota; + + assert(bitsSet(1).equal([0])); + assert(bitsSet(5).equal([0, 2])); + assert(bitsSet(-1).equal(iota(32))); + assert(bitsSet(int.min).equal([31])); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_checkedint.d b/libphobos/testsuite/libphobos.phobos/std_checkedint.d new file mode 100644 index 000000000000..589d8d3a716c --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_checkedint.d @@ -0,0 +1,628 @@ +@safe unittest +{ + import std.checkedint; + + int[] concatAndAdd(int[] a, int[] b, int offset) + { + // Aborts on overflow on size computation + auto r = new int[(checked(a.length) + b.length).get]; + // Aborts on overflow on element computation + foreach (i; 0 .. a.length) + r[i] = (a[i] + checked(offset)).get; + foreach (i; 0 .. b.length) + r[i + a.length] = (b[i] + checked(offset)).get; + return r; + } + assert(concatAndAdd([1, 2, 3], [4, 5], -1) == [0, 1, 2, 3, 4]); +} + +@safe unittest +{ + import std.checkedint; + + auto x = (cast(byte) 127).checked!Saturate; + assert(x == 127); + x++; + assert(x == 127); +} + +@safe unittest +{ + import std.checkedint; + + auto x = 100.checked!WithNaN; + assert(x == 100); + x /= 0; + assert(x.isNaN); +} + +@safe unittest +{ + import std.checkedint; + + uint x = 1; + auto y = x.checked!ProperCompare; + assert(x < -1); // built-in comparison + assert(y > -1); // ProperCompare +} + +@safe unittest +{ + import std.checkedint; + + import std.exception : assertThrown; + auto x = -1.checked!Throw; + assertThrown(x / 0); + assertThrown(x + int.min); + assertThrown(x == uint.max); +} + +@safe unittest +{ + import std.checkedint; + + auto x = checked(ubyte(42)); + static assert(is(typeof(x.get()) == ubyte)); + assert(x.get == 42); + const y = checked(ubyte(42)); + static assert(is(typeof(y.get()) == const ubyte)); + assert(y.get == 42); + +} + +@safe unittest +{ + import std.checkedint; + + assert(Checked!short.min == -32768); + assert(Checked!(short, WithNaN).min == -32767); + assert(Checked!(uint, WithNaN).max == uint.max - 1); + +} + +@safe unittest +{ + import std.checkedint; + + auto a = checked(42L); + assert(a == 42); + auto b = Checked!long(4242); // convert 4242 to long + assert(b == 4242); + +} + +@safe unittest +{ + import std.checkedint; + + Checked!long a; + a = 42L; + assert(a == 42); + a = 4242; + assert(a == 4242); + +} + +@safe unittest +{ + import std.checkedint; + + Checked!long a, b; + a = b = 3; + assert(a == 3 && b == 3); + +} + +@system unittest +{ + import std.checkedint; + + import std.conv : to; + + const a = to!long("1234"); + const b = to!(Checked!long)("1234"); + assert(a == b); + +} + +@safe unittest +{ + import std.checkedint; + + assert(cast(uint) checked(42) == 42); + assert(cast(uint) checked!WithNaN(-42) == uint.max); + +} + +@safe unittest +{ + import std.checkedint; + + import std.traits : isUnsigned; + + static struct MyHook + { + static bool thereWereErrors; + static bool hookOpEquals(L, R)(L lhs, R rhs) + { + if (lhs != rhs) return false; + static if (isUnsigned!L && !isUnsigned!R) + { + if (lhs > 0 && rhs < 0) thereWereErrors = true; + } + else static if (isUnsigned!R && !isUnsigned!L) + if (lhs < 0 && rhs > 0) thereWereErrors = true; + // Preserve built-in behavior. + return true; + } + } + auto a = checked!MyHook(-42); + assert(a == uint(-42)); + assert(MyHook.thereWereErrors); + MyHook.thereWereErrors = false; + assert(checked!MyHook(uint(-42)) == -42); + assert(MyHook.thereWereErrors); + static struct MyHook2 + { + static bool hookOpEquals(L, R)(L lhs, R rhs) + { + return lhs == rhs; + } + } + MyHook.thereWereErrors = false; + assert(checked!MyHook2(uint(-42)) == a); + // Hook on left hand side takes precedence, so no errors + assert(!MyHook.thereWereErrors); + +} + +@system unittest +{ + import std.checkedint; + + import std.format; + + assert(format("%04d", checked(15)) == "0015"); + assert(format("0x%02x", checked(15)) == "0x0f"); + +} + +@safe unittest +{ + import std.checkedint; + + import std.traits : isUnsigned; + + static struct MyHook + { + static bool thereWereErrors; + static int hookOpCmp(L, R)(L lhs, R rhs) + { + static if (isUnsigned!L && !isUnsigned!R) + { + if (rhs < 0 && rhs >= lhs) + thereWereErrors = true; + } + else static if (isUnsigned!R && !isUnsigned!L) + { + if (lhs < 0 && lhs >= rhs) + thereWereErrors = true; + } + // Preserve built-in behavior. + return lhs < rhs ? -1 : lhs > rhs; + } + } + auto a = checked!MyHook(-42); + assert(a > uint(42)); + assert(MyHook.thereWereErrors); + static struct MyHook2 + { + static int hookOpCmp(L, R)(L lhs, R rhs) + { + // Default behavior + return lhs < rhs ? -1 : lhs > rhs; + } + } + MyHook.thereWereErrors = false; + assert(Checked!(uint, MyHook2)(uint(-42)) <= a); + //assert(Checked!(uint, MyHook2)(uint(-42)) >= a); + // Hook on left hand side takes precedence, so no errors + assert(!MyHook.thereWereErrors); + assert(a <= Checked!(uint, MyHook2)(uint(-42))); + assert(MyHook.thereWereErrors); + +} + +@safe unittest +{ + import std.checkedint; + + static struct MyHook + { + static bool thereWereErrors; + static L hookOpUnary(string x, L)(L lhs) + { + if (x == "-" && lhs == -lhs) thereWereErrors = true; + return -lhs; + } + } + auto a = checked!MyHook(long.min); + assert(a == -a); + assert(MyHook.thereWereErrors); + auto b = checked!void(42); + assert(++b == 43); + +} + +@safe unittest +{ + import std.checkedint; + + static struct MyHook + { + static bool thereWereErrors; + static T onLowerBound(Rhs, T)(Rhs rhs, T bound) + { + thereWereErrors = true; + return bound; + } + static T onUpperBound(Rhs, T)(Rhs rhs, T bound) + { + thereWereErrors = true; + return bound; + } + } + auto x = checked!MyHook(byte.min); + x -= 1; + assert(MyHook.thereWereErrors); + MyHook.thereWereErrors = false; + x = byte.max; + x += 1; + assert(MyHook.thereWereErrors); + +} + +@safe @nogc pure nothrow unittest +{ + import std.checkedint; + + // Hook that ignores all problems. + static struct Ignore + { + @nogc nothrow pure @safe static: + Dst onBadCast(Dst, Src)(Src src) { return cast(Dst) src; } + Lhs onLowerBound(Rhs, T)(Rhs rhs, T bound) { return cast(T) rhs; } + T onUpperBound(Rhs, T)(Rhs rhs, T bound) { return cast(T) rhs; } + bool hookOpEquals(Lhs, Rhs)(Lhs lhs, Rhs rhs) { return lhs == rhs; } + int hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs) { return (lhs > rhs) - (lhs < rhs); } + typeof(~Lhs()) onOverflow(string x, Lhs)(ref Lhs lhs) { return mixin(x ~ "lhs"); } + typeof(Lhs() + Rhs()) onOverflow(string x, Lhs, Rhs)(Lhs lhs, Rhs rhs) + { + static if (x == "/") + return typeof(lhs / rhs).min; + else + return mixin("lhs" ~ x ~ "rhs"); + } + } + + auto x = Checked!(int, Ignore)(5) + 7; +} + +@safe unittest +{ + import std.checkedint; + + static assert(is(typeof(checked(42)) == Checked!int)); + assert(checked(42) == Checked!int(42)); + static assert(is(typeof(checked!WithNaN(42)) == Checked!(int, WithNaN))); + assert(checked!WithNaN(42) == Checked!(int, WithNaN)(42)); +} + +@safe unittest +{ + import std.checkedint; + + void test(T)() + { + Checked!(int, Abort) x; + x = 42; + auto x1 = cast(T) x; + assert(x1 == 42); + //x1 += long(int.max); + } + test!short; + test!(const short); + test!(immutable short); +} + +@safe unittest +{ + import std.checkedint; + + void test(T)() + { + Checked!(int, Throw) x; + x = 42; + auto x1 = cast(T) x; + assert(x1 == 42); + x = T.max + 1; + import std.exception : assertThrown, assertNotThrown; + assertThrown(cast(T) x); + x = x.max; + assertThrown(x += 42); + assertThrown(x += 42L); + x = x.min; + assertThrown(-x); + assertThrown(x -= 42); + assertThrown(x -= 42L); + x = -1; + assertNotThrown(x == -1); + assertThrown(x == uint(-1)); + assertNotThrown(x <= -1); + assertThrown(x <= uint(-1)); + } + test!short; + test!(const short); + test!(immutable short); +} + +@safe unittest +{ + import std.checkedint; + + auto x = checked!Warn(-42); + // Passes + assert(x == -42); + // Passes but prints a warning + // assert(x == uint(-42)); + +} + +@safe unittest +{ + import std.checkedint; + + auto x = checked!Warn(-42); + // Passes + assert(x <= -42); + // Passes but prints a warning + // assert(x <= uint(-42)); + +} + +@safe unittest +{ + import std.checkedint; + + auto x = checked!Warn(42); + short x1 = cast(short) x; + //x += long(int.max); + auto y = checked!Warn(cast(const int) 42); + short y1 = cast(const byte) y; +} + +@safe unittest +{ + import std.checkedint; + + alias opEqualsProper = ProperCompare.hookOpEquals; + assert(opEqualsProper(42, 42)); + assert(opEqualsProper(42.0, 42.0)); + assert(opEqualsProper(42u, 42)); + assert(opEqualsProper(42, 42u)); + assert(-1 == 4294967295u); + assert(!opEqualsProper(-1, 4294967295u)); + assert(!opEqualsProper(const uint(-1), -1)); + assert(!opEqualsProper(uint(-1), -1.0)); + assert(3_000_000_000U == -1_294_967_296); + assert(!opEqualsProper(3_000_000_000U, -1_294_967_296)); +} + +@safe unittest +{ + import std.checkedint; + + auto x = checked!WithNaN(422); + assert((cast(ubyte) x) == 255); + x = checked!WithNaN(-422); + assert((cast(byte) x) == -128); + assert(cast(short) x == -422); + assert(cast(bool) x); + x = x.init; // set back to NaN + assert(x != true); + assert(x != false); + +} + +@safe unittest +{ + import std.checkedint; + + Checked!(int, WithNaN) x; + assert(!(x < 0) && !(x > 0) && !(x == 0)); + x = 1; + assert(x > 0 && !(x < 0) && !(x == 0)); + +} + +@safe unittest +{ + import std.checkedint; + + Checked!(int, WithNaN) x; + ++x; + assert(x.isNaN); + x = 1; + assert(!x.isNaN); + x = -x; + ++x; + assert(!x.isNaN); + +} + +@safe unittest +{ + import std.checkedint; + + Checked!(int, WithNaN) x; + assert((x + 1).isNaN); + x = 100; + assert(!(x + 1).isNaN); + +} + +@safe unittest +{ + import std.checkedint; + + Checked!(int, WithNaN) x; + assert((1 + x).isNaN); + x = 100; + assert(!(1 + x).isNaN); + +} + +@safe unittest +{ + import std.checkedint; + + Checked!(int, WithNaN) x; + x += 4; + assert(x.isNaN); + x = 0; + x += 4; + assert(!x.isNaN); + x += int.max; + assert(x.isNaN); + +} + +@safe unittest +{ + import std.checkedint; + + auto x1 = Checked!(int, WithNaN)(); + assert(x1.isNaN); + assert(x1.get == int.min); + assert(x1 != x1); + assert(!(x1 < x1)); + assert(!(x1 > x1)); + assert(!(x1 == x1)); + ++x1; + assert(x1.isNaN); + assert(x1.get == int.min); + --x1; + assert(x1.isNaN); + assert(x1.get == int.min); + x1 = 42; + assert(!x1.isNaN); + assert(x1 == x1); + assert(x1 <= x1); + assert(x1 >= x1); + static assert(x1.min == int.min + 1); + x1 += long(int.max); +} + +@safe unittest +{ + import std.checkedint; + + auto x1 = Checked!(int, WithNaN)(); + assert(x1.isNaN); + x1 = 1; + assert(!x1.isNaN); + x1 = x1.init; + assert(x1.isNaN); +} + +@safe unittest +{ + import std.checkedint; + + auto x = checked!Saturate(short(100)); + x += 33000; + assert(x == short.max); + x -= 70000; + assert(x == short.min); + +} + +@safe unittest +{ + import std.checkedint; + + assert(checked!Saturate(int.max) + 1 == int.max); + assert(checked!Saturate(100) ^^ 10 == int.max); + assert(checked!Saturate(-100) ^^ 10 == int.max); + assert(checked!Saturate(100) / 0 == int.max); + assert(checked!Saturate(100) << -1 == 0); + assert(checked!Saturate(100) << 33 == int.max); + assert(checked!Saturate(100) >> -1 == int.max); + assert(checked!Saturate(100) >> 33 == 0); + +} + +@safe unittest +{ + import std.checkedint; + + auto x = checked!Saturate(int.max); + ++x; + assert(x == int.max); + --x; + assert(x == int.max - 1); + x = int.min; + assert(-x == int.max); + x -= 42; + assert(x == int.min); + assert(x * -2 == int.max); +} + +@safe unittest +{ + import std.checkedint; + + bool overflow; + assert(opChecked!"+"(const short(1), short(1), overflow) == 2 && !overflow); + assert(opChecked!"+"(1, 1, overflow) == 2 && !overflow); + assert(opChecked!"+"(1, 1u, overflow) == 2 && !overflow); + assert(opChecked!"+"(-1, 1u, overflow) == 0 && !overflow); + assert(opChecked!"+"(1u, -1, overflow) == 0 && !overflow); +} + +@safe unittest +{ + import std.checkedint; + + bool overflow; + assert(opChecked!"-"(1, 1, overflow) == 0 && !overflow); + assert(opChecked!"-"(1, 1u, overflow) == 0 && !overflow); + assert(opChecked!"-"(1u, -1, overflow) == 2 && !overflow); + assert(opChecked!"-"(-1, 1u, overflow) == 0 && overflow); +} + +@safe unittest +{ + import std.checkedint; + + struct MyHook + { + static size_t hookToHash(T)(const T payload) nothrow @trusted + { + return .hashOf(payload); + } + } + + int[Checked!(int, MyHook)] aa; + Checked!(int, MyHook) var = 42; + aa[var] = 100; + + assert(aa[var] == 100); + + int[Checked!(int, Abort)] bb; + Checked!(int, Abort) var2 = 42; + bb[var2] = 100; + + assert(bb[var2] == 100); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_complex.d b/libphobos/testsuite/libphobos.phobos/std_complex.d new file mode 100644 index 000000000000..44ac5d7fdf2a --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_complex.d @@ -0,0 +1,403 @@ +@safe pure nothrow unittest +{ + import std.complex; + + auto a = complex(1.0); + static assert(is(typeof(a) == Complex!double)); + assert(a.re == 1.0); + assert(a.im == 0.0); + + auto b = complex(2.0L); + static assert(is(typeof(b) == Complex!real)); + assert(b.re == 2.0L); + assert(b.im == 0.0L); + + auto c = complex(1.0, 2.0); + static assert(is(typeof(c) == Complex!double)); + assert(c.re == 1.0); + assert(c.im == 2.0); + + auto d = complex(3.0, 4.0L); + static assert(is(typeof(d) == Complex!real)); + assert(d.re == 3.0); + assert(d.im == 4.0L); + + auto e = complex(1); + static assert(is(typeof(e) == Complex!double)); + assert(e.re == 1); + assert(e.im == 0); + + auto f = complex(1L, 2); + static assert(is(typeof(f) == Complex!double)); + assert(f.re == 1L); + assert(f.im == 2); + + auto g = complex(3, 4.0L); + static assert(is(typeof(g) == Complex!real)); + assert(g.re == 3); + assert(g.im == 4.0L); +} + +@safe unittest +{ + import std.complex; + + auto c = complex(1.2, 3.4); + + // Vanilla toString formatting: + assert(c.toString() == "1.2+3.4i"); + + // Formatting with std.string.format specs: the precision and width + // specifiers apply to both the real and imaginary parts of the + // complex number. + import std.format : format; + assert(format("%.2f", c) == "1.20+3.40i"); + assert(format("%4.1f", c) == " 1.2+ 3.4i"); + +} + +@safe pure nothrow unittest +{ + import std.complex; + + static import core.math; + assert(abs(complex(1.0)) == 1.0); + assert(abs(complex(0.0, 1.0)) == 1.0); + assert(abs(complex(1.0L, -2.0L)) == core.math.sqrt(5.0L)); +} + +@safe pure nothrow unittest +{ + import std.complex; + + import std.math.operations : isClose; + assert(sqAbs(complex(0.0)) == 0.0); + assert(sqAbs(complex(1.0)) == 1.0); + assert(sqAbs(complex(0.0, 1.0)) == 1.0); + assert(isClose(sqAbs(complex(1.0L, -2.0L)), 5.0L)); + assert(isClose(sqAbs(complex(-3.0L, 1.0L)), 10.0L)); + assert(isClose(sqAbs(complex(1.0f,-1.0f)), 2.0f)); +} + +@safe pure nothrow unittest +{ + import std.complex; + + import std.math.constants : PI_2, PI_4; + assert(arg(complex(1.0)) == 0.0); + assert(arg(complex(0.0L, 1.0L)) == PI_2); + assert(arg(complex(1.0L, 1.0L)) == PI_4); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import std.math.operations : isClose; + import std.math.constants : PI; + assert(norm(complex(3.0, 4.0)) == 25.0); + assert(norm(fromPolar(5.0, 0.0)) == 25.0); + assert(isClose(norm(fromPolar(5.0L, PI / 6)), 25.0L)); + assert(isClose(norm(fromPolar(5.0L, 13 * PI / 6)), 25.0L)); +} + +@safe pure nothrow unittest +{ + import std.complex; + + assert(conj(complex(1.0)) == complex(1.0)); + assert(conj(complex(1.0, 2.0)) == complex(1.0, -2.0)); +} + +@safe pure nothrow unittest +{ + import std.complex; + + assert(proj(complex(1.0)) == complex(1.0)); + assert(proj(complex(double.infinity, 5.0)) == complex(double.infinity, 0.0)); + assert(proj(complex(5.0, -double.infinity)) == complex(double.infinity, -0.0)); +} + +@safe pure nothrow unittest +{ + import std.complex; + + import core.math; + import std.math.operations : isClose; + import std.math.algebraic : sqrt; + import std.math.constants : PI_4; + auto z = fromPolar(core.math.sqrt(2.0L), PI_4); + assert(isClose(z.re, 1.0L)); + assert(isClose(z.im, 1.0L)); +} + +@safe pure nothrow unittest +{ + import std.complex; + + static import core.math; + assert(sin(complex(0.0)) == 0.0); + assert(sin(complex(2.0, 0)) == core.math.sin(2.0)); +} + +@safe pure nothrow unittest +{ + import std.complex; + + static import core.math; + static import std.math; + assert(cos(complex(0.0)) == 1.0); + assert(cos(complex(1.3, 0.0)) == core.math.cos(1.3)); + assert(cos(complex(0.0, 5.2)) == std.math.cosh(5.2)); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + static import std.math; + + int ceqrel(T)(const Complex!T x, const Complex!T y) @safe pure nothrow @nogc + { + import std.math.operations : feqrel; + const r = feqrel(x.re, y.re); + const i = feqrel(x.im, y.im); + return r < i ? r : i; + } + assert(ceqrel(tan(complex(1.0, 0.0)), complex(std.math.tan(1.0), 0.0)) >= double.mant_dig - 2); + assert(ceqrel(tan(complex(0.0, 1.0)), complex(0.0, std.math.tanh(1.0))) >= double.mant_dig - 2); +} + +@safe pure nothrow unittest +{ + import std.complex; + + import std.math.operations : isClose; + import std.math.constants : PI; + assert(asin(complex(0.0)) == 0.0); + assert(isClose(asin(complex(0.5L)), PI / 6)); +} + +@safe pure nothrow unittest +{ + import std.complex; + + import std.math.operations : isClose; + import std.math.constants : PI; + import std.math.trigonometry : std_math_acos = acos; + assert(acos(complex(0.0)) == std_math_acos(0.0)); + assert(isClose(acos(complex(0.5L)), PI / 3)); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import std.math.operations : isClose; + import std.math.constants : PI; + assert(atan(complex(0.0)) == 0.0); + assert(isClose(atan(sqrt(complex(3.0L))), PI / 3)); + assert(isClose(atan(sqrt(complex(3.0f))), float(PI) / 3)); +} + +@safe pure nothrow unittest +{ + import std.complex; + + static import std.math; + assert(sinh(complex(0.0)) == 0.0); + assert(sinh(complex(1.0L)) == std.math.sinh(1.0L)); + assert(sinh(complex(1.0f)) == std.math.sinh(1.0f)); +} + +@safe pure nothrow unittest +{ + import std.complex; + + static import std.math; + assert(cosh(complex(0.0)) == 1.0); + assert(cosh(complex(1.0L)) == std.math.cosh(1.0L)); + assert(cosh(complex(1.0f)) == std.math.cosh(1.0f)); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import std.math.operations : isClose; + import std.math.trigonometry : std_math_tanh = tanh; + assert(tanh(complex(0.0)) == 0.0); + assert(isClose(tanh(complex(1.0L)), std_math_tanh(1.0L))); + assert(isClose(tanh(complex(1.0f)), std_math_tanh(1.0f))); +} + +@safe pure nothrow unittest +{ + import std.complex; + + import std.math.operations : isClose; + import std.math.trigonometry : std_math_asinh = asinh; + assert(asinh(complex(0.0)) == 0.0); + assert(isClose(asinh(complex(1.0L)), std_math_asinh(1.0L))); + assert(isClose(asinh(complex(1.0f)), std_math_asinh(1.0f))); +} + +@safe pure nothrow unittest +{ + import std.complex; + + import std.math.operations : isClose; + import std.math.trigonometry : std_math_acosh = acosh; + assert(acosh(complex(1.0)) == 0.0); + assert(isClose(acosh(complex(3.0L)), std_math_acosh(3.0L))); + assert(isClose(acosh(complex(3.0f)), std_math_acosh(3.0f))); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import std.math.operations : isClose; + import std.math.trigonometry : std_math_atanh = atanh; + assert(atanh(complex(0.0)) == 0.0); + assert(isClose(atanh(complex(0.5L)), std_math_atanh(0.5L))); + assert(isClose(atanh(complex(0.5f)), std_math_atanh(0.5f))); +} + +@safe pure nothrow unittest +{ + import std.complex; + + import core.math : cos, sin; + assert(expi(0.0L) == 1.0L); + assert(expi(1.3e5L) == complex(cos(1.3e5L), sin(1.3e5L))); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import std.math.trigonometry : cosh, sinh; + assert(coshisinh(3.0L) == complex(cosh(3.0L), sinh(3.0L))); +} + +@safe pure nothrow unittest +{ + import std.complex; + + static import core.math; + assert(sqrt(complex(0.0)) == 0.0); + assert(sqrt(complex(1.0L, 0)) == core.math.sqrt(1.0L)); + assert(sqrt(complex(-1.0L, 0)) == complex(0, 1.0L)); + assert(sqrt(complex(-8.0, -6.0)) == complex(1.0, -3.0)); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import std.math.operations : isClose; + import std.math.constants : PI; + + assert(exp(complex(0.0, 0.0)) == complex(1.0, 0.0)); + + auto a = complex(2.0, 1.0); + assert(exp(conj(a)) == conj(exp(a))); + + auto b = exp(complex(0.0L, 1.0L) * PI); + assert(isClose(b, -1.0L, 0.0, 1e-15)); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import core.math : sqrt; + import std.math.constants : PI; + import std.math.operations : isClose; + + auto a = complex(2.0, 1.0); + assert(log(conj(a)) == conj(log(a))); + + auto b = 2.0 * log10(complex(0.0, 1.0)); + auto c = 4.0 * log10(complex(sqrt(2.0) / 2, sqrt(2.0) / 2)); + assert(isClose(b, c, 0.0, 1e-15)); + + assert(log(complex(-1.0L, 0.0L)) == complex(0.0L, PI)); + assert(log(complex(-1.0L, -0.0L)) == complex(0.0L, -PI)); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import core.math : sqrt; + import std.math.constants : LN10, PI; + import std.math.operations : isClose; + + auto a = complex(2.0, 1.0); + assert(log10(a) == log(a) / log(complex(10.0))); + + auto b = log10(complex(0.0, 1.0)) * 2.0; + auto c = log10(complex(sqrt(2.0) / 2, sqrt(2.0) / 2)) * 4.0; + assert(isClose(b, c, 0.0, 1e-15)); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import std.math.operations : isClose; + + auto a = complex(1.0, 2.0); + assert(pow(a, 2) == a * a); + assert(pow(a, 3) == a * a * a); + assert(pow(a, -2) == 1.0 / (a * a)); + assert(isClose(pow(a, -3), 1.0 / (a * a * a))); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import std.math.operations : isClose; + assert(pow(complex(0.0), 2.0) == complex(0.0)); + assert(pow(complex(5.0), 2.0) == complex(25.0)); + + auto a = pow(complex(-1.0, 0.0), 0.5); + assert(isClose(a, complex(0.0, +1.0), 0.0, 1e-16)); + + auto b = pow(complex(-1.0, -0.0), 0.5); + assert(isClose(b, complex(0.0, -1.0), 0.0, 1e-16)); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import std.math.operations : isClose; + import std.math.exponential : exp; + import std.math.constants : PI; + auto a = complex(0.0); + auto b = complex(2.0); + assert(pow(a, b) == complex(0.0)); + + auto c = complex(0.0L, 1.0L); + assert(isClose(pow(c, c), exp((-PI) / 2))); +} + +@safe pure nothrow @nogc unittest +{ + import std.complex; + + import std.math.operations : isClose; + assert(pow(2.0, complex(0.0)) == complex(1.0)); + assert(pow(2.0, complex(5.0)) == complex(32.0)); + + auto a = pow(-2.0, complex(-1.0)); + assert(isClose(a, complex(-0.5), 0.0, 1e-16)); + + auto b = pow(-0.5, complex(-1.0)); + assert(isClose(b, complex(-2.0), 0.0, 1e-15)); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_concurrency.d b/libphobos/testsuite/libphobos.phobos/std_concurrency.d new file mode 100644 index 000000000000..46da87d47af6 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_concurrency.d @@ -0,0 +1,235 @@ +@system unittest +{ + import std.concurrency; + + __gshared string received; + static void spawnedFunc(Tid ownerTid) + { + import std.conv : text; + // Receive a message from the owner thread. + receive((int i){ + received = text("Received the number ", i); + + // Send a message back to the owner thread + // indicating success. + send(ownerTid, true); + }); + } + + // Start spawnedFunc in a new thread. + auto childTid = spawn(&spawnedFunc, thisTid); + + // Send the number 42 to this new thread. + send(childTid, 42); + + // Receive the result code. + auto wasSuccessful = receiveOnly!(bool); + assert(wasSuccessful); + assert(received == "Received the number 42"); +} + +@system unittest +{ + import std.concurrency; + + static void f(string msg) + { + assert(msg == "Hello World"); + } + + auto tid = spawn(&f, "Hello World"); +} + +@system unittest +{ + import std.concurrency; + + string msg = "Hello, World!"; + + static void f1(string msg) {} + static assert(!__traits(compiles, spawn(&f1, msg.dup))); + static assert( __traits(compiles, spawn(&f1, msg.idup))); + + static void f2(char[] msg) {} + static assert(!__traits(compiles, spawn(&f2, msg.dup))); + static assert(!__traits(compiles, spawn(&f2, msg.idup))); +} + +@system unittest +{ + import std.concurrency; + + spawn({ + ownerTid.send("This is so great!"); + }); + assert(receiveOnly!string == "This is so great!"); +} + +@system unittest +{ + import std.concurrency; + + import std.variant : Variant; + + auto process = () + { + receive( + (int i) { ownerTid.send(1); }, + (double f) { ownerTid.send(2); }, + (Variant v) { ownerTid.send(3); } + ); + }; + + { + auto tid = spawn(process); + send(tid, 42); + assert(receiveOnly!int == 1); + } + + { + auto tid = spawn(process); + send(tid, 3.14); + assert(receiveOnly!int == 2); + } + + { + auto tid = spawn(process); + send(tid, "something else"); + assert(receiveOnly!int == 3); + } +} + +@system unittest +{ + import std.concurrency; + + auto tid = spawn( + { + assert(receiveOnly!int == 42); + }); + send(tid, 42); +} + +@system unittest +{ + import std.concurrency; + + auto tid = spawn( + { + assert(receiveOnly!string == "text"); + }); + send(tid, "text"); +} + +@system unittest +{ + import std.concurrency; + + struct Record { string name; int age; } + + auto tid = spawn( + { + auto msg = receiveOnly!(double, Record); + assert(msg[0] == 0.5); + assert(msg[1].name == "Alice"); + assert(msg[1].age == 31); + }); + + send(tid, 0.5, Record("Alice", 31)); +} + +@system unittest +{ + import std.concurrency; + + auto tid = spawn({ + int i; + while (i < 9) + i = receiveOnly!int; + + ownerTid.send(i * 2); + }); + + auto r = new Generator!int({ + foreach (i; 1 .. 10) + yield(i); + }); + + foreach (e; r) + tid.send(e); + + assert(receiveOnly!int == 18); +} + +@system unittest +{ + import std.concurrency; + + import std.range; + + InputRange!int myIota = iota(10).inputRangeObject; + + myIota.popFront(); + myIota.popFront(); + assert(myIota.moveFront == 2); + assert(myIota.front == 2); + myIota.popFront(); + assert(myIota.front == 3); + + //can be assigned to std.range.interfaces.InputRange directly + myIota = new Generator!int( + { + foreach (i; 0 .. 10) yield(i); + }); + + myIota.popFront(); + myIota.popFront(); + assert(myIota.moveFront == 2); + assert(myIota.front == 2); + myIota.popFront(); + assert(myIota.front == 3); + + size_t[2] counter = [0, 0]; + foreach (i, unused; myIota) counter[] += [1, i]; + + assert(myIota.empty); + assert(counter == [7, 21]); +} + +@system unittest +{ + import std.concurrency; + + static class MySingleton + { + static MySingleton instance() + { + __gshared MySingleton inst; + return initOnce!inst(new MySingleton); + } + } + + assert(MySingleton.instance !is null); +} + +@system unittest +{ + import std.concurrency; + + import core.sync.mutex : Mutex; + + static shared bool varA, varB; + static shared Mutex m; + m = new shared Mutex; + + spawn({ + // use a different mutex for varB to avoid a dead-lock + initOnce!varB(true, m); + ownerTid.send(true); + }); + // init depends on the result of the spawned thread + initOnce!varA(receiveOnly!bool); + assert(varA == true); + assert(varB == true); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_container_array.d b/libphobos/testsuite/libphobos.phobos/std_container_array.d new file mode 100644 index 000000000000..abf8dd57ceb9 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_container_array.d @@ -0,0 +1,56 @@ +pure @system unittest +{ + import std.container.array; + + auto arr = Array!int(0, 2, 3); + assert(arr[0] == 0); + assert(arr.front == 0); + assert(arr.back == 3); + + // reserve space + arr.reserve(1000); + assert(arr.length == 3); + assert(arr.capacity >= 1000); + + // insertion + arr.insertBefore(arr[1..$], 1); + assert(arr.front == 0); + assert(arr.length == 4); + + arr.insertBack(4); + assert(arr.back == 4); + assert(arr.length == 5); + + // set elements + arr[1] *= 42; + assert(arr[1] == 42); +} + +pure @system unittest +{ + import std.container.array; + + import std.algorithm.comparison : equal; + auto arr = Array!int(1, 2, 3); + + // concat + auto b = Array!int(11, 12, 13); + arr ~= b; + assert(arr.length == 6); + + // slicing + assert(arr[1 .. 3].equal([2, 3])); + + // remove + arr.linearRemove(arr[1 .. 3]); + assert(arr[0 .. 2].equal([1, 11])); +} + +pure @system unittest +{ + import std.container.array; + + auto arr = Array!bool([true, true, false, true, false]); + assert(arr.length == 5); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_container_binaryheap.d b/libphobos/testsuite/libphobos.phobos/std_container_binaryheap.d new file mode 100644 index 000000000000..1ebcc6738fec --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_container_binaryheap.d @@ -0,0 +1,102 @@ +@system unittest +{ + import std.container.binaryheap; + + import std.algorithm.comparison : equal; + import std.range : take; + auto maxHeap = heapify([4, 7, 3, 1, 5]); + assert(maxHeap.take(3).equal([7, 5, 4])); + + auto minHeap = heapify!"a > b"([4, 7, 3, 1, 5]); + assert(minHeap.take(3).equal([1, 3, 4])); +} + +@system unittest +{ + import std.container.binaryheap; + + import std.algorithm.comparison : equal; + int[] a = [ 4, 1, 3, 2, 16, 9, 10, 14, 8, 7 ]; + auto h = heapify(a); + // largest element + assert(h.front == 16); + // a has the heap property + assert(equal(a, [ 16, 14, 10, 8, 7, 9, 3, 2, 4, 1 ])); +} + +@system unittest +{ + import std.container.binaryheap; + + import std.algorithm.comparison : equal; + import std.range : take; + int[] a = [4, 1, 3, 2, 16, 9, 10, 14, 8, 7]; + auto top5 = heapify(a).take(5); + assert(top5.equal([16, 14, 10, 9, 8])); +} + +@system unittest +{ + import std.container.binaryheap; + + import std.conv : to; + import std.range.primitives; + { + // example from "Introduction to Algorithms" Cormen et al., p 146 + int[] a = [ 4, 1, 3, 2, 16, 9, 10, 14, 8, 7 ]; + auto h = heapify(a); + h = heapify!"a < b"(a); + assert(h.front == 16); + assert(a == [ 16, 14, 10, 8, 7, 9, 3, 2, 4, 1 ]); + auto witness = [ 16, 14, 10, 9, 8, 7, 4, 3, 2, 1 ]; + for (; !h.empty; h.removeFront(), witness.popFront()) + { + assert(!witness.empty); + assert(witness.front == h.front); + } + assert(witness.empty); + } + { + int[] a = [ 4, 1, 3, 2, 16, 9, 10, 14, 8, 7 ]; + int[] b = new int[a.length]; + BinaryHeap!(int[]) h = BinaryHeap!(int[])(b, 0); + foreach (e; a) + { + h.insert(e); + } + assert(b == [ 16, 14, 10, 8, 7, 3, 9, 1, 4, 2 ], to!string(b)); + } +} + +@system unittest +{ + import std.container.binaryheap; + + import std.stdio; + import std.algorithm.comparison : equal; + import std.container.binaryheap; + + int[] a = [ 4, 1, 3, 2, 16, 9, 10, 14, 8, 7 ]; + auto h = heapify(a); + + // Internal representation of Binary Heap tree + assert(a.equal([16, 14, 10, 8, 7, 9, 3, 2, 4, 1])); + + h.replaceFront(30); + // Value 16 was replaced by 30 + assert(a.equal([30, 14, 10, 8, 7, 9, 3, 2, 4, 1])); + + // Making changes to the Store will be seen in the Heap + a[0] = 40; + assert(h.front() == 40); + + // Inserting a new element will reallocate the Store, leaving + // the original Store unchanged. + h.insert(20); + assert(a.equal([40, 14, 10, 8, 7, 9, 3, 2, 4, 1])); + + // Making changes to the original Store will not affect the Heap anymore + a[0] = 60; + assert(h.front() == 40); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_container_dlist.d b/libphobos/testsuite/libphobos.phobos/std_container_dlist.d new file mode 100644 index 000000000000..f9510485a08e --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_container_dlist.d @@ -0,0 +1,47 @@ +@safe unittest +{ + import std.container.dlist; + + import std.algorithm.comparison : equal; + import std.container : DList; + + auto s = DList!int(1, 2, 3); + assert(equal(s[], [1, 2, 3])); + + s.removeFront(); + assert(equal(s[], [2, 3])); + s.removeBack(); + assert(equal(s[], [2])); + + s.insertFront([4, 5]); + assert(equal(s[], [4, 5, 2])); + s.insertBack([6, 7]); + assert(equal(s[], [4, 5, 2, 6, 7])); + + // If you want to apply range operations, simply slice it. + import std.algorithm.searching : countUntil; + import std.range : popFrontN, popBackN, walkLength; + + auto sl = DList!int([1, 2, 3, 4, 5]); + assert(countUntil(sl[], 2) == 1); + + auto r = sl[]; + popFrontN(r, 2); + popBackN(r, 2); + assert(r.equal([3])); + assert(walkLength(r) == 1); + + // DList.Range can be used to remove elements from the list it spans + auto nl = DList!int([1, 2, 3, 4, 5]); + for (auto rn = nl[]; !rn.empty;) + if (rn.front % 2 == 0) + nl.popFirstOf(rn); + else + rn.popFront(); + assert(equal(nl[], [1, 3, 5])); + auto rs = nl[]; + rs.popFront(); + nl.remove(rs); + assert(equal(nl[], [1])); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_container_rbtree.d b/libphobos/testsuite/libphobos.phobos/std_container_rbtree.d new file mode 100644 index 000000000000..a9d333550dc7 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_container_rbtree.d @@ -0,0 +1,60 @@ +@safe pure unittest +{ + import std.container.rbtree; + + import std.algorithm.comparison : equal; + import std.container.rbtree; + + auto rbt = redBlackTree(3, 1, 4, 2, 5); + assert(rbt.front == 1); + assert(equal(rbt[], [1, 2, 3, 4, 5])); + + rbt.removeKey(1, 4); + assert(equal(rbt[], [2, 3, 5])); + + rbt.removeFront(); + assert(equal(rbt[], [3, 5])); + + rbt.insert([1, 2, 4]); + assert(equal(rbt[], [1, 2, 3, 4, 5])); + + // Query bounds in O(log(n)) + assert(rbt.lowerBound(3).equal([1, 2])); + assert(rbt.equalRange(3).equal([3])); + assert(rbt.upperBound(3).equal([4, 5])); + + // A Red Black tree with the highest element at front: + import std.range : iota; + auto maxTree = redBlackTree!"a > b"(iota(5)); + assert(equal(maxTree[], [4, 3, 2, 1, 0])); + + // adding duplicates will not add them, but return 0 + auto rbt2 = redBlackTree(1, 3); + assert(rbt2.insert(1) == 0); + assert(equal(rbt2[], [1, 3])); + assert(rbt2.insert(2) == 1); + + // however you can allow duplicates + auto ubt = redBlackTree!true([0, 1, 0, 1]); + assert(equal(ubt[], [0, 0, 1, 1])); +} + +@safe pure unittest +{ + import std.container.rbtree; + + import std.range : iota; + + auto rbt1 = redBlackTree(0, 1, 5, 7); + auto rbt2 = redBlackTree!string("hello", "world"); + auto rbt3 = redBlackTree!true(0, 1, 5, 7, 5); + auto rbt4 = redBlackTree!"a > b"(0, 1, 5, 7); + auto rbt5 = redBlackTree!("a > b", true)(0.1, 1.3, 5.9, 7.2, 5.9); + + // also works with ranges + auto rbt6 = redBlackTree(iota(3)); + auto rbt7 = redBlackTree!true(iota(3)); + auto rbt8 = redBlackTree!"a > b"(iota(3)); + auto rbt9 = redBlackTree!("a > b", true)(iota(3)); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_container_slist.d b/libphobos/testsuite/libphobos.phobos/std_container_slist.d new file mode 100644 index 000000000000..7c9a2b66ac1c --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_container_slist.d @@ -0,0 +1,28 @@ +@safe unittest +{ + import std.container.slist; + + import std.algorithm.comparison : equal; + import std.container : SList; + + auto s = SList!int(1, 2, 3); + assert(equal(s[], [1, 2, 3])); + + s.removeFront(); + assert(equal(s[], [2, 3])); + + s.insertFront([5, 6]); + assert(equal(s[], [5, 6, 2, 3])); + + // If you want to apply range operations, simply slice it. + import std.algorithm.searching : countUntil; + import std.range : popFrontN, walkLength; + + auto sl = SList!int(1, 2, 3, 4, 5); + assert(countUntil(sl[], 2) == 1); + + auto r = sl[]; + popFrontN(r, 2); + assert(walkLength(r) == 3); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_container_util.d b/libphobos/testsuite/libphobos.phobos/std_container_util.d new file mode 100644 index 000000000000..07d8831464b8 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_container_util.d @@ -0,0 +1,51 @@ +@system unittest +{ + import std.container.util; + + import std.algorithm.comparison : equal; + import std.container; + + auto arr = make!(Array!int)([4, 2, 3, 1]); + assert(equal(arr[], [4, 2, 3, 1])); + + auto rbt = make!(RedBlackTree!(int, "a > b"))([4, 2, 3, 1]); + assert(equal(rbt[], [4, 3, 2, 1])); + + alias makeList = make!(SList!int); + auto slist = makeList(1, 2, 3); + assert(equal(slist[], [1, 2, 3])); +} + +@safe unittest +{ + import std.container.util; + + import std.container.array : Array; + import std.range : only, repeat; + import std.range.primitives : isInfinite; + static assert(__traits(compiles, { auto arr = make!Array(only(5)); })); + static assert(!__traits(compiles, { auto arr = make!Array(repeat(5)); })); +} + +@system unittest +{ + import std.container.util; + + import std.algorithm.comparison : equal; + import std.container.array, std.container.rbtree, std.container.slist; + import std.range : iota; + + auto arr = make!Array(iota(5)); + assert(equal(arr[], [0, 1, 2, 3, 4])); + + auto rbtmax = make!(RedBlackTree, "a > b")(iota(5)); + assert(equal(rbtmax[], [4, 3, 2, 1, 0])); + + auto rbtmin = make!RedBlackTree(4, 1, 3, 2); + assert(equal(rbtmin[], [1, 2, 3, 4])); + + alias makeList = make!SList; + auto list = makeList(1, 7, 42); + assert(equal(list[], [1, 7, 42])); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_conv.d b/libphobos/testsuite/libphobos.phobos/std_conv.d new file mode 100644 index 000000000000..01f6fb7e2569 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_conv.d @@ -0,0 +1,511 @@ +@safe unittest +{ + import std.conv; + + import std.exception : assertThrown; + assertThrown!ConvException(to!int("abc")); +} + +@safe unittest +{ + import std.conv; + + import std.exception : assertThrown; + assertThrown!ConvOverflowException(to!ubyte(1_000_000)); +} + +@safe pure unittest +{ + import std.conv; + + int a = 42; + int b = to!int(a); + double c = to!double(3.14); // c is double with value 3.14 +} + +@safe pure unittest +{ + import std.conv; + + import std.exception : assertThrown; + + int a = 420; + assert(to!long(a) == a); + assertThrown!ConvOverflowException(to!byte(a)); + + assert(to!int(4.2e6) == 4200000); + assertThrown!ConvOverflowException(to!uint(-3.14)); + assert(to!uint(3.14) == 3); + assert(to!uint(3.99) == 3); + assert(to!int(-3.99) == -3); +} + +@safe pure unittest +{ + import std.conv; + + auto str = to!string(42, 16); + assert(str == "2A"); + auto i = to!int(str, 16); + assert(i == 42); +} + +@safe pure unittest +{ + import std.conv; + + // 2^24 - 1, largest proper integer representable as float + int a = 16_777_215; + assert(to!int(to!float(a)) == a); + assert(to!int(to!float(-a)) == -a); +} + +@safe pure unittest +{ + import std.conv; + + import std.exception : assertThrown; + + assert(to!char("a") == 'a'); + assertThrown(to!char("ñ")); // 'ñ' does not fit into a char + assert(to!wchar("ñ") == 'ñ'); + assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar + assert(to!dchar("😃") == '😃'); + + // Using wstring or dstring as source type does not affect the result + assert(to!char("a"w) == 'a'); + assert(to!char("a"d) == 'a'); + + // Two code points cannot be converted to a single one + assertThrown(to!char("ab")); +} + +@safe pure unittest +{ + import std.conv; + + import std.string : split; + + int[] a = [1, 2, 3]; + auto b = to!(float[])(a); + assert(b == [1.0f, 2, 3]); + string str = "1 2 3 4 5 6"; + auto numbers = to!(double[])(split(str)); + assert(numbers == [1.0, 2, 3, 4, 5, 6]); + int[string] c; + c["a"] = 1; + c["b"] = 2; + auto d = to!(double[wstring])(c); + assert(d["a"w] == 1 && d["b"w] == 2); +} + +@safe unittest +{ + import std.conv; + + int[string][double[int[]]] a; + auto b = to!(short[wstring][string[double[]]])(a); +} + +@safe pure unittest +{ + import std.conv; + + import std.exception : assertThrown; + // Testing object conversions + class A {} + class B : A {} + class C : A {} + A a1 = new A, a2 = new B, a3 = new C; + assert(to!B(a2) is a2); + assert(to!C(a3) is a3); + assertThrown!ConvException(to!B(a3)); +} + +@system pure unittest +{ + import std.conv; + + // Conversion representing dynamic/static array with string + long[] a = [ 1, 3, 5 ]; + assert(to!string(a) == "[1, 3, 5]"); + + // Conversion representing associative array with string + int[string] associativeArray = ["0":1, "1":2]; + assert(to!string(associativeArray) == `["0":1, "1":2]` || + to!string(associativeArray) == `["1":2, "0":1]`); + + // char* to string conversion + assert(to!string(cast(char*) null) == ""); + assert(to!string("foo\0".ptr) == "foo"); + + // Conversion reinterpreting void array to string + auto w = "abcx"w; + const(void)[] b = w; + assert(b.length == 8); + + auto c = to!(wchar[])(b); + assert(c == "abcx"); +} + +@safe pure unittest +{ + import std.conv; + + import std.exception : assertThrown; + + enum E { a, b, c } + assert(to!E("a") == E.a); + assert(to!E("b") == E.b); + assertThrown!ConvException(to!E("A")); +} + +@safe unittest +{ + import std.conv; + + assert(roundTo!int(3.14) == 3); + assert(roundTo!int(3.49) == 3); + assert(roundTo!int(3.5) == 4); + assert(roundTo!int(3.999) == 4); + assert(roundTo!int(-3.14) == -3); + assert(roundTo!int(-3.49) == -3); + assert(roundTo!int(-3.5) == -4); + assert(roundTo!int(-3.999) == -4); + assert(roundTo!(const int)(to!(const double)(-3.999)) == -4); +} + +@safe unittest +{ + import std.conv; + + import std.typecons : Flag, Yes, No; + auto s = "true"; + bool b = parse!bool(s); + assert(b); + auto s2 = "true"; + bool b2 = parse!(bool, string, No.doCount)(s2); + assert(b2); + auto s3 = "true"; + auto b3 = parse!(bool, string, Yes.doCount)(s3); + assert(b3.data && b3.count == 4); + auto s4 = "falSE"; + auto b4 = parse!(bool, string, Yes.doCount)(s4); + assert(!b4.data && b4.count == 5); +} + +@safe pure unittest +{ + import std.conv; + + import std.typecons : Flag, Yes, No; + string s = "123"; + auto a = parse!int(s); + assert(a == 123); + + string s1 = "123"; + auto a1 = parse!(int, string, Yes.doCount)(s1); + assert(a1.data == 123 && a1.count == 3); +} + +@safe pure unittest +{ + import std.conv; + + import std.string : tr; + import std.typecons : Flag, Yes, No; + string test = "123 \t 76.14"; + auto a = parse!uint(test); + assert(a == 123); + assert(test == " \t 76.14"); // parse bumps string + test = tr(test, " \t\n\r", "", "d"); // skip ws + assert(test == "76.14"); + auto b = parse!double(test); + assert(b == 76.14); + assert(test == ""); + + string test2 = "123 \t 76.14"; + auto a2 = parse!(uint, string, Yes.doCount)(test2); + assert(a2.data == 123 && a2.count == 3); + assert(test2 == " \t 76.14");// parse bumps string + test2 = tr(test2, " \t\n\r", "", "d"); // skip ws + assert(test2 == "76.14"); + auto b2 = parse!(double, string, Yes.doCount)(test2); + assert(b2.data == 76.14 && b2.count == 5); + assert(test2 == ""); + +} + +@safe unittest +{ + import std.conv; + + import std.typecons : Flag, Yes, No, tuple; + enum EnumType : bool { a = true, b = false, c = a } + + auto str = "a"; + assert(parse!EnumType(str) == EnumType.a); + auto str2 = "a"; + assert(parse!(EnumType, string, No.doCount)(str2) == EnumType.a); + auto str3 = "a"; + assert(parse!(EnumType, string, Yes.doCount)(str3) == tuple(EnumType.a, 1)); + +} + +@safe unittest +{ + import std.conv; + + import std.math.operations : isClose; + import std.math.traits : isNaN, isInfinity; + import std.typecons : Flag, Yes, No; + auto str = "123.456"; + assert(parse!double(str).isClose(123.456)); + auto str2 = "123.456"; + assert(parse!(double, string, No.doCount)(str2).isClose(123.456)); + auto str3 = "123.456"; + auto r = parse!(double, string, Yes.doCount)(str3); + assert(r.data.isClose(123.456)); + assert(r.count == 7); + auto str4 = "-123.456"; + r = parse!(double, string, Yes.doCount)(str4); + assert(r.data.isClose(-123.456)); + assert(r.count == 8); + auto str5 = "+123.456"; + r = parse!(double, string, Yes.doCount)(str5); + assert(r.data.isClose(123.456)); + assert(r.count == 8); + auto str6 = "inf0"; + r = parse!(double, string, Yes.doCount)(str6); + assert(isInfinity(r.data) && r.count == 3 && str6 == "0"); + auto str7 = "-0"; + auto r2 = parse!(float, string, Yes.doCount)(str7); + assert(r2.data.isClose(0.0) && r2.count == 2); + auto str8 = "nan"; + auto r3 = parse!(real, string, Yes.doCount)(str8); + assert(isNaN(r3.data) && r3.count == 3); +} + +@safe pure unittest +{ + import std.conv; + + import std.typecons : Flag, Yes, No; + auto s = "Hello, World!"; + char first = parse!char(s); + assert(first == 'H'); + assert(s == "ello, World!"); + char second = parse!(char, string, No.doCount)(s); + assert(second == 'e'); + assert(s == "llo, World!"); + auto third = parse!(char, string, Yes.doCount)(s); + assert(third.data == 'l' && third.count == 1); + assert(s == "lo, World!"); +} + +@safe pure unittest +{ + import std.conv; + + import std.exception : assertThrown; + import std.typecons : Flag, Yes, No; + + alias NullType = typeof(null); + auto s1 = "null"; + assert(parse!NullType(s1) is null); + assert(s1 == ""); + + auto s2 = "NUll"d; + assert(parse!NullType(s2) is null); + assert(s2 == ""); + + auto s3 = "nuLlNULl"; + assert(parse!(NullType, string, No.doCount)(s3) is null); + auto r = parse!(NullType, string, Yes.doCount)(s3); + assert(r.data is null && r.count == 4); + + auto m = "maybe"; + assertThrown!ConvException(parse!NullType(m)); + assertThrown!ConvException(parse!(NullType, string, Yes.doCount)(m)); + assert(m == "maybe"); // m shouldn't change on failure + + auto s = "NULL"; + assert(parse!(const NullType)(s) is null); +} + +@safe pure unittest +{ + import std.conv; + + import std.typecons : Flag, Yes, No; + auto s1 = `[['h', 'e', 'l', 'l', 'o'], "world"]`; + auto a1 = parse!(string[])(s1); + assert(a1 == ["hello", "world"]); + + auto s2 = `["aaa", "bbb", "ccc"]`; + auto a2 = parse!(string[])(s2); + assert(a2 == ["aaa", "bbb", "ccc"]); + + auto s3 = `[['h', 'e', 'l', 'l', 'o'], "world"]`; + auto len3 = s3.length; + auto a3 = parse!(string[], string, Yes.doCount)(s3); + assert(a3.data == ["hello", "world"]); + assert(a3.count == len3); +} + +@safe pure unittest +{ + import std.conv; + + import std.typecons : Flag, Yes, No, tuple; + import std.range.primitives : save; + import std.array : assocArray; + auto s1 = "[1:10, 2:20, 3:30]"; + auto copyS1 = s1.save; + auto aa1 = parse!(int[int])(s1); + assert(aa1 == [1:10, 2:20, 3:30]); + assert(tuple([1:10, 2:20, 3:30], copyS1.length) == parse!(int[int], string, Yes.doCount)(copyS1)); + + auto s2 = `["aaa":10, "bbb":20, "ccc":30]`; + auto copyS2 = s2.save; + auto aa2 = parse!(int[string])(s2); + assert(aa2 == ["aaa":10, "bbb":20, "ccc":30]); + assert(tuple(["aaa":10, "bbb":20, "ccc":30], copyS2.length) == + parse!(int[string], string, Yes.doCount)(copyS2)); + + auto s3 = `["aaa":[1], "bbb":[2,3], "ccc":[4,5,6]]`; + auto copyS3 = s3.save; + auto aa3 = parse!(int[][string])(s3); + assert(aa3 == ["aaa":[1], "bbb":[2,3], "ccc":[4,5,6]]); + assert(tuple(["aaa":[1], "bbb":[2,3], "ccc":[4,5,6]], copyS3.length) == + parse!(int[][string], string, Yes.doCount)(copyS3)); + + auto s4 = `[]`; + int[int] emptyAA; + assert(tuple(emptyAA, s4.length) == parse!(int[int], string, Yes.doCount)(s4)); +} + +@safe unittest +{ + import std.conv; + + assert( text(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"c); + assert(wtext(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"w); + assert(dtext(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"d); +} + +@safe unittest +{ + import std.conv; + + // Same as 0177 + auto a = octal!177; + // octal is a compile-time device + enum b = octal!160; + // Create an unsigned octal + auto c = octal!"1_000_000u"; + // Leading zeros are allowed when converting from a string + auto d = octal!"0001_200_000"; +} + +@safe unittest +{ + import std.conv; + + import std.traits : Unsigned; + immutable int s = 42; + auto u1 = unsigned(s); //not qualified + static assert(is(typeof(u1) == uint)); + Unsigned!(typeof(s)) u2 = unsigned(s); //same qualification + static assert(is(typeof(u2) == immutable uint)); + immutable u3 = unsigned(s); //explicitly qualified +} + +@safe unittest +{ + import std.conv; + + import std.traits : Signed; + + immutable uint u = 42; + auto s1 = signed(u); //not qualified + static assert(is(typeof(s1) == int)); + Signed!(typeof(u)) s2 = signed(u); //same qualification + static assert(is(typeof(s2) == immutable int)); + immutable s3 = signed(u); //explicitly qualified +} + +@safe unittest +{ + import std.conv; + + enum A { a = 42 } + static assert(is(typeof(A.a.asOriginalType) == int)); + assert(A.a.asOriginalType == 42); + enum B : double { a = 43 } + static assert(is(typeof(B.a.asOriginalType) == double)); + assert(B.a.asOriginalType == 43); +} + +@system unittest +{ + import std.conv; + + // Regular cast, which has been verified to be legal by the programmer: + { + long x; + auto y = cast(int) x; + } + + // However this will still compile if 'x' is changed to be a pointer: + { + long* x; + auto y = cast(int) x; + } + + // castFrom provides a more reliable alternative to casting: + { + long x; + auto y = castFrom!long.to!int(x); + } + + // Changing the type of 'x' will now issue a compiler error, + // allowing bad casts to be caught before it's too late: + { + long* x; + static assert( + !__traits(compiles, castFrom!long.to!int(x)) + ); + + // if cast is still needed, must be changed to: + auto y = castFrom!(long*).to!int(x); + } +} + +@safe unittest +{ + import std.conv; + + // conversion at compile time + auto string1 = hexString!"304A314B"; + assert(string1 == "0J1K"); + auto string2 = hexString!"304A314B"w; + assert(string2 == "0J1K"w); + auto string3 = hexString!"304A314B"d; + assert(string3 == "0J1K"d); +} + +@safe unittest +{ + import std.conv; + + import std.algorithm.comparison : equal; + + assert(toChars(1).equal("1")); + assert(toChars(1_000_000).equal("1000000")); + + assert(toChars!(2)(2U).equal("10")); + assert(toChars!(16)(255U).equal("ff")); + assert(toChars!(16, char, LetterCase.upper)(255U).equal("FF")); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_csv.d b/libphobos/testsuite/libphobos.phobos/std_csv.d new file mode 100644 index 000000000000..e35df43da688 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_csv.d @@ -0,0 +1,228 @@ +@safe unittest +{ + import std.csv; + + import std.exception : collectException; + import std.algorithm.searching : count; + string text = "a,b,c\nHello,65"; + auto ex = collectException!CSVException(csvReader(text).count); + assert(ex.toString == "(Row: 0, Col: 0) Row 2's length 2 does not match previous length of 3."); +} + +@safe unittest +{ + import std.csv; + + import std.exception : collectException; + import std.algorithm.searching : count; + import std.typecons : Tuple; + string text = "a,b\nHello,65"; + auto ex = collectException!CSVException(csvReader!(Tuple!(string,int))(text).count); + assert(ex.toString == "(Row: 1, Col: 2) Unexpected 'b' when converting from type string to type int"); +} + +@safe unittest +{ + import std.csv; + + import std.exception : assertThrown; + string text = "a,\"b,c\nHello,65,2.5"; + assertThrown!IncompleteCellException(text.csvReader(["a","b","c"])); +} + +@safe unittest +{ + import std.csv; + + import std.exception : assertThrown; + string text = "a,b,c\nHello,65,2.5"; + assertThrown!HeaderMismatchException(text.csvReader(["b","c","invalid"])); +} + +@safe unittest +{ + import std.csv; + + import std.algorithm.comparison : equal; + import std.algorithm.searching : count; + import std.exception : assertThrown; + + string text = "a,b,c\nHello,65,\"2.5"; + assertThrown!IncompleteCellException(text.csvReader.count); + + // ignore the exceptions and try to handle invalid CSV + auto firstLine = text.csvReader!(string, Malformed.ignore)(null).front; + assert(firstLine.equal(["Hello", "65", "2.5"])); +} + +@safe unittest +{ + import std.csv; + + import std.algorithm.comparison : equal; + string text = "76,26,22"; + auto records = text.csvReader!int; + assert(records.equal!equal([ + [76, 26, 22], + ])); +} + +@safe unittest +{ + import std.csv; + + import std.algorithm.comparison : equal; + string text = "Hello;65;2.5\nWorld;123;7.5"; + struct Layout + { + string name; + int value; + double other; + } + + auto records = text.csvReader!Layout(';'); + assert(records.equal([ + Layout("Hello", 65, 2.5), + Layout("World", 123, 7.5), + ])); +} + +@safe unittest +{ + import std.csv; + + string text = "A \" is now part of the data"; + auto records = text.csvReader!(string, Malformed.ignore); + auto record = records.front; + + assert(record.front == text); +} + +@safe unittest +{ + import std.csv; + + import std.algorithm.comparison : equal; + string text = "a,b,c\nHello,65,63.63\nWorld,123,3673.562"; + auto records = text.csvReader!int(["b"]); + + assert(records.equal!equal([ + [65], + [123], + ])); +} + +@safe unittest +{ + import std.csv; + + import std.algorithm.comparison : equal; + string text = "a,b,c\nHello,65,2.5\nWorld,123,7.5"; + struct Layout + { + int value; + double other; + string name; + } + + auto records = text.csvReader!Layout(["b","c","a"]); + assert(records.equal([ + Layout(65, 2.5, "Hello"), + Layout(123, 7.5, "World") + ])); +} + +@safe unittest +{ + import std.csv; + + string text = "a,b,c\nHello,65,63.63"; + auto records = text.csvReader(null); + + assert(records.header == ["a","b","c"]); +} + +@safe unittest +{ + import std.csv; + + import std.algorithm.comparison : equal; + + string text = "76,26,22\n1,2\n3,4,5,6"; + auto records = text.csvReader!int(',', '"', true); + + assert(records.equal!equal([ + [76, 26, 22], + [1, 2], + [3, 4, 5, 6] + ])); +} + +@safe unittest +{ + import std.csv; + + import std.algorithm.comparison : equal; + + static struct Three + { + int a; + int b; + int c; + } + + string text = "76,26,22\n1,2\n3,4,5,6"; + auto records = text.csvReader!Three(',', '"', true); + + assert(records.equal([ + Three(76, 26, 22), + Three(1, 2, 0), + Three(3, 4, 5) + ])); +} + +@safe unittest +{ + import std.csv; + + import std.algorithm.comparison : equal; + + auto text = "Name,Occupation,Salary\r" ~ + "Joe,Carpenter,300000\nFred,Blacksmith\r\n"; + + auto r = csvReader!(string[string])(text, null, ',', '"', true); + + assert(r.equal([ + [ "Name" : "Joe", "Occupation" : "Carpenter", "Salary" : "300000" ], + [ "Name" : "Fred", "Occupation" : "Blacksmith" ] + ])); +} + +@safe unittest +{ + import std.csv; + + import std.array : appender; + import std.range.primitives : popFront; + + string str = "65,63\n123,3673"; + + auto a = appender!(char[])(); + + csvNextToken(str,a,',','"'); + assert(a.data == "65"); + assert(str == ",63\n123,3673"); + + str.popFront(); + a.shrinkTo(0); + csvNextToken(str,a,',','"'); + assert(a.data == "63"); + assert(str == "\n123,3673"); + + str.popFront(); + a.shrinkTo(0); + csvNextToken(str,a,',','"'); + assert(a.data == "123"); + assert(str == ",3673"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_datetime_date.d b/libphobos/testsuite/libphobos.phobos/std_datetime_date.d new file mode 100644 index 000000000000..0ecf625562af --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_datetime_date.d @@ -0,0 +1,992 @@ +@safe pure unittest +{ + import std.datetime.date; + + assert(Date(2018, 10, 1).month == Month.oct); + assert(DateTime(1, 1, 1).month == Month.jan); +} + +@safe pure unittest +{ + import std.datetime.date; + + assert(Date(2018, 10, 1).dayOfWeek == DayOfWeek.mon); + assert(DateTime(5, 5, 5).dayOfWeek == DayOfWeek.thu); +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).year == 1999); + assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).year == 2010); + assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).year == -7); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(0, 1, 1), TimeOfDay(12, 30, 33)).yearBC == 1); + assert(DateTime(Date(-1, 1, 1), TimeOfDay(10, 7, 2)).yearBC == 2); + assert(DateTime(Date(-100, 1, 1), TimeOfDay(4, 59, 0)).yearBC == 101); + +} + +@safe unittest +{ + import std.datetime.date; + + auto dt = DateTime(Date(2010, 1, 1), TimeOfDay(7, 30, 0)); + dt.yearBC = 1; + assert(dt == DateTime(Date(0, 1, 1), TimeOfDay(7, 30, 0))); + + dt.yearBC = 10; + assert(dt == DateTime(Date(-9, 1, 1), TimeOfDay(7, 30, 0))); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).month == 7); + assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).month == 10); + assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).month == 4); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).day == 6); + assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).day == 4); + assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).day == 5); + +} + +@safe unittest +{ + import std.datetime.date; + + auto dt1 = DateTime(2010, 1, 1, 12, 30, 33); + dt1.add!"months"(11); + assert(dt1 == DateTime(2010, 12, 1, 12, 30, 33)); + + auto dt2 = DateTime(2010, 1, 1, 12, 30, 33); + dt2.add!"months"(-11); + assert(dt2 == DateTime(2009, 2, 1, 12, 30, 33)); + + auto dt3 = DateTime(2000, 2, 29, 12, 30, 33); + dt3.add!"years"(1); + assert(dt3 == DateTime(2001, 3, 1, 12, 30, 33)); + + auto dt4 = DateTime(2000, 2, 29, 12, 30, 33); + dt4.add!"years"(1, AllowDayOverflow.no); + assert(dt4 == DateTime(2001, 2, 28, 12, 30, 33)); + +} + +@safe unittest +{ + import std.datetime.date; + + auto dt1 = DateTime(2010, 1, 1, 12, 33, 33); + dt1.roll!"months"(1); + assert(dt1 == DateTime(2010, 2, 1, 12, 33, 33)); + + auto dt2 = DateTime(2010, 1, 1, 12, 33, 33); + dt2.roll!"months"(-1); + assert(dt2 == DateTime(2010, 12, 1, 12, 33, 33)); + + auto dt3 = DateTime(1999, 1, 29, 12, 33, 33); + dt3.roll!"months"(1); + assert(dt3 == DateTime(1999, 3, 1, 12, 33, 33)); + + auto dt4 = DateTime(1999, 1, 29, 12, 33, 33); + dt4.roll!"months"(1, AllowDayOverflow.no); + assert(dt4 == DateTime(1999, 2, 28, 12, 33, 33)); + + auto dt5 = DateTime(2000, 2, 29, 12, 30, 33); + dt5.roll!"years"(1); + assert(dt5 == DateTime(2001, 3, 1, 12, 30, 33)); + + auto dt6 = DateTime(2000, 2, 29, 12, 30, 33); + dt6.roll!"years"(1, AllowDayOverflow.no); + assert(dt6 == DateTime(2001, 2, 28, 12, 30, 33)); + +} + +@safe unittest +{ + import std.datetime.date; + + auto dt1 = DateTime(2010, 1, 1, 11, 23, 12); + dt1.roll!"days"(1); + assert(dt1 == DateTime(2010, 1, 2, 11, 23, 12)); + dt1.roll!"days"(365); + assert(dt1 == DateTime(2010, 1, 26, 11, 23, 12)); + dt1.roll!"days"(-32); + assert(dt1 == DateTime(2010, 1, 25, 11, 23, 12)); + + auto dt2 = DateTime(2010, 7, 4, 12, 0, 0); + dt2.roll!"hours"(1); + assert(dt2 == DateTime(2010, 7, 4, 13, 0, 0)); + + auto dt3 = DateTime(2010, 1, 1, 0, 0, 0); + dt3.roll!"seconds"(-1); + assert(dt3 == DateTime(2010, 1, 1, 0, 0, 59)); + +} + +@safe unittest +{ + import std.datetime.date; + + import core.time : hours, seconds; + + assert(DateTime(2015, 12, 31, 23, 59, 59) + seconds(1) == + DateTime(2016, 1, 1, 0, 0, 0)); + + assert(DateTime(2015, 12, 31, 23, 59, 59) + hours(1) == + DateTime(2016, 1, 1, 0, 59, 59)); + + assert(DateTime(2016, 1, 1, 0, 0, 0) - seconds(1) == + DateTime(2015, 12, 31, 23, 59, 59)); + + assert(DateTime(2016, 1, 1, 0, 59, 59) - hours(1) == + DateTime(2015, 12, 31, 23, 59, 59)); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(1999, 2, 1, 12, 2, 3).diffMonths( + DateTime(1999, 1, 31, 23, 59, 59)) == 1); + + assert(DateTime(1999, 1, 31, 0, 0, 0).diffMonths( + DateTime(1999, 2, 1, 12, 3, 42)) == -1); + + assert(DateTime(1999, 3, 1, 5, 30, 0).diffMonths( + DateTime(1999, 1, 1, 2, 4, 7)) == 2); + + assert(DateTime(1999, 1, 1, 7, 2, 4).diffMonths( + DateTime(1999, 3, 31, 0, 30, 58)) == -2); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(1999, 1, 1), TimeOfDay(12, 22, 7)).dayOfYear == 1); + assert(DateTime(Date(1999, 12, 31), TimeOfDay(7, 2, 59)).dayOfYear == 365); + assert(DateTime(Date(2000, 12, 31), TimeOfDay(21, 20, 0)).dayOfYear == 366); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)).dayOfGregorianCal == 1); + assert(DateTime(Date(1, 12, 31), TimeOfDay(23, 59, 59)).dayOfGregorianCal == 365); + assert(DateTime(Date(2, 1, 1), TimeOfDay(2, 2, 2)).dayOfGregorianCal == 366); + + assert(DateTime(Date(0, 12, 31), TimeOfDay(7, 7, 7)).dayOfGregorianCal == 0); + assert(DateTime(Date(0, 1, 1), TimeOfDay(19, 30, 0)).dayOfGregorianCal == -365); + assert(DateTime(Date(-1, 12, 31), TimeOfDay(4, 7, 0)).dayOfGregorianCal == -366); + + assert(DateTime(Date(2000, 1, 1), TimeOfDay(9, 30, 20)).dayOfGregorianCal == 730_120); + assert(DateTime(Date(2010, 12, 31), TimeOfDay(15, 45, 50)).dayOfGregorianCal == 734_137); + +} + +@safe unittest +{ + import std.datetime.date; + + auto dt = DateTime(Date.init, TimeOfDay(12, 0, 0)); + dt.dayOfGregorianCal = 1; + assert(dt == DateTime(Date(1, 1, 1), TimeOfDay(12, 0, 0))); + + dt.dayOfGregorianCal = 365; + assert(dt == DateTime(Date(1, 12, 31), TimeOfDay(12, 0, 0))); + + dt.dayOfGregorianCal = 366; + assert(dt == DateTime(Date(2, 1, 1), TimeOfDay(12, 0, 0))); + + dt.dayOfGregorianCal = 0; + assert(dt == DateTime(Date(0, 12, 31), TimeOfDay(12, 0, 0))); + + dt.dayOfGregorianCal = -365; + assert(dt == DateTime(Date(-0, 1, 1), TimeOfDay(12, 0, 0))); + + dt.dayOfGregorianCal = -366; + assert(dt == DateTime(Date(-1, 12, 31), TimeOfDay(12, 0, 0))); + + dt.dayOfGregorianCal = 730_120; + assert(dt == DateTime(Date(2000, 1, 1), TimeOfDay(12, 0, 0))); + + dt.dayOfGregorianCal = 734_137; + assert(dt == DateTime(Date(2010, 12, 31), TimeOfDay(12, 0, 0))); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(1999, 1, 6), TimeOfDay(0, 0, 0)).endOfMonth == + DateTime(Date(1999, 1, 31), TimeOfDay(23, 59, 59))); + + assert(DateTime(Date(1999, 2, 7), TimeOfDay(19, 30, 0)).endOfMonth == + DateTime(Date(1999, 2, 28), TimeOfDay(23, 59, 59))); + + assert(DateTime(Date(2000, 2, 7), TimeOfDay(5, 12, 27)).endOfMonth == + DateTime(Date(2000, 2, 29), TimeOfDay(23, 59, 59))); + + assert(DateTime(Date(2000, 6, 4), TimeOfDay(12, 22, 9)).endOfMonth == + DateTime(Date(2000, 6, 30), TimeOfDay(23, 59, 59))); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(1999, 1, 6), TimeOfDay(0, 0, 0)).daysInMonth == 31); + assert(DateTime(Date(1999, 2, 7), TimeOfDay(19, 30, 0)).daysInMonth == 28); + assert(DateTime(Date(2000, 2, 7), TimeOfDay(5, 12, 27)).daysInMonth == 29); + assert(DateTime(Date(2000, 6, 4), TimeOfDay(12, 22, 9)).daysInMonth == 30); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(1, 1, 1), TimeOfDay(12, 7, 0)).isAD); + assert(DateTime(Date(2010, 12, 31), TimeOfDay(0, 0, 0)).isAD); + assert(!DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 59)).isAD); + assert(!DateTime(Date(-2010, 1, 1), TimeOfDay(2, 2, 2)).isAD); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toISOString() == + "20100704T070612"); + + assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toISOString() == + "19981225T021500"); + + assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toISOString() == + "00000105T230959"); + + assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toISOString() == + "-00040105T000002"); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toISOExtString() == + "2010-07-04T07:06:12"); + + assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toISOExtString() == + "1998-12-25T02:15:00"); + + assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toISOExtString() == + "0000-01-05T23:09:59"); + + assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toISOExtString() == + "-0004-01-05T00:00:02"); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toSimpleString() == + "2010-Jul-04 07:06:12"); + + assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toSimpleString() == + "1998-Dec-25 02:15:00"); + + assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toSimpleString() == + "0000-Jan-05 23:09:59"); + + assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toSimpleString() == + "-0004-Jan-05 00:00:02"); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime.fromISOString("20100704T070612") == + DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); + + assert(DateTime.fromISOString("19981225T021500") == + DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0))); + + assert(DateTime.fromISOString("00000105T230959") == + DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59))); + + assert(DateTime.fromISOString("-00040105T000002") == + DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2))); + + assert(DateTime.fromISOString(" 20100704T070612 ") == + DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime.fromISOExtString("2010-07-04T07:06:12") == + DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); + + assert(DateTime.fromISOExtString("1998-12-25T02:15:00") == + DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0))); + + assert(DateTime.fromISOExtString("0000-01-05T23:09:59") == + DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59))); + + assert(DateTime.fromISOExtString("-0004-01-05T00:00:02") == + DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2))); + + assert(DateTime.fromISOExtString(" 2010-07-04T07:06:12 ") == + DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(DateTime.fromSimpleString("2010-Jul-04 07:06:12") == + DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); + assert(DateTime.fromSimpleString("1998-Dec-25 02:15:00") == + DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0))); + assert(DateTime.fromSimpleString("0000-Jan-05 23:09:59") == + DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59))); + assert(DateTime.fromSimpleString("-0004-Jan-05 00:00:02") == + DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2))); + assert(DateTime.fromSimpleString(" 2010-Jul-04 07:06:12 ") == + DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); + +} + +@safe pure unittest +{ + import std.datetime.date; + + import core.time : days, seconds; + + auto dt = DateTime(2000, 6, 1, 10, 30, 0); + + assert(dt.date == Date(2000, 6, 1)); + assert(dt.timeOfDay == TimeOfDay(10, 30, 0)); + assert(dt.dayOfYear == 153); + assert(dt.dayOfWeek == DayOfWeek.thu); + + dt += 10.days + 100.seconds; + assert(dt == DateTime(2000, 6, 11, 10, 31, 40)); + + assert(dt.toISOExtString() == "2000-06-11T10:31:40"); + assert(dt.toISOString() == "20000611T103140"); + assert(dt.toSimpleString() == "2000-Jun-11 10:31:40"); + + assert(DateTime.fromISOExtString("2018-01-01T12:00:00") == DateTime(2018, 1, 1, 12, 0, 0)); + assert(DateTime.fromISOString("20180101T120000") == DateTime(2018, 1, 1, 12, 0, 0)); + assert(DateTime.fromSimpleString("2018-Jan-01 12:00:00") == DateTime(2018, 1, 1, 12, 0, 0)); +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(1999, 7, 6).year == 1999); + assert(Date(2010, 10, 4).year == 2010); + assert(Date(-7, 4, 5).year == -7); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(1999, 7, 6).year == 1999); + assert(Date(2010, 10, 4).year == 2010); + assert(Date(-7, 4, 5).year == -7); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(0, 1, 1).yearBC == 1); + assert(Date(-1, 1, 1).yearBC == 2); + assert(Date(-100, 1, 1).yearBC == 101); + +} + +@safe unittest +{ + import std.datetime.date; + + auto date = Date(2010, 1, 1); + date.yearBC = 1; + assert(date == Date(0, 1, 1)); + + date.yearBC = 10; + assert(date == Date(-9, 1, 1)); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(1999, 7, 6).month == 7); + assert(Date(2010, 10, 4).month == 10); + assert(Date(-7, 4, 5).month == 4); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(1999, 7, 6).day == 6); + assert(Date(2010, 10, 4).day == 4); + assert(Date(-7, 4, 5).day == 5); + +} + +@safe unittest +{ + import std.datetime.date; + + auto d1 = Date(2010, 1, 1); + d1.add!"months"(11); + assert(d1 == Date(2010, 12, 1)); + + auto d2 = Date(2010, 1, 1); + d2.add!"months"(-11); + assert(d2 == Date(2009, 2, 1)); + + auto d3 = Date(2000, 2, 29); + d3.add!"years"(1); + assert(d3 == Date(2001, 3, 1)); + + auto d4 = Date(2000, 2, 29); + d4.add!"years"(1, AllowDayOverflow.no); + assert(d4 == Date(2001, 2, 28)); + +} + +@safe unittest +{ + import std.datetime.date; + + auto d1 = Date(2010, 1, 1); + d1.roll!"months"(1); + assert(d1 == Date(2010, 2, 1)); + + auto d2 = Date(2010, 1, 1); + d2.roll!"months"(-1); + assert(d2 == Date(2010, 12, 1)); + + auto d3 = Date(1999, 1, 29); + d3.roll!"months"(1); + assert(d3 == Date(1999, 3, 1)); + + auto d4 = Date(1999, 1, 29); + d4.roll!"months"(1, AllowDayOverflow.no); + assert(d4 == Date(1999, 2, 28)); + + auto d5 = Date(2000, 2, 29); + d5.roll!"years"(1); + assert(d5 == Date(2001, 3, 1)); + + auto d6 = Date(2000, 2, 29); + d6.roll!"years"(1, AllowDayOverflow.no); + assert(d6 == Date(2001, 2, 28)); + +} + +@safe unittest +{ + import std.datetime.date; + + auto d = Date(2010, 1, 1); + d.roll!"days"(1); + assert(d == Date(2010, 1, 2)); + d.roll!"days"(365); + assert(d == Date(2010, 1, 26)); + d.roll!"days"(-32); + assert(d == Date(2010, 1, 25)); + +} + +@safe unittest +{ + import std.datetime.date; + + import core.time : days; + + assert(Date(2015, 12, 31) + days(1) == Date(2016, 1, 1)); + assert(Date(2004, 2, 26) + days(4) == Date(2004, 3, 1)); + + assert(Date(2016, 1, 1) - days(1) == Date(2015, 12, 31)); + assert(Date(2004, 3, 1) - days(4) == Date(2004, 2, 26)); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(1999, 2, 1).diffMonths(Date(1999, 1, 31)) == 1); + assert(Date(1999, 1, 31).diffMonths(Date(1999, 2, 1)) == -1); + assert(Date(1999, 3, 1).diffMonths(Date(1999, 1, 1)) == 2); + assert(Date(1999, 1, 1).diffMonths(Date(1999, 3, 31)) == -2); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(1999, 1, 1).dayOfYear == 1); + assert(Date(1999, 12, 31).dayOfYear == 365); + assert(Date(2000, 12, 31).dayOfYear == 366); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(1, 1, 1).dayOfGregorianCal == 1); + assert(Date(1, 12, 31).dayOfGregorianCal == 365); + assert(Date(2, 1, 1).dayOfGregorianCal == 366); + + assert(Date(0, 12, 31).dayOfGregorianCal == 0); + assert(Date(0, 1, 1).dayOfGregorianCal == -365); + assert(Date(-1, 12, 31).dayOfGregorianCal == -366); + + assert(Date(2000, 1, 1).dayOfGregorianCal == 730_120); + assert(Date(2010, 12, 31).dayOfGregorianCal == 734_137); + +} + +@safe unittest +{ + import std.datetime.date; + + auto date = Date.init; + date.dayOfGregorianCal = 1; + assert(date == Date(1, 1, 1)); + + date.dayOfGregorianCal = 365; + assert(date == Date(1, 12, 31)); + + date.dayOfGregorianCal = 366; + assert(date == Date(2, 1, 1)); + + date.dayOfGregorianCal = 0; + assert(date == Date(0, 12, 31)); + + date.dayOfGregorianCal = -365; + assert(date == Date(-0, 1, 1)); + + date.dayOfGregorianCal = -366; + assert(date == Date(-1, 12, 31)); + + date.dayOfGregorianCal = 730_120; + assert(date == Date(2000, 1, 1)); + + date.dayOfGregorianCal = 734_137; + assert(date == Date(2010, 12, 31)); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(1999, 1, 6).endOfMonth == Date(1999, 1, 31)); + assert(Date(1999, 2, 7).endOfMonth == Date(1999, 2, 28)); + assert(Date(2000, 2, 7).endOfMonth == Date(2000, 2, 29)); + assert(Date(2000, 6, 4).endOfMonth == Date(2000, 6, 30)); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(1999, 1, 6).daysInMonth == 31); + assert(Date(1999, 2, 7).daysInMonth == 28); + assert(Date(2000, 2, 7).daysInMonth == 29); + assert(Date(2000, 6, 4).daysInMonth == 30); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(1, 1, 1).isAD); + assert(Date(2010, 12, 31).isAD); + assert(!Date(0, 12, 31).isAD); + assert(!Date(-2010, 1, 1).isAD); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(2010, 7, 4).toISOString() == "20100704"); + assert(Date(1998, 12, 25).toISOString() == "19981225"); + assert(Date(0, 1, 5).toISOString() == "00000105"); + assert(Date(-4, 1, 5).toISOString() == "-00040105"); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(2010, 7, 4).toISOExtString() == "2010-07-04"); + assert(Date(1998, 12, 25).toISOExtString() == "1998-12-25"); + assert(Date(0, 1, 5).toISOExtString() == "0000-01-05"); + assert(Date(-4, 1, 5).toISOExtString() == "-0004-01-05"); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date(2010, 7, 4).toSimpleString() == "2010-Jul-04"); + assert(Date(1998, 12, 25).toSimpleString() == "1998-Dec-25"); + assert(Date(0, 1, 5).toSimpleString() == "0000-Jan-05"); + assert(Date(-4, 1, 5).toSimpleString() == "-0004-Jan-05"); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date.fromISOString("20100704") == Date(2010, 7, 4)); + assert(Date.fromISOString("19981225") == Date(1998, 12, 25)); + assert(Date.fromISOString("00000105") == Date(0, 1, 5)); + assert(Date.fromISOString("-00040105") == Date(-4, 1, 5)); + assert(Date.fromISOString(" 20100704 ") == Date(2010, 7, 4)); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date.fromISOExtString("2010-07-04") == Date(2010, 7, 4)); + assert(Date.fromISOExtString("1998-12-25") == Date(1998, 12, 25)); + assert(Date.fromISOExtString("0000-01-05") == Date(0, 1, 5)); + assert(Date.fromISOExtString("-0004-01-05") == Date(-4, 1, 5)); + assert(Date.fromISOExtString(" 2010-07-04 ") == Date(2010, 7, 4)); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(Date.fromSimpleString("2010-Jul-04") == Date(2010, 7, 4)); + assert(Date.fromSimpleString("1998-Dec-25") == Date(1998, 12, 25)); + assert(Date.fromSimpleString("0000-Jan-05") == Date(0, 1, 5)); + assert(Date.fromSimpleString("-0004-Jan-05") == Date(-4, 1, 5)); + assert(Date.fromSimpleString(" 2010-Jul-04 ") == Date(2010, 7, 4)); + +} + +@safe pure unittest +{ + import std.datetime.date; + + import core.time : days; + + auto d = Date(2000, 6, 1); + + assert(d.dayOfYear == 153); + assert(d.dayOfWeek == DayOfWeek.thu); + + d += 10.days; + assert(d == Date(2000, 6, 11)); + + assert(d.toISOExtString() == "2000-06-11"); + assert(d.toISOString() == "20000611"); + assert(d.toSimpleString() == "2000-Jun-11"); + + assert(Date.fromISOExtString("2018-01-01") == Date(2018, 1, 1)); + assert(Date.fromISOString("20180101") == Date(2018, 1, 1)); + assert(Date.fromSimpleString("2018-Jan-01") == Date(2018, 1, 1)); +} + +@safe unittest +{ + import std.datetime.date; + + auto tod1 = TimeOfDay(7, 12, 0); + tod1.roll!"hours"(1); + assert(tod1 == TimeOfDay(8, 12, 0)); + + auto tod2 = TimeOfDay(7, 12, 0); + tod2.roll!"hours"(-1); + assert(tod2 == TimeOfDay(6, 12, 0)); + + auto tod3 = TimeOfDay(23, 59, 0); + tod3.roll!"minutes"(1); + assert(tod3 == TimeOfDay(23, 0, 0)); + + auto tod4 = TimeOfDay(0, 0, 0); + tod4.roll!"minutes"(-1); + assert(tod4 == TimeOfDay(0, 59, 0)); + + auto tod5 = TimeOfDay(23, 59, 59); + tod5.roll!"seconds"(1); + assert(tod5 == TimeOfDay(23, 59, 0)); + + auto tod6 = TimeOfDay(0, 0, 0); + tod6.roll!"seconds"(-1); + assert(tod6 == TimeOfDay(0, 0, 59)); + +} + +@safe unittest +{ + import std.datetime.date; + + import core.time : hours, minutes, seconds; + + assert(TimeOfDay(12, 12, 12) + seconds(1) == TimeOfDay(12, 12, 13)); + assert(TimeOfDay(12, 12, 12) + minutes(1) == TimeOfDay(12, 13, 12)); + assert(TimeOfDay(12, 12, 12) + hours(1) == TimeOfDay(13, 12, 12)); + assert(TimeOfDay(23, 59, 59) + seconds(1) == TimeOfDay(0, 0, 0)); + + assert(TimeOfDay(12, 12, 12) - seconds(1) == TimeOfDay(12, 12, 11)); + assert(TimeOfDay(12, 12, 12) - minutes(1) == TimeOfDay(12, 11, 12)); + assert(TimeOfDay(12, 12, 12) - hours(1) == TimeOfDay(11, 12, 12)); + assert(TimeOfDay(0, 0, 0) - seconds(1) == TimeOfDay(23, 59, 59)); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(TimeOfDay(0, 0, 0).toISOString() == "000000"); + assert(TimeOfDay(12, 30, 33).toISOString() == "123033"); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(TimeOfDay(0, 0, 0).toISOExtString() == "00:00:00"); + assert(TimeOfDay(12, 30, 33).toISOExtString() == "12:30:33"); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(TimeOfDay.fromISOString("000000") == TimeOfDay(0, 0, 0)); + assert(TimeOfDay.fromISOString("123033") == TimeOfDay(12, 30, 33)); + assert(TimeOfDay.fromISOString(" 123033 ") == TimeOfDay(12, 30, 33)); + +} + +@safe unittest +{ + import std.datetime.date; + + assert(TimeOfDay.fromISOExtString("00:00:00") == TimeOfDay(0, 0, 0)); + assert(TimeOfDay.fromISOExtString("12:30:33") == TimeOfDay(12, 30, 33)); + assert(TimeOfDay.fromISOExtString(" 12:30:33 ") == TimeOfDay(12, 30, 33)); + +} + +@safe pure unittest +{ + import std.datetime.date; + + import core.time : minutes, seconds; + + auto t = TimeOfDay(12, 30, 0); + + t += 10.minutes + 100.seconds; + assert(t == TimeOfDay(12, 41, 40)); + + assert(t.toISOExtString() == "12:41:40"); + assert(t.toISOString() == "124140"); + + assert(TimeOfDay.fromISOExtString("15:00:00") == TimeOfDay(15, 0, 0)); + assert(TimeOfDay.fromISOString("015000") == TimeOfDay(1, 50, 0)); +} + +@safe unittest +{ + import std.datetime.date; + + assert(valid!"hours"(12)); + assert(!valid!"hours"(32)); + assert(valid!"months"(12)); + assert(!valid!"months"(13)); +} + +@safe pure nothrow @nogc unittest +{ + import std.datetime.date; + + assert(valid!"days"(2016, 2, 29)); + assert(!valid!"days"(2016, 2, 30)); + assert(valid!"days"(2017, 2, 20)); + assert(!valid!"days"(2017, 2, 29)); +} + +@safe pure unittest +{ + import std.datetime.date; + + import std.exception : assertThrown, assertNotThrown; + + assertNotThrown(enforceValid!"months"(10)); + assertNotThrown(enforceValid!"seconds"(40)); + + assertThrown!DateTimeException(enforceValid!"months"(0)); + assertThrown!DateTimeException(enforceValid!"hours"(24)); + assertThrown!DateTimeException(enforceValid!"minutes"(60)); + assertThrown!DateTimeException(enforceValid!"seconds"(60)); +} + +@safe pure unittest +{ + import std.datetime.date; + + import std.exception : assertThrown, assertNotThrown; + + assertNotThrown(enforceValid!"days"(2000, Month.jan, 1)); + // leap year + assertNotThrown(enforceValid!"days"(2000, Month.feb, 29)); + + assertThrown!DateTimeException(enforceValid!"days"(2001, Month.feb, 29)); + assertThrown!DateTimeException(enforceValid!"days"(2000, Month.jan, 32)); + assertThrown!DateTimeException(enforceValid!"days"(2000, Month.apr, 31)); +} + +@safe pure nothrow @nogc unittest +{ + import std.datetime.date; + + assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.mon) == 0); + assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sun) == 6); + assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.wed) == 2); +} + +@safe pure unittest +{ + import std.datetime.date; + + assert(monthsToMonth(Month.jan, Month.jan) == 0); + assert(monthsToMonth(Month.jan, Month.dec) == 11); + assert(monthsToMonth(Month.jul, Month.oct) == 3); +} + +@safe unittest +{ + import std.datetime.date; + + foreach (year; [1, 2, 100, 2001, 2002, 2003, 2005, 2006, 2007, 2009, 2010]) + { + assert(!yearIsLeapYear(year)); + assert(!yearIsLeapYear(-year)); + } + + foreach (year; [0, 4, 8, 400, 800, 1600, 1996, 2000, 2004, 2008, 2012]) + { + assert(yearIsLeapYear(year)); + assert(yearIsLeapYear(-year)); + } +} + +@safe unittest +{ + import std.datetime.date; + + import core.time : Duration; + import std.datetime.interval : Interval; + import std.datetime.systime : SysTime; + + static assert(isTimePoint!Date); + static assert(isTimePoint!DateTime); + static assert(isTimePoint!SysTime); + static assert(isTimePoint!TimeOfDay); + + static assert(!isTimePoint!int); + static assert(!isTimePoint!Duration); + static assert(!isTimePoint!(Interval!SysTime)); +} + +@safe @nogc nothrow unittest +{ + import std.datetime.date; + + assert(validTimeUnits("msecs", "seconds", "minutes")); + assert(validTimeUnits("days", "weeks", "months")); + assert(!validTimeUnits("ms", "seconds", "minutes")); +} + +@safe pure unittest +{ + import std.datetime.date; + + import std.exception : assertThrown; + + assert(cmpTimeUnits("hours", "hours") == 0); + assert(cmpTimeUnits("hours", "weeks") < 0); + assert(cmpTimeUnits("months", "seconds") > 0); + + assertThrown!DateTimeException(cmpTimeUnits("month", "second")); +} + +@safe pure unittest +{ + import std.datetime.date; + + static assert(CmpTimeUnits!("years", "weeks") > 0); + static assert(CmpTimeUnits!("days", "days") == 0); + static assert(CmpTimeUnits!("seconds", "hours") < 0); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_datetime_interval.d b/libphobos/testsuite/libphobos.phobos/std_datetime_interval.d new file mode 100644 index 000000000000..e741f3aeed16 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_datetime_interval.d @@ -0,0 +1,112 @@ +@system unittest +{ + import std.datetime.interval; + + import std.datetime.date : Date, DayOfWeek; + + auto interval = Interval!Date(Date(2010, 9, 2), Date(2010, 9, 27)); + auto func = everyDayOfWeek!Date(DayOfWeek.mon); + auto range = interval.fwdRange(func); + + // A Thursday. Using PopFirst.yes would have made this Date(2010, 9, 6). + assert(range.front == Date(2010, 9, 2)); + + range.popFront(); + assert(range.front == Date(2010, 9, 6)); + + range.popFront(); + assert(range.front == Date(2010, 9, 13)); + + range.popFront(); + assert(range.front == Date(2010, 9, 20)); + + range.popFront(); + assert(range.empty); +} + +@system unittest +{ + import std.datetime.interval; + + import std.datetime.date : Date, Month; + + auto interval = Interval!Date(Date(2000, 1, 30), Date(2004, 8, 5)); + auto func = everyMonth!Date(Month.feb); + auto range = interval.fwdRange(func); + + // Using PopFirst.yes would have made this Date(2010, 2, 29). + assert(range.front == Date(2000, 1, 30)); + + range.popFront(); + assert(range.front == Date(2000, 2, 29)); + + range.popFront(); + assert(range.front == Date(2001, 2, 28)); + + range.popFront(); + assert(range.front == Date(2002, 2, 28)); + + range.popFront(); + assert(range.front == Date(2003, 2, 28)); + + range.popFront(); + assert(range.front == Date(2004, 2, 28)); + + range.popFront(); + assert(range.empty); +} + +@system unittest +{ + import std.datetime.interval; + + import core.time : dur; + import std.datetime.date : Date; + + auto interval = Interval!Date(Date(2010, 9, 2), Date(2010, 9, 27)); + auto func = everyDuration!Date(dur!"days"(8)); + auto range = interval.fwdRange(func); + + // Using PopFirst.yes would have made this Date(2010, 9, 10). + assert(range.front == Date(2010, 9, 2)); + + range.popFront(); + assert(range.front == Date(2010, 9, 10)); + + range.popFront(); + assert(range.front == Date(2010, 9, 18)); + + range.popFront(); + assert(range.front == Date(2010, 9, 26)); + + range.popFront(); + assert(range.empty); +} + +@system unittest +{ + import std.datetime.interval; + + import core.time : dur; + import std.datetime.date : AllowDayOverflow, Date; + + auto interval = Interval!Date(Date(2010, 9, 2), Date(2025, 9, 27)); + auto func = everyDuration!Date(4, 1, AllowDayOverflow.yes, dur!"days"(2)); + auto range = interval.fwdRange(func); + + // Using PopFirst.yes would have made this Date(2014, 10, 12). + assert(range.front == Date(2010, 9, 2)); + + range.popFront(); + assert(range.front == Date(2014, 10, 4)); + + range.popFront(); + assert(range.front == Date(2018, 11, 6)); + + range.popFront(); + assert(range.front == Date(2022, 12, 8)); + + range.popFront(); + assert(range.empty); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_datetime_package.d b/libphobos/testsuite/libphobos.phobos/std_datetime_package.d new file mode 100644 index 000000000000..d40ad44f080e --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_datetime_package.d @@ -0,0 +1,34 @@ +@safe unittest +{ + import std.datetime; + + import std.datetime.systime : SysTime, Clock; + + SysTime currentTime = Clock.currTime(); +} + +@safe unittest +{ + import std.datetime; + + import std.datetime.date : DateTime; + + auto dt = DateTime(2018, 1, 1, 12, 30, 10); + assert(dt.toISOString() == "20180101T123010"); + assert(dt.toISOExtString() == "2018-01-01T12:30:10"); +} + +@safe unittest +{ + import std.datetime; + + import std.datetime.systime : SysTime; + import std.datetime.timezone : UTC; + import core.time : days; + + auto st = SysTime(DateTime(2018, 1, 1, 12, 30, 10), UTC()); + assert(st.toISOExtString() == "2018-01-01T12:30:10Z"); + st += 2.days; + assert(st.toISOExtString() == "2018-01-03T12:30:10Z"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_datetime_stopwatch.d b/libphobos/testsuite/libphobos.phobos/std_datetime_stopwatch.d new file mode 100644 index 000000000000..df58cb1c9413 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_datetime_stopwatch.d @@ -0,0 +1,210 @@ +@system nothrow @nogc unittest +{ + import std.datetime.stopwatch; + + import core.thread : Thread; + + { + auto sw = StopWatch(AutoStart.yes); + assert(sw.running); + Thread.sleep(usecs(1)); + assert(sw.peek() > Duration.zero); + } + { + auto sw = StopWatch(AutoStart.no); + assert(!sw.running); + Thread.sleep(usecs(1)); + assert(sw.peek() == Duration.zero); + } + { + StopWatch sw; + assert(!sw.running); + Thread.sleep(usecs(1)); + assert(sw.peek() == Duration.zero); + } + + assert(StopWatch.init == StopWatch(AutoStart.no)); + assert(StopWatch.init != StopWatch(AutoStart.yes)); + +} + +@system nothrow @nogc unittest +{ + import std.datetime.stopwatch; + + import core.thread : Thread; + + auto sw = StopWatch(AutoStart.yes); + Thread.sleep(usecs(1)); + sw.stop(); + assert(sw.peek() > Duration.zero); + sw.reset(); + assert(sw.peek() == Duration.zero); + +} + +@system nothrow @nogc unittest +{ + import std.datetime.stopwatch; + + import core.thread : Thread; + + StopWatch sw; + assert(!sw.running); + assert(sw.peek() == Duration.zero); + sw.start(); + assert(sw.running); + Thread.sleep(usecs(1)); + assert(sw.peek() > Duration.zero); + +} + +@system nothrow @nogc unittest +{ + import std.datetime.stopwatch; + + import core.thread : Thread; + + auto sw = StopWatch(AutoStart.yes); + assert(sw.running); + Thread.sleep(usecs(1)); + immutable t1 = sw.peek(); + assert(t1 > Duration.zero); + + sw.stop(); + assert(!sw.running); + immutable t2 = sw.peek(); + assert(t2 >= t1); + immutable t3 = sw.peek(); + assert(t2 == t3); + +} + +@system nothrow @nogc unittest +{ + import std.datetime.stopwatch; + + import core.thread : Thread; + + auto sw = StopWatch(AutoStart.no); + assert(sw.peek() == Duration.zero); + sw.start(); + + Thread.sleep(usecs(1)); + assert(sw.peek() >= usecs(1)); + + Thread.sleep(usecs(1)); + assert(sw.peek() >= usecs(2)); + + sw.stop(); + immutable stopped = sw.peek(); + Thread.sleep(usecs(1)); + assert(sw.peek() == stopped); + + sw.start(); + Thread.sleep(usecs(1)); + assert(sw.peek() > stopped); + +} + +@system nothrow @nogc unittest +{ + import std.datetime.stopwatch; + + import core.thread : Thread; + + StopWatch sw; + sw.setTimeElapsed(hours(1)); + + // As discussed in MonoTime's documentation, converting between + // Duration and ticks is not exact, though it will be close. + // How exact it is depends on the frequency/resolution of the + // system's monotonic clock. + assert(abs(sw.peek() - hours(1)) < usecs(1)); + + sw.start(); + Thread.sleep(usecs(1)); + assert(sw.peek() > hours(1) + usecs(1)); + +} + +@safe nothrow @nogc unittest +{ + import std.datetime.stopwatch; + + StopWatch sw; + assert(!sw.running); + sw.start(); + assert(sw.running); + sw.stop(); + assert(!sw.running); + +} + +@safe nothrow @nogc unittest +{ + import std.datetime.stopwatch; + + auto sw = StopWatch(AutoStart.no); + sw.start(); + // ... Insert operations to be timed here ... + sw.stop(); + + long msecs = sw.peek.total!"msecs"; + long usecs = sw.peek.total!"usecs"; + long nsecs = sw.peek.total!"nsecs"; + + assert(usecs >= msecs * 1000); + assert(nsecs >= usecs * 1000); +} + +@system nothrow @nogc unittest +{ + import std.datetime.stopwatch; + + import core.thread : Thread; + + auto sw = StopWatch(AutoStart.yes); + + Duration t1 = sw.peek(); + Thread.sleep(usecs(1)); + Duration t2 = sw.peek(); + assert(t2 > t1); + + Thread.sleep(usecs(1)); + sw.stop(); + + Duration t3 = sw.peek(); + assert(t3 > t2); + Duration t4 = sw.peek(); + assert(t3 == t4); + + sw.start(); + Thread.sleep(usecs(1)); + + Duration t5 = sw.peek(); + assert(t5 > t4); + + // If stopping or resetting the StopWatch is not required, then + // MonoTime can easily be used by itself without StopWatch. + auto before = MonoTime.currTime; + // do stuff... + auto timeElapsed = MonoTime.currTime - before; +} + +@safe unittest +{ + import std.datetime.stopwatch; + + import std.conv : to; + + int a; + void f0() {} + void f1() { auto b = a; } + void f2() { auto b = to!string(a); } + auto r = benchmark!(f0, f1, f2)(10_000); + Duration f0Result = r[0]; // time f0 took to run 10,000 times + Duration f1Result = r[1]; // time f1 took to run 10,000 times + Duration f2Result = r[2]; // time f2 took to run 10,000 times +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_datetime_systime.d b/libphobos/testsuite/libphobos.phobos/std_datetime_systime.d new file mode 100644 index 000000000000..a0f410374d6b --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_datetime_systime.d @@ -0,0 +1,750 @@ +@safe unittest +{ + import std.datetime.systime; + + import std.datetime.timezone : LocalTime; + SysTime today = Clock.currTime(); + assert(today.timezone is LocalTime()); +} + +@safe unittest +{ + import std.datetime.systime; + + import std.datetime.date : DateTime; + import std.datetime.timezone : UTC; + + auto st = SysTime.fromISOExtString("2018-01-01T10:30:00Z"); + assert(st == SysTime(DateTime(2018, 1, 1, 10, 30, 0), UTC())); +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : hours; + import std.datetime.date : DateTime; + import std.datetime.timezone : SimpleTimeZone; + + auto ny = SysTime( + DateTime(2018, 1, 1, 10, 30, 0), + new immutable SimpleTimeZone(-5.hours, "America/New_York") + ); + + // ISO standard time strings + assert(ny.toISOString() == "20180101T103000-05:00"); + assert(ny.toISOExtString() == "2018-01-01T10:30:00-05:00"); +} + +@safe unittest +{ + import std.datetime.systime; + + import std.datetime.timezone : LocalTime; + SysTime today = Clock.currTime(); + assert(today.timezone is LocalTime()); +} + +@safe unittest +{ + import std.datetime.systime; + + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).year == 1999); + assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).year == 2010); + assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).year == -7); + +} + +@safe unittest +{ + import std.datetime.systime; + + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(0, 1, 1, 12, 30, 33)).yearBC == 1); + assert(SysTime(DateTime(-1, 1, 1, 10, 7, 2)).yearBC == 2); + assert(SysTime(DateTime(-100, 1, 1, 4, 59, 0)).yearBC == 101); + +} + +@safe unittest +{ + import std.datetime.systime; + + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).month == 7); + assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).month == 10); + assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).month == 4); + +} + +@safe unittest +{ + import std.datetime.systime; + + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(1999, 7, 6, 9, 7, 5)).day == 6); + assert(SysTime(DateTime(2010, 10, 4, 0, 0, 30)).day == 4); + assert(SysTime(DateTime(-7, 4, 5, 7, 45, 2)).day == 5); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : msecs, usecs, hnsecs, nsecs; + import std.datetime.date : DateTime; + + auto dt = DateTime(1982, 4, 1, 20, 59, 22); + assert(SysTime(dt, msecs(213)).fracSecs == msecs(213)); + assert(SysTime(dt, usecs(5202)).fracSecs == usecs(5202)); + assert(SysTime(dt, hnsecs(1234567)).fracSecs == hnsecs(1234567)); + + // SysTime and Duration both have a precision of hnsecs (100 ns), + // so nsecs are going to be truncated. + assert(SysTime(dt, nsecs(123456789)).fracSecs == nsecs(123456700)); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : Duration, msecs, hnsecs, nsecs; + import std.datetime.date : DateTime; + + auto st = SysTime(DateTime(1982, 4, 1, 20, 59, 22)); + assert(st.fracSecs == Duration.zero); + + st.fracSecs = msecs(213); + assert(st.fracSecs == msecs(213)); + + st.fracSecs = hnsecs(1234567); + assert(st.fracSecs == hnsecs(1234567)); + + // SysTime has a precision of hnsecs (100 ns), so nsecs are + // going to be truncated. + st.fracSecs = nsecs(123456789); + assert(st.fracSecs == hnsecs(1234567)); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : hours; + import std.datetime.date : DateTime; + import std.datetime.timezone : SimpleTimeZone, UTC; + + assert(SysTime(DateTime(1970, 1, 1), UTC()).toUnixTime() == 0); + + auto pst = new immutable SimpleTimeZone(hours(-8)); + assert(SysTime(DateTime(1970, 1, 1), pst).toUnixTime() == 28800); + + auto utc = SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC()); + assert(utc.toUnixTime() == 1_198_311_285); + + auto ca = SysTime(DateTime(2007, 12, 22, 8, 14, 45), pst); + assert(ca.toUnixTime() == 1_198_340_085); + + static void testScope(scope ref SysTime st) @safe + { + auto result = st.toUnixTime(); + } + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : hours; + import std.datetime.date : DateTime; + import std.datetime.timezone : SimpleTimeZone, UTC; + + assert(SysTime.fromUnixTime(0) == + SysTime(DateTime(1970, 1, 1), UTC())); + + auto pst = new immutable SimpleTimeZone(hours(-8)); + assert(SysTime.fromUnixTime(28800) == + SysTime(DateTime(1970, 1, 1), pst)); + + auto st1 = SysTime.fromUnixTime(1_198_311_285, UTC()); + assert(st1 == SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC())); + assert(st1.timezone is UTC()); + assert(st1 == SysTime(DateTime(2007, 12, 22, 0, 14, 45), pst)); + + auto st2 = SysTime.fromUnixTime(1_198_311_285, pst); + assert(st2 == SysTime(DateTime(2007, 12, 22, 8, 14, 45), UTC())); + assert(st2.timezone is pst); + assert(st2 == SysTime(DateTime(2007, 12, 22, 0, 14, 45), pst)); + +} + +@safe unittest +{ + import std.datetime.systime; + + import std.datetime.date : AllowDayOverflow, DateTime; + + auto st1 = SysTime(DateTime(2010, 1, 1, 12, 33, 33)); + st1.roll!"months"(1); + assert(st1 == SysTime(DateTime(2010, 2, 1, 12, 33, 33))); + + auto st2 = SysTime(DateTime(2010, 1, 1, 12, 33, 33)); + st2.roll!"months"(-1); + assert(st2 == SysTime(DateTime(2010, 12, 1, 12, 33, 33))); + + auto st3 = SysTime(DateTime(1999, 1, 29, 12, 33, 33)); + st3.roll!"months"(1); + assert(st3 == SysTime(DateTime(1999, 3, 1, 12, 33, 33))); + + auto st4 = SysTime(DateTime(1999, 1, 29, 12, 33, 33)); + st4.roll!"months"(1, AllowDayOverflow.no); + assert(st4 == SysTime(DateTime(1999, 2, 28, 12, 33, 33))); + + auto st5 = SysTime(DateTime(2000, 2, 29, 12, 30, 33)); + st5.roll!"years"(1); + assert(st5 == SysTime(DateTime(2001, 3, 1, 12, 30, 33))); + + auto st6 = SysTime(DateTime(2000, 2, 29, 12, 30, 33)); + st6.roll!"years"(1, AllowDayOverflow.no); + assert(st6 == SysTime(DateTime(2001, 2, 28, 12, 30, 33))); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : msecs, hnsecs; + import std.datetime.date : DateTime; + + auto st1 = SysTime(DateTime(2010, 1, 1, 11, 23, 12)); + st1.roll!"days"(1); + assert(st1 == SysTime(DateTime(2010, 1, 2, 11, 23, 12))); + st1.roll!"days"(365); + assert(st1 == SysTime(DateTime(2010, 1, 26, 11, 23, 12))); + st1.roll!"days"(-32); + assert(st1 == SysTime(DateTime(2010, 1, 25, 11, 23, 12))); + + auto st2 = SysTime(DateTime(2010, 7, 4, 12, 0, 0)); + st2.roll!"hours"(1); + assert(st2 == SysTime(DateTime(2010, 7, 4, 13, 0, 0))); + + auto st3 = SysTime(DateTime(2010, 2, 12, 12, 0, 0)); + st3.roll!"hours"(-1); + assert(st3 == SysTime(DateTime(2010, 2, 12, 11, 0, 0))); + + auto st4 = SysTime(DateTime(2009, 12, 31, 0, 0, 0)); + st4.roll!"minutes"(1); + assert(st4 == SysTime(DateTime(2009, 12, 31, 0, 1, 0))); + + auto st5 = SysTime(DateTime(2010, 1, 1, 0, 0, 0)); + st5.roll!"minutes"(-1); + assert(st5 == SysTime(DateTime(2010, 1, 1, 0, 59, 0))); + + auto st6 = SysTime(DateTime(2009, 12, 31, 0, 0, 0)); + st6.roll!"seconds"(1); + assert(st6 == SysTime(DateTime(2009, 12, 31, 0, 0, 1))); + + auto st7 = SysTime(DateTime(2010, 1, 1, 0, 0, 0)); + st7.roll!"seconds"(-1); + assert(st7 == SysTime(DateTime(2010, 1, 1, 0, 0, 59))); + + auto dt = DateTime(2010, 1, 1, 0, 0, 0); + auto st8 = SysTime(dt); + st8.roll!"msecs"(1); + assert(st8 == SysTime(dt, msecs(1))); + + auto st9 = SysTime(dt); + st9.roll!"msecs"(-1); + assert(st9 == SysTime(dt, msecs(999))); + + auto st10 = SysTime(dt); + st10.roll!"hnsecs"(1); + assert(st10 == SysTime(dt, hnsecs(1))); + + auto st11 = SysTime(dt); + st11.roll!"hnsecs"(-1); + assert(st11 == SysTime(dt, hnsecs(9_999_999))); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : hours, seconds; + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(2015, 12, 31, 23, 59, 59)) + seconds(1) == + SysTime(DateTime(2016, 1, 1, 0, 0, 0))); + + assert(SysTime(DateTime(2015, 12, 31, 23, 59, 59)) + hours(1) == + SysTime(DateTime(2016, 1, 1, 0, 59, 59))); + + assert(SysTime(DateTime(2016, 1, 1, 0, 0, 0)) - seconds(1) == + SysTime(DateTime(2015, 12, 31, 23, 59, 59))); + + assert(SysTime(DateTime(2016, 1, 1, 0, 59, 59)) - hours(1) == + SysTime(DateTime(2015, 12, 31, 23, 59, 59))); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time; + import std.datetime.date : Date; + + assert(SysTime(Date(1999, 2, 1)).diffMonths( + SysTime(Date(1999, 1, 31))) == 1); + + assert(SysTime(Date(1999, 1, 31)).diffMonths( + SysTime(Date(1999, 2, 1))) == -1); + + assert(SysTime(Date(1999, 3, 1)).diffMonths( + SysTime(Date(1999, 1, 1))) == 2); + + assert(SysTime(Date(1999, 1, 1)).diffMonths( + SysTime(Date(1999, 3, 31))) == -2); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time; + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(1999, 1, 1, 12, 22, 7)).dayOfYear == 1); + assert(SysTime(DateTime(1999, 12, 31, 7, 2, 59)).dayOfYear == 365); + assert(SysTime(DateTime(2000, 12, 31, 21, 20, 0)).dayOfYear == 366); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time; + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(1, 1, 1, 0, 0, 0)).dayOfGregorianCal == 1); + assert(SysTime(DateTime(1, 12, 31, 23, 59, 59)).dayOfGregorianCal == 365); + assert(SysTime(DateTime(2, 1, 1, 2, 2, 2)).dayOfGregorianCal == 366); + + assert(SysTime(DateTime(0, 12, 31, 7, 7, 7)).dayOfGregorianCal == 0); + assert(SysTime(DateTime(0, 1, 1, 19, 30, 0)).dayOfGregorianCal == -365); + assert(SysTime(DateTime(-1, 12, 31, 4, 7, 0)).dayOfGregorianCal == -366); + + assert(SysTime(DateTime(2000, 1, 1, 9, 30, 20)).dayOfGregorianCal == 730_120); + assert(SysTime(DateTime(2010, 12, 31, 15, 45, 50)).dayOfGregorianCal == 734_137); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time; + import std.datetime.date : DateTime; + + auto st = SysTime(DateTime(0, 1, 1, 12, 0, 0)); + st.dayOfGregorianCal = 1; + assert(st == SysTime(DateTime(1, 1, 1, 12, 0, 0))); + + st.dayOfGregorianCal = 365; + assert(st == SysTime(DateTime(1, 12, 31, 12, 0, 0))); + + st.dayOfGregorianCal = 366; + assert(st == SysTime(DateTime(2, 1, 1, 12, 0, 0))); + + st.dayOfGregorianCal = 0; + assert(st == SysTime(DateTime(0, 12, 31, 12, 0, 0))); + + st.dayOfGregorianCal = -365; + assert(st == SysTime(DateTime(-0, 1, 1, 12, 0, 0))); + + st.dayOfGregorianCal = -366; + assert(st == SysTime(DateTime(-1, 12, 31, 12, 0, 0))); + + st.dayOfGregorianCal = 730_120; + assert(st == SysTime(DateTime(2000, 1, 1, 12, 0, 0))); + + st.dayOfGregorianCal = 734_137; + assert(st == SysTime(DateTime(2010, 12, 31, 12, 0, 0))); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time; + import std.datetime.date : Date; + + auto st = SysTime(Date(1999, 7, 6)); + const cst = SysTime(Date(2010, 5, 1)); + immutable ist = SysTime(Date(2015, 10, 10)); + + assert(st.isoWeek == 27); + assert(cst.isoWeek == 17); + assert(ist.isoWeek == 41); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : msecs, usecs, hnsecs; + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).endOfMonth == + SysTime(DateTime(1999, 1, 31, 23, 59, 59), hnsecs(9_999_999))); + + assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0), msecs(24)).endOfMonth == + SysTime(DateTime(1999, 2, 28, 23, 59, 59), hnsecs(9_999_999))); + + assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27), usecs(5203)).endOfMonth == + SysTime(DateTime(2000, 2, 29, 23, 59, 59), hnsecs(9_999_999))); + + assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9), hnsecs(12345)).endOfMonth == + SysTime(DateTime(2000, 6, 30, 23, 59, 59), hnsecs(9_999_999))); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time; + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(1999, 1, 6, 0, 0, 0)).daysInMonth == 31); + assert(SysTime(DateTime(1999, 2, 7, 19, 30, 0)).daysInMonth == 28); + assert(SysTime(DateTime(2000, 2, 7, 5, 12, 27)).daysInMonth == 29); + assert(SysTime(DateTime(2000, 6, 4, 12, 22, 9)).daysInMonth == 30); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time; + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(1, 1, 1, 12, 7, 0)).isAD); + assert(SysTime(DateTime(2010, 12, 31, 0, 0, 0)).isAD); + assert(!SysTime(DateTime(0, 12, 31, 23, 59, 59)).isAD); + assert(!SysTime(DateTime(-2010, 1, 1, 2, 2, 2)).isAD); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : msecs, hnsecs; + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOString() == + "20100704T070612"); + + assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toISOString() == + "19981225T021500.024"); + + assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOString() == + "00000105T230959"); + + assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOString() == + "-00040105T000002.052092"); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : msecs, hnsecs; + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toISOExtString() == + "2010-07-04T07:06:12"); + + assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toISOExtString() == + "1998-12-25T02:15:00.024"); + + assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toISOExtString() == + "0000-01-05T23:09:59"); + + assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString() == + "-0004-01-05T00:00:02.052092"); + + assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString(4) == + "-0004-01-05T00:00:02.0520"); + + assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString(2) == + "-0004-01-05T00:00:02.05"); + + assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toISOExtString(7) == + "-0004-01-05T00:00:02.0520920"); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : msecs, hnsecs; + import std.datetime.date : DateTime; + + assert(SysTime(DateTime(2010, 7, 4, 7, 6, 12)).toSimpleString() == + "2010-Jul-04 07:06:12"); + + assert(SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(24)).toSimpleString() == + "1998-Dec-25 02:15:00.024"); + + assert(SysTime(DateTime(0, 1, 5, 23, 9, 59)).toSimpleString() == + "0000-Jan-05 23:09:59"); + + assert(SysTime(DateTime(-4, 1, 5, 0, 0, 2), hnsecs(520_920)).toSimpleString() == + "-0004-Jan-05 00:00:02.052092"); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : hours, msecs, usecs, hnsecs; + import std.datetime.date : DateTime; + import std.datetime.timezone : SimpleTimeZone, UTC; + + assert(SysTime.fromISOString("20100704T070612") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12))); + + assert(SysTime.fromISOString("19981225T021500.007") == + SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7))); + + assert(SysTime.fromISOString("00000105T230959.00002") == + SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20))); + + assert(SysTime.fromISOString("20130207T043937.000050392") == + SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503))); + + assert(SysTime.fromISOString("-00040105T000002") == + SysTime(DateTime(-4, 1, 5, 0, 0, 2))); + + assert(SysTime.fromISOString(" 20100704T070612 ") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12))); + + assert(SysTime.fromISOString("20100704T070612Z") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC())); + + assert(SysTime.fromISOString("20100704T070612-0800") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12), + new immutable SimpleTimeZone(hours(-8)))); + + assert(SysTime.fromISOString("20100704T070612+0800") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12), + new immutable SimpleTimeZone(hours(8)))); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : hours, msecs, usecs, hnsecs; + import std.datetime.date : DateTime; + import std.datetime.timezone : SimpleTimeZone, UTC; + + assert(SysTime.fromISOExtString("2010-07-04T07:06:12") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12))); + + assert(SysTime.fromISOExtString("1998-12-25T02:15:00.007") == + SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7))); + + assert(SysTime.fromISOExtString("0000-01-05T23:09:59.00002") == + SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20))); + + assert(SysTime.fromISOExtString("2013-02-07T04:39:37.000050392") == + SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503))); + + assert(SysTime.fromISOExtString("-0004-01-05T00:00:02") == + SysTime(DateTime(-4, 1, 5, 0, 0, 2))); + + assert(SysTime.fromISOExtString(" 2010-07-04T07:06:12 ") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12))); + + assert(SysTime.fromISOExtString("2010-07-04T07:06:12Z") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC())); + + assert(SysTime.fromISOExtString("2010-07-04T07:06:12-08:00") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12), + new immutable SimpleTimeZone(hours(-8)))); + assert(SysTime.fromISOExtString("2010-07-04T07:06:12+08:00") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12), + new immutable SimpleTimeZone(hours(8)))); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : hours, msecs, usecs, hnsecs; + import std.datetime.date : DateTime; + import std.datetime.timezone : SimpleTimeZone, UTC; + + assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12))); + + assert(SysTime.fromSimpleString("1998-Dec-25 02:15:00.007") == + SysTime(DateTime(1998, 12, 25, 2, 15, 0), msecs(7))); + + assert(SysTime.fromSimpleString("0000-Jan-05 23:09:59.00002") == + SysTime(DateTime(0, 1, 5, 23, 9, 59), usecs(20))); + + assert(SysTime.fromSimpleString("2013-Feb-07 04:39:37.000050392") == + SysTime(DateTime(2013, 2, 7, 4, 39, 37), hnsecs(503))); + + assert(SysTime.fromSimpleString("-0004-Jan-05 00:00:02") == + SysTime(DateTime(-4, 1, 5, 0, 0, 2))); + + assert(SysTime.fromSimpleString(" 2010-Jul-04 07:06:12 ") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12))); + + assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12Z") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12), UTC())); + + assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12-08:00") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12), + new immutable SimpleTimeZone(hours(-8)))); + + assert(SysTime.fromSimpleString("2010-Jul-04 07:06:12+08:00") == + SysTime(DateTime(2010, 7, 4, 7, 6, 12), + new immutable SimpleTimeZone(hours(8)))); + +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : days, hours, seconds; + import std.datetime.date : Date, DateTime; + import std.datetime.timezone : SimpleTimeZone, UTC; + + const dt = DateTime(2018, 1, 1, 10, 30, 0); + // make a specific point in time in the UTC timezone + auto st = SysTime(dt, UTC()); + assert(st.year == 2018); + assert(st.hour == 10); + + // cast to convert + assert(cast(DateTime) st == dt); + assert(cast(Date) st == Date(2018, 1, 1)); + + // make a specific point in time in the New York timezone + const ny = SysTime(dt, + new immutable SimpleTimeZone(-5.hours, "America/New_York") + ); + assert(ny != st); + assert(ny.hour == 10); + + // ISO standard time strings + assert(st.toISOString() == "20180101T103000Z"); + assert(st.toISOExtString() == "2018-01-01T10:30:00Z"); + + // add two days and 30 seconds + st += 2.days + 30.seconds; + assert(st.toISOExtString() == "2018-01-03T10:30:30Z"); +} + +@safe unittest +{ + import std.datetime.systime; + + import std.datetime.date : DateTime; + import std.datetime.timezone : UTC; + + // Midnight, January 1st, 1970 + assert(unixTimeToStdTime(0) == 621_355_968_000_000_000L); + assert(SysTime(unixTimeToStdTime(0)) == + SysTime(DateTime(1970, 1, 1), UTC())); + + assert(unixTimeToStdTime(int.max) == 642_830_804_470_000_000L); + assert(SysTime(unixTimeToStdTime(int.max)) == + SysTime(DateTime(2038, 1, 19, 3, 14, 7), UTC())); + + assert(unixTimeToStdTime(-127_127) == 621_354_696_730_000_000L); + assert(SysTime(unixTimeToStdTime(-127_127)) == + SysTime(DateTime(1969, 12, 30, 12, 41, 13), UTC())); +} + +@safe unittest +{ + import std.datetime.systime; + + // Midnight, January 1st, 1970 UTC + assert(stdTimeToUnixTime(621_355_968_000_000_000L) == 0); + + // 2038-01-19 03:14:07 UTC + assert(stdTimeToUnixTime(642_830_804_470_000_000L) == int.max); +} + +@safe unittest +{ + import std.datetime.systime; + + import std.datetime.date : DateTime; + + assert(DosFileTimeToSysTime(0b00000000001000010000000000000000) == SysTime(DateTime(1980, 1, 1, 0, 0, 0))); + assert(DosFileTimeToSysTime(0b11111111100111111011111101111101) == SysTime(DateTime(2107, 12, 31, 23, 59, 58))); + assert(DosFileTimeToSysTime(0x3E3F8456) == SysTime(DateTime(2011, 1, 31, 16, 34, 44))); +} + +@safe unittest +{ + import std.datetime.systime; + + import std.datetime.date : DateTime; + + assert(SysTimeToDosFileTime(SysTime(DateTime(1980, 1, 1, 0, 0, 0))) == 0b00000000001000010000000000000000); + assert(SysTimeToDosFileTime(SysTime(DateTime(2107, 12, 31, 23, 59, 58))) == 0b11111111100111111011111101111101); + assert(SysTimeToDosFileTime(SysTime(DateTime(2011, 1, 31, 16, 34, 44))) == 0x3E3F8456); +} + +@safe unittest +{ + import std.datetime.systime; + + import core.time : hours; + import std.datetime.date : DateTime, DateTimeException; + import std.datetime.timezone : SimpleTimeZone, UTC; + import std.exception : assertThrown; + + auto tz = new immutable SimpleTimeZone(hours(-8)); + assert(parseRFC822DateTime("Sat, 6 Jan 1990 12:14:19 -0800") == + SysTime(DateTime(1990, 1, 6, 12, 14, 19), tz)); + + assert(parseRFC822DateTime("9 Jul 2002 13:11 +0000") == + SysTime(DateTime(2002, 7, 9, 13, 11, 0), UTC())); + + auto badStr = "29 Feb 2001 12:17:16 +0200"; + assertThrown!DateTimeException(parseRFC822DateTime(badStr)); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_datetime_timezone.d b/libphobos/testsuite/libphobos.phobos/std_datetime_timezone.d new file mode 100644 index 000000000000..007902c339ec --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_datetime_timezone.d @@ -0,0 +1,15 @@ +@safe unittest +{ + import std.datetime.timezone; + + version (Posix) + { + auto tz = PosixTimeZone.getTimeZone("America/Los_Angeles"); + + assert(tz.name == "America/Los_Angeles"); + assert(tz.stdName == "PST"); + assert(tz.dstName == "PDT"); + } + +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_demangle.d b/libphobos/testsuite/libphobos.phobos/std_demangle.d new file mode 100644 index 000000000000..7ec7843a7c6b --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_demangle.d @@ -0,0 +1,33 @@ +@safe pure unittest +{ + import std.demangle; + + // int b in module a + assert(demangle("_D1a1bi") == "int a.b"); + // char array foo in module test + assert(demangle("_D4test3fooAa") == "char[] test.foo"); +} + +@system unittest +{ + import std.demangle; + + import std.ascii : isAlphaNum; + import std.algorithm.iteration : chunkBy, joiner, map; + import std.algorithm.mutation : copy; + import std.conv : to; + import std.demangle : demangle; + import std.functional : pipe; + import std.stdio : stdin, stdout; + + void main() + { + stdin.byLineCopy + .map!( + l => l.chunkBy!(a => isAlphaNum(a) || a == '_') + .map!(a => a[1].pipe!(to!string, demangle)).joiner + ) + .copy(stdout.lockingTextWriter); + } +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_digest_crc.d b/libphobos/testsuite/libphobos.phobos/std_digest_crc.d new file mode 100644 index 000000000000..9ca8dd698f7d --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_digest_crc.d @@ -0,0 +1,207 @@ +@safe unittest +{ + import std.digest.crc; + + //Template API + import std.digest.crc; + + ubyte[4] hash = crc32Of("The quick brown fox jumps over the lazy dog"); + assert(crcHexString(hash) == "414FA339"); + + //Feeding data + ubyte[1024] data; + CRC32 crc; + crc.put(data[]); + crc.start(); //Start again + crc.put(data[]); + hash = crc.finish(); +} + +@safe unittest +{ + import std.digest.crc; + + //OOP API + import std.digest.crc; + + auto crc = new CRC32Digest(); + ubyte[] hash = crc.digest("The quick brown fox jumps over the lazy dog"); + assert(crcHexString(hash) == "414FA339"); //352441c2 + + //Feeding data + ubyte[1024] data; + crc.put(data[]); + crc.reset(); //Start again + crc.put(data[]); + hash = crc.finish(); +} + +@safe unittest +{ + import std.digest.crc; + + //Simple example, hashing a string using crc32Of helper function + ubyte[4] hash32 = crc32Of("abc"); + //Let's get a hash string + assert(crcHexString(hash32) == "352441C2"); + // Repeat for CRC64 + ubyte[8] hash64ecma = crc64ECMAOf("abc"); + assert(crcHexString(hash64ecma) == "2CD8094A1A277627"); + ubyte[8] hash64iso = crc64ISOOf("abc"); + assert(crcHexString(hash64iso) == "3776C42000000000"); +} + +@safe unittest +{ + import std.digest.crc; + + ubyte[1024] data; + //Using the basic API + CRC32 hash32; + CRC64ECMA hash64ecma; + CRC64ISO hash64iso; + //Initialize data here... + hash32.put(data); + ubyte[4] result32 = hash32.finish(); + hash64ecma.put(data); + ubyte[8] result64ecma = hash64ecma.finish(); + hash64iso.put(data); + ubyte[8] result64iso = hash64iso.finish(); +} + +@safe unittest +{ + import std.digest.crc; + + //Let's use the template features: + //Note: When passing a CRC32 to a function, it must be passed by reference! + void doSomething(T)(ref T hash) + if (isDigest!T) + { + hash.put(cast(ubyte) 0); + } + CRC32 crc32; + crc32.start(); + doSomething(crc32); + assert(crcHexString(crc32.finish()) == "D202EF8D"); + // repeat for CRC64 + CRC64ECMA crc64ecma; + crc64ecma.start(); + doSomething(crc64ecma); + assert(crcHexString(crc64ecma.finish()) == "1FADA17364673F59"); + CRC64ISO crc64iso; + crc64iso.start(); + doSomething(crc64iso); + assert(crcHexString(crc64iso.finish()) == "6F90000000000000"); +} + +@system unittest +{ + import std.digest.crc; + + ubyte[] data = [4,5,7,25]; + assert(data.crc32Of == [167, 180, 199, 131]); + + import std.utf : byChar; + assert("hello"d.byChar.crc32Of == [134, 166, 16, 54]); + + ubyte[4] hash = "abc".crc32Of(); + assert(hash == digest!CRC32("ab", "c")); + + import std.range : iota; + enum ubyte S = 5, F = 66; + assert(iota(S, F).crc32Of == [59, 140, 234, 154]); +} + +@system unittest +{ + import std.digest.crc; + + ubyte[] data = [4,5,7,25]; + assert(data.crc64ECMAOf == [58, 142, 220, 214, 118, 98, 105, 69]); + + import std.utf : byChar; + assert("hello"d.byChar.crc64ECMAOf == [177, 55, 185, 219, 229, 218, 30, 155]); + + ubyte[8] hash = "abc".crc64ECMAOf(); + assert("abc".crc64ECMAOf == [39, 118, 39, 26, 74, 9, 216, 44]); + assert(hash == digest!CRC64ECMA("ab", "c")); + + import std.range : iota; + enum ubyte S = 5, F = 66; + assert(iota(S, F).crc64ECMAOf == [6, 184, 91, 238, 46, 213, 127, 188]); +} + +@system unittest +{ + import std.digest.crc; + + ubyte[] data = [4,5,7,25]; + assert(data.crc64ISOOf == [0, 0, 0, 80, 137, 232, 203, 120]); + + import std.utf : byChar; + assert("hello"d.byChar.crc64ISOOf == [0, 0, 16, 216, 226, 238, 62, 60]); + + ubyte[8] hash = "abc".crc64ISOOf(); + assert("abc".crc64ISOOf == [0, 0, 0, 0, 32, 196, 118, 55]); + assert(hash == digest!CRC64ISO("ab", "c")); + + import std.range : iota; + enum ubyte S = 5, F = 66; + + assert(iota(S, F).crc64ISOOf == [21, 185, 116, 95, 219, 11, 54, 7]); +} + +@safe unittest +{ + import std.digest.crc; + + //Simple example, hashing a string using CRC32Digest.digest helper function + auto crc = new CRC32Digest(); + ubyte[] hash = crc.digest("abc"); + //Let's get a hash string + assert(crcHexString(hash) == "352441C2"); +} + +@system unittest +{ + import std.digest.crc; + + //Let's use the OOP features: + void test(Digest dig) + { + dig.put(cast(ubyte) 0); + } + auto crc = new CRC32Digest(); + test(crc); + + //Let's use a custom buffer: + ubyte[4] buf; + ubyte[] result = crc.finish(buf[]); + assert(crcHexString(result) == "D202EF8D"); +} + +@safe unittest +{ + import std.digest.crc; + + //Simple example + auto hash = new CRC32Digest(); + hash.put(cast(ubyte) 0); + ubyte[] result = hash.finish(); +} + +@system unittest +{ + import std.digest.crc; + + //using a supplied buffer + ubyte[4] buf; + auto hash = new CRC32Digest(); + hash.put(cast(ubyte) 0); + ubyte[] result = hash.finish(buf[]); + //The result is now in result (and in buf. If you pass a buffer which is bigger than + //necessary, result will have the correct length, but buf will still have it's original + //length) +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_digest_hmac.d b/libphobos/testsuite/libphobos.phobos/std_digest_hmac.d new file mode 100644 index 000000000000..db5fb9720782 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_digest_hmac.d @@ -0,0 +1,145 @@ +@safe unittest +{ + import std.digest.hmac; + + import std.ascii : LetterCase; + import std.digest : toHexString; + import std.digest.sha : SHA1; + import std.string : representation; + + auto secret = "secret".representation; + assert("The quick brown fox jumps over the lazy dog" + .representation + .hmac!SHA1(secret) + .toHexString!(LetterCase.lower) == "198ea1ea04c435c1246b586a06d5cf11c3ffcda6"); +} + +@safe pure nothrow @nogc unittest +{ + import std.digest.hmac; + + import std.digest.sha : SHA1; + import std.string : representation; + auto hmac = HMAC!SHA1("My s3cR3T keY".representation); + hmac.put("Hello, world".representation); + static immutable expected = [ + 130, 32, 235, 44, 208, 141, + 150, 232, 211, 214, 162, 195, + 188, 127, 52, 89, 100, 68, 90, 216]; + assert(hmac.finish() == expected); + +} + +@safe pure nothrow @nogc unittest +{ + import std.digest.hmac; + + import std.digest.sha : SHA1; + import std.string : representation; + string data1 = "Hello, world", data2 = "Hola mundo"; + auto hmac = HMAC!SHA1("My s3cR3T keY".representation); + hmac.put(data1.representation); + hmac.start(); // reset digest + hmac.put(data2.representation); // start over + static immutable expected = [ + 122, 151, 232, 240, 249, 80, + 19, 178, 186, 77, 110, 23, 208, + 52, 11, 88, 34, 151, 192, 255]; + assert(hmac.finish() == expected); + +} + +@safe pure nothrow @nogc unittest +{ + import std.digest.hmac; + + import std.digest.hmac, std.digest.sha; + import std.string : representation; + string data1 = "Hello, world", data2 = "Hola mundo"; + auto hmac = HMAC!SHA1("My s3cR3T keY".representation); + hmac.put(data1.representation) + .put(data2.representation); + static immutable expected = [ + 197, 57, 52, 3, 13, 194, 13, + 36, 117, 228, 8, 11, 111, 51, + 165, 3, 123, 31, 251, 113]; + assert(hmac.finish() == expected); + +} + +@safe pure nothrow @nogc unittest +{ + import std.digest.hmac; + + import std.digest.sha : SHA1; + import std.string : representation; + string data1 = "Hello, world", data2 = "Hola mundo"; + auto hmac = HMAC!SHA1("My s3cR3T keY".representation); + auto testDigest = hmac.put(data1.representation) + .put(data2.representation) + .finish(); + static immutable expected = [ + 197, 57, 52, 3, 13, 194, 13, + 36, 117, 228, 8, 11, 111, 51, + 165, 3, 123, 31, 251, 113]; + assert(testDigest == expected); + +} + +@safe pure nothrow @nogc unittest +{ + import std.digest.hmac; + + import std.digest.sha : SHA1; + import std.string : representation; + string data1 = "Hello, world", data2 = "Hola mundo"; + auto digest = hmac!SHA1("My s3cR3T keY".representation) + .put(data1.representation) + .put(data2.representation) + .finish(); + static immutable expected = [ + 197, 57, 52, 3, 13, 194, 13, 36, + 117, 228, 8, 11, 111, 51, 165, + 3, 123, 31, 251, 113]; + assert(digest == expected); + +} + +@safe pure nothrow @nogc unittest +{ + import std.digest.hmac; + + import std.algorithm.iteration : map; + import std.digest.sha : SHA1; + import std.string : representation; + string data = "Hello, world"; + auto digest = data.representation + .map!(a => cast(ubyte)(a+1)) + .hmac!SHA1("My s3cR3T keY".representation); + static assert(is(typeof(digest) == ubyte[20])); + static immutable expected = [ + 163, 208, 118, 179, 216, 93, + 17, 10, 84, 200, 87, 104, 244, + 111, 136, 214, 167, 210, 58, 10]; + assert(digest == expected); + +} + +@safe pure nothrow @nogc unittest +{ + import std.digest.hmac; + + import std.digest.sha : SHA1; + import std.string : representation; + string data1 = "Hello, world", data2 = "Hola mundo"; + auto hmac = HMAC!SHA1("My s3cR3T keY".representation); + auto digest = hmac.put(data1.representation) + .put(data2.representation) + .finish(); + static immutable expected = [ + 197, 57, 52, 3, 13, 194, 13, + 36, 117, 228, 8, 11, 111, 51, + 165, 3, 123, 31, 251, 113]; + assert(digest == expected); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_digest_md.d b/libphobos/testsuite/libphobos.phobos/std_digest_md.d new file mode 100644 index 000000000000..a9cf45fa94e0 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_digest_md.d @@ -0,0 +1,124 @@ +@safe unittest +{ + import std.digest.md; + + //Template API + import std.digest.md; + + //Feeding data + ubyte[1024] data; + MD5 md5; + md5.start(); + md5.put(data[]); + md5.start(); //Start again + md5.put(data[]); + auto hash = md5.finish(); +} + +@safe unittest +{ + import std.digest.md; + + //OOP API + import std.digest.md; + + auto md5 = new MD5Digest(); + ubyte[] hash = md5.digest("abc"); + assert(toHexString(hash) == "900150983CD24FB0D6963F7D28E17F72"); + + //Feeding data + ubyte[1024] data; + md5.put(data[]); + md5.reset(); //Start again + md5.put(data[]); + hash = md5.finish(); +} + +@safe unittest +{ + import std.digest.md; + + //Simple example + MD5 hash; + hash.start(); + hash.put(cast(ubyte) 0); + ubyte[16] result = hash.finish(); + +} + +@safe unittest +{ + import std.digest.md; + + //Simple example, hashing a string using md5Of helper function + ubyte[16] hash = md5Of("abc"); + //Let's get a hash string + assert(toHexString(hash) == "900150983CD24FB0D6963F7D28E17F72"); +} + +@safe unittest +{ + import std.digest.md; + + //Using the basic API + MD5 hash; + hash.start(); + ubyte[1024] data; + //Initialize data here... + hash.put(data); + ubyte[16] result = hash.finish(); +} + +@safe unittest +{ + import std.digest.md; + + //Let's use the template features: + void doSomething(T)(ref T hash) + if (isDigest!T) + { + hash.put(cast(ubyte) 0); + } + MD5 md5; + md5.start(); + doSomething(md5); + assert(toHexString(md5.finish()) == "93B885ADFE0DA089CDF634904FD59F71"); +} + +@safe unittest +{ + import std.digest.md; + + ubyte[16] hash = md5Of("abc"); + assert(hash == digest!MD5("abc")); +} + +@safe unittest +{ + import std.digest.md; + + //Simple example, hashing a string using Digest.digest helper function + auto md5 = new MD5Digest(); + ubyte[] hash = md5.digest("abc"); + //Let's get a hash string + assert(toHexString(hash) == "900150983CD24FB0D6963F7D28E17F72"); +} + +@system unittest +{ + import std.digest.md; + + //Let's use the OOP features: + void test(Digest dig) + { + dig.put(cast(ubyte) 0); + } + auto md5 = new MD5Digest(); + test(md5); + + //Let's use a custom buffer: + ubyte[16] buf; + ubyte[] result = md5.finish(buf[]); + assert(toHexString(result) == "93B885ADFE0DA089CDF634904FD59F71"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_digest_murmurhash.d b/libphobos/testsuite/libphobos.phobos/std_digest_murmurhash.d new file mode 100644 index 000000000000..c44496d54780 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_digest_murmurhash.d @@ -0,0 +1,82 @@ +@safe unittest +{ + import std.digest.murmurhash; + + // MurmurHash3!32, MurmurHash3!(128, 32) and MurmurHash3!(128, 64) implement + // the std.digest Template API. + static assert(isDigest!(MurmurHash3!32)); + // The convenient digest template allows for quick hashing of any data. + ubyte[4] hashed = digest!(MurmurHash3!32)([1, 2, 3, 4]); + assert(hashed == [0, 173, 69, 68]); +} + +@safe unittest +{ + import std.digest.murmurhash; + + // One can also hash ubyte data piecewise by instanciating a hasher and call + // the 'put' method. + const(ubyte)[] data1 = [1, 2, 3]; + const(ubyte)[] data2 = [4, 5, 6, 7]; + // The incoming data will be buffered and hashed element by element. + MurmurHash3!32 hasher; + hasher.put(data1); + hasher.put(data2); + // The call to 'finish' ensures: + // - the remaining bits are processed + // - the hash gets finalized + auto hashed = hasher.finish(); + assert(hashed == [181, 151, 88, 252]); +} + +@safe unittest +{ + import std.digest.murmurhash; + + // Using `putElements`, `putRemainder` and `finalize` you gain full + // control over which part of the algorithm to run. + // This allows for maximum throughput but needs extra care. + + // Data type must be the same as the hasher's element type: + // - uint for MurmurHash3!32 + // - uint[4] for MurmurHash3!(128, 32) + // - ulong[2] for MurmurHash3!(128, 64) + const(uint)[] data = [1, 2, 3, 4]; + // Note the hasher starts with 'Fast'. + MurmurHash3!32 hasher; + // Push as many array of elements as you need. The less calls the better. + hasher.putElements(data); + // Put remainder bytes if needed. This method can be called only once. + hasher.putRemainder(ubyte(1), ubyte(1), ubyte(1)); + // Call finalize to incorporate data length in the hash. + hasher.finalize(); + // Finally get the hashed value. + auto hashed = hasher.getBytes(); + assert(hashed == [188, 165, 108, 2]); +} + +@safe unittest +{ + import std.digest.murmurhash; + + ubyte[4] hashed = digest!(MurmurHash3!32)([1, 2, 3, 4]); + assert(hashed == [0, 173, 69, 68]); +} + +@safe unittest +{ + import std.digest.murmurhash; + + const(ubyte)[] data1 = [1, 2, 3]; + const(ubyte)[] data2 = [4, 5, 6, 7]; + // The incoming data will be buffered and hashed element by element. + MurmurHash3!32 hasher; + hasher.put(data1); + hasher.put(data2); + // The call to 'finish' ensures: + // - the remaining bits are processed + // - the hash gets finalized + auto hashed = hasher.finish(); + assert(hashed == [181, 151, 88, 252]); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_digest_package.d b/libphobos/testsuite/libphobos.phobos/std_digest_package.d new file mode 100644 index 000000000000..330326c3fdec --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_digest_package.d @@ -0,0 +1,492 @@ +@system unittest +{ + import std.digest; + + import std.digest.crc; + + //Simple example + char[8] hexHash = hexDigest!CRC32("The quick brown fox jumps over the lazy dog"); + assert(hexHash == "39A34F41"); + + //Simple example, using the API manually + CRC32 context = makeDigest!CRC32(); + context.put(cast(ubyte[])"The quick brown fox jumps over the lazy dog"); + ubyte[4] hash = context.finish(); + assert(toHexString(hash) == "39A34F41"); +} + +@system unittest +{ + import std.digest; + + //Generating the hashes of a file, idiomatic D way + import std.digest.crc, std.digest.md, std.digest.sha; + import std.stdio; + + // Digests a file and prints the result. + void digestFile(Hash)(string filename) + if (isDigest!Hash) + { + auto file = File(filename); + auto result = digest!Hash(file.byChunk(4096 * 1024)); + writefln("%s (%s) = %s", Hash.stringof, filename, toHexString(result)); + } + + void main(string[] args) + { + foreach (name; args[1 .. $]) + { + digestFile!MD5(name); + digestFile!SHA1(name); + digestFile!CRC32(name); + } + } +} + +@system unittest +{ + import std.digest; + + //Generating the hashes of a file using the template API + import std.digest.crc, std.digest.md, std.digest.sha; + import std.stdio; + // Digests a file and prints the result. + void digestFile(Hash)(ref Hash hash, string filename) + if (isDigest!Hash) + { + File file = File(filename); + + //As digests imlement OutputRange, we could use std.algorithm.copy + //Let's do it manually for now + foreach (buffer; file.byChunk(4096 * 1024)) + hash.put(buffer); + + auto result = hash.finish(); + writefln("%s (%s) = %s", Hash.stringof, filename, toHexString(result)); + } + + void uMain(string[] args) + { + MD5 md5; + SHA1 sha1; + CRC32 crc32; + + md5.start(); + sha1.start(); + crc32.start(); + + foreach (arg; args[1 .. $]) + { + digestFile(md5, arg); + digestFile(sha1, arg); + digestFile(crc32, arg); + } + } +} + +@system unittest +{ + import std.digest; + + import std.digest.crc, std.digest.md, std.digest.sha; + import std.stdio; + + // Digests a file and prints the result. + void digestFile(Digest hash, string filename) + { + File file = File(filename); + + //As digests implement OutputRange, we could use std.algorithm.copy + //Let's do it manually for now + foreach (buffer; file.byChunk(4096 * 1024)) + hash.put(buffer); + + ubyte[] result = hash.finish(); + writefln("%s (%s) = %s", typeid(hash).toString(), filename, toHexString(result)); + } + + void umain(string[] args) + { + auto md5 = new MD5Digest(); + auto sha1 = new SHA1Digest(); + auto crc32 = new CRC32Digest(); + + foreach (arg; args[1 .. $]) + { + digestFile(md5, arg); + digestFile(sha1, arg); + digestFile(crc32, arg); + } + } +} + +@system unittest +{ + import std.digest; + + //Using the OutputRange feature + import std.algorithm.mutation : copy; + import std.digest.md; + import std.range : repeat; + + auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000); + auto ctx = makeDigest!MD5(); + copy(oneMillionRange, &ctx); //Note: You must pass a pointer to copy! + assert(ctx.finish().toHexString() == "7707D6AE4E027C70EEA2A935C2296F21"); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc; + static assert(isDigest!CRC32); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc; + void myFunction(T)() + if (isDigest!T) + { + T dig; + dig.start(); + auto result = dig.finish(); + } + myFunction!CRC32(); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc; + assert(is(DigestType!(CRC32) == ubyte[4])); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc; + CRC32 dig; + dig.start(); + DigestType!CRC32 result = dig.finish(); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc, std.digest.md; + assert(!hasPeek!(MD5)); + assert(hasPeek!CRC32); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc; + void myFunction(T)() + if (hasPeek!T) + { + T dig; + dig.start(); + auto result = dig.peek(); + } + myFunction!CRC32(); +} + +@system unittest +{ + import std.digest; + + import std.digest.hmac, std.digest.md; + static assert(hasBlockSize!MD5 && MD5.blockSize == 512); + static assert(hasBlockSize!(HMAC!MD5) && HMAC!MD5.blockSize == 512); +} + +@system unittest +{ + import std.digest; + + import std.digest.md; + import std.range : repeat; + auto testRange = repeat!ubyte(cast(ubyte)'a', 100); + auto md5 = digest!MD5(testRange); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc, std.digest.md, std.digest.sha; + auto md5 = digest!MD5( "The quick brown fox jumps over the lazy dog"); + auto sha1 = digest!SHA1( "The quick brown fox jumps over the lazy dog"); + auto crc32 = digest!CRC32("The quick brown fox jumps over the lazy dog"); + assert(toHexString(crc32) == "39A34F41"); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc; + auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog"); + assert(toHexString(crc32) == "39A34F41"); +} + +@system unittest +{ + import std.digest; + + import std.digest.md; + import std.range : repeat; + auto testRange = repeat!ubyte(cast(ubyte)'a', 100); + assert(hexDigest!MD5(testRange) == "36A92CC94A9E0FA21F625F8BFB007ADF"); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc; + assert(hexDigest!(CRC32, Order.decreasing)("The quick brown fox jumps over the lazy dog") == "414FA339"); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc; + assert(hexDigest!(CRC32, Order.decreasing)("The quick ", "brown ", "fox jumps over the lazy dog") == "414FA339"); +} + +@system unittest +{ + import std.digest; + + import std.digest.md; + auto md5 = makeDigest!MD5(); + md5.put(0); + assert(toHexString(md5.finish()) == "93B885ADFE0DA089CDF634904FD59F71"); +} + +@system unittest +{ + import std.digest; + + //Using the OutputRange feature + import std.algorithm.mutation : copy; + import std.digest.md; + import std.range : repeat; + + auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000); + auto ctx = new MD5Digest(); + copy(oneMillionRange, ctx); + assert(ctx.finish().toHexString() == "7707D6AE4E027C70EEA2A935C2296F21"); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc, std.digest.md, std.digest.sha; + ubyte[] md5 = (new MD5Digest()).digest("The quick brown fox jumps over the lazy dog"); + ubyte[] sha1 = (new SHA1Digest()).digest("The quick brown fox jumps over the lazy dog"); + ubyte[] crc32 = (new CRC32Digest()).digest("The quick brown fox jumps over the lazy dog"); + assert(crcHexString(crc32) == "414FA339"); +} + +@system unittest +{ + import std.digest; + + import std.digest.crc; + ubyte[] crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog"); + assert(crcHexString(crc32) == "414FA339"); +} + +@system unittest +{ + import std.digest; + + void test(Digest dig) + { + dig.put(cast(ubyte) 0); //single ubyte + dig.put(cast(ubyte) 0, cast(ubyte) 0); //variadic + ubyte[10] buf; + dig.put(buf); //buffer + } +} + +@safe unittest +{ + import std.digest; + + import std.digest.crc : CRC32; + + auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog"); + assert(crc32.toHexString!(Order.decreasing) == "414FA339"); + assert(crc32.toHexString!(LetterCase.lower, Order.decreasing) == "414fa339"); +} + +@safe unittest +{ + import std.digest; + + import std.digest.crc; + //Test with template API: + auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog"); + //Lower case variant: + assert(toHexString!(LetterCase.lower)(crc32) == "39a34f41"); + //Usually CRCs are printed in this order, though: + assert(toHexString!(Order.decreasing)(crc32) == "414FA339"); + assert(toHexString!(LetterCase.lower, Order.decreasing)(crc32) == "414fa339"); +} + +@safe unittest +{ + import std.digest; + + import std.digest.crc; + // With OOP API + auto crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog"); + //Usually CRCs are printed in this order, though: + assert(toHexString!(Order.decreasing)(crc32) == "414FA339"); +} + +@system unittest +{ + import std.digest; + + import std.digest.md; + //Simple example + auto hash = new WrapperDigest!MD5(); + hash.put(cast(ubyte) 0); + auto result = hash.finish(); +} + +@system unittest +{ + import std.digest; + + //using a supplied buffer + import std.digest.md; + ubyte[16] buf; + auto hash = new WrapperDigest!MD5(); + hash.put(cast(ubyte) 0); + auto result = hash.finish(buf[]); + //The result is now in result (and in buf). If you pass a buffer which is bigger than + //necessary, result will have the correct length, but buf will still have it's original + //length +} + +@system pure unittest +{ + import std.digest; + + import std.digest.hmac : hmac; + import std.digest.sha : SHA1; + import std.string : representation; + + // a typical HMAC data integrity verification + auto secret = "A7GZIP6TAQA6OHM7KZ42KB9303CEY0MOV5DD6NTV".representation; + auto data = "data".representation; + + auto hex1 = data.hmac!SHA1(secret).toHexString; + auto hex2 = data.hmac!SHA1(secret).toHexString; + auto hex3 = "data1".representation.hmac!SHA1(secret).toHexString; + + assert( secureEqual(hex1[], hex2[])); + assert(!secureEqual(hex1[], hex3[])); +} + +@safe unittest +{ + import std.digest; + + assert(isHexString("0x0123456789ABCDEFabcdef")); + assert(isHexString("0123456789ABCDEFabcdef")); + assert(!isHexString("g")); + assert(!isHexString("#")); +} + +@safe unittest +{ + import std.digest; + + import std.range.primitives : ElementType, isForwardRange; + import std.traits : ReturnType; + + // The decoder implements a forward range. + static assert(isForwardRange!(ReturnType!(fromHexStringAsRange!string))); + static assert(isForwardRange!(ReturnType!(fromHexStringAsRange!wstring))); + static assert(isForwardRange!(ReturnType!(fromHexStringAsRange!dstring))); + + // The element type of the range is always `ubyte`. + static assert( + is(ElementType!(ReturnType!(fromHexStringAsRange!string)) == ubyte) + ); + static assert( + is(ElementType!(ReturnType!(fromHexStringAsRange!wstring)) == ubyte) + ); + static assert( + is(ElementType!(ReturnType!(fromHexStringAsRange!dstring)) == ubyte) + ); +} + +@safe unittest +{ + import std.digest; + + // Single byte + assert("0xff".fromHexString == [255]); + assert("0xff"w.fromHexString == [255]); + assert("0xff"d.fromHexString == [255]); + assert("0xC0".fromHexString == [192]); + assert("0x00".fromHexString == [0]); + + // Nothing + assert("".fromHexString == []); + assert(""w.fromHexString == []); + assert(""d.fromHexString == []); + + // Nothing but a prefix + assert("0x".fromHexString == []); + assert("0x"w.fromHexString == []); + assert("0x"d.fromHexString == []); + + // Half a byte + assert("0x1".fromHexString == [0x01]); + assert("0x1"w.fromHexString == [0x01]); + assert("0x1"d.fromHexString == [0x01]); + + // Mixed case is fine. + assert("0xAf".fromHexString == [0xAF]); + assert("0xaF".fromHexString == [0xAF]); + + // Multiple bytes + assert("0xfff".fromHexString == [0x0F, 0xFF]); + assert("0x123AaAa".fromHexString == [0x01, 0x23, 0xAA, 0xAA]); + assert("EBBBBF".fromHexString == [0xEB, 0xBB, 0xBF]); + + // md5 sum + assert("d41d8cd98f00b204e9800998ecf8427e".fromHexString == [ + 0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04, + 0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E, + ]); +} + +@safe unittest +{ + import std.digest; + + // Cycle self-test + const ubyte[] initial = [0x00, 0x12, 0x34, 0xEB]; + assert(initial == initial.toHexString().fromHexString()); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_digest_ripemd.d b/libphobos/testsuite/libphobos.phobos/std_digest_ripemd.d new file mode 100644 index 000000000000..582a21bd7219 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_digest_ripemd.d @@ -0,0 +1,127 @@ +@safe unittest +{ + import std.digest.ripemd; + + //Template API + import std.digest.md; + + ubyte[20] hash = ripemd160Of("abc"); + assert(toHexString(hash) == "8EB208F7E05D987A9B044A8E98C6B087F15A0BFC"); + + //Feeding data + ubyte[1024] data; + RIPEMD160 md; + md.start(); + md.put(data[]); + md.start(); //Start again + md.put(data[]); + hash = md.finish(); +} + +@safe unittest +{ + import std.digest.ripemd; + + //OOP API + import std.digest.md; + + auto md = new RIPEMD160Digest(); + ubyte[] hash = md.digest("abc"); + assert(toHexString(hash) == "8EB208F7E05D987A9B044A8E98C6B087F15A0BFC"); + + //Feeding data + ubyte[1024] data; + md.put(data[]); + md.reset(); //Start again + md.put(data[]); + hash = md.finish(); +} + +@safe unittest +{ + import std.digest.ripemd; + + //Simple example, hashing a string using ripemd160Of helper function + ubyte[20] hash = ripemd160Of("abc"); + //Let's get a hash string + assert(toHexString(hash) == "8EB208F7E05D987A9B044A8E98C6B087F15A0BFC"); +} + +@safe unittest +{ + import std.digest.ripemd; + + //Using the basic API + RIPEMD160 hash; + hash.start(); + ubyte[1024] data; + //Initialize data here... + hash.put(data); + ubyte[20] result = hash.finish(); +} + +@safe unittest +{ + import std.digest.ripemd; + + //Let's use the template features: + void doSomething(T)(ref T hash) + if (isDigest!T) + { + hash.put(cast(ubyte) 0); + } + RIPEMD160 md; + md.start(); + doSomething(md); + assert(toHexString(md.finish()) == "C81B94933420221A7AC004A90242D8B1D3E5070D"); +} + +@safe unittest +{ + import std.digest.ripemd; + + //Simple example + RIPEMD160 hash; + hash.start(); + hash.put(cast(ubyte) 0); + ubyte[20] result = hash.finish(); + assert(toHexString(result) == "C81B94933420221A7AC004A90242D8B1D3E5070D"); +} + +@safe unittest +{ + import std.digest.ripemd; + + ubyte[20] hash = ripemd160Of("abc"); + assert(hash == digest!RIPEMD160("abc")); +} + +@safe unittest +{ + import std.digest.ripemd; + + //Simple example, hashing a string using Digest.digest helper function + auto md = new RIPEMD160Digest(); + ubyte[] hash = md.digest("abc"); + //Let's get a hash string + assert(toHexString(hash) == "8EB208F7E05D987A9B044A8E98C6B087F15A0BFC"); +} + +@system unittest +{ + import std.digest.ripemd; + + //Let's use the OOP features: + void test(Digest dig) + { + dig.put(cast(ubyte) 0); + } + auto md = new RIPEMD160Digest(); + test(md); + + //Let's use a custom buffer: + ubyte[20] buf; + ubyte[] result = md.finish(buf[]); + assert(toHexString(result) == "C81B94933420221A7AC004A90242D8B1D3E5070D"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_digest_sha.d b/libphobos/testsuite/libphobos.phobos/std_digest_sha.d new file mode 100644 index 000000000000..04339ef8ac51 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_digest_sha.d @@ -0,0 +1,163 @@ +@safe unittest +{ + import std.digest.sha; + + //Template API + import std.digest.sha; + + ubyte[20] hash1 = sha1Of("abc"); + assert(toHexString(hash1) == "A9993E364706816ABA3E25717850C26C9CD0D89D"); + + ubyte[28] hash224 = sha224Of("abc"); + assert(toHexString(hash224) == "23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7"); + + //Feeding data + ubyte[1024] data; + SHA1 sha1; + sha1.start(); + sha1.put(data[]); + sha1.start(); //Start again + sha1.put(data[]); + hash1 = sha1.finish(); +} + +@safe unittest +{ + import std.digest.sha; + + //OOP API + import std.digest.sha; + + auto sha1 = new SHA1Digest(); + ubyte[] hash1 = sha1.digest("abc"); + assert(toHexString(hash1) == "A9993E364706816ABA3E25717850C26C9CD0D89D"); + + auto sha224 = new SHA224Digest(); + ubyte[] hash224 = sha224.digest("abc"); + assert(toHexString(hash224) == "23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7"); + + //Feeding data + ubyte[1024] data; + sha1.put(data[]); + sha1.reset(); //Start again + sha1.put(data[]); + hash1 = sha1.finish(); +} + +@safe unittest +{ + import std.digest.sha; + + //Simple example + SHA1 hash; + hash.start(); + hash.put(cast(ubyte) 0); + ubyte[20] result = hash.finish(); + +} + +@safe unittest +{ + import std.digest.sha; + + //Simple example, hashing a string using sha1Of helper function + ubyte[20] hash = sha1Of("abc"); + //Let's get a hash string + assert(toHexString(hash) == "A9993E364706816ABA3E25717850C26C9CD0D89D"); + + //The same, but using SHA-224 + ubyte[28] hash224 = sha224Of("abc"); + assert(toHexString(hash224) == "23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7"); +} + +@safe unittest +{ + import std.digest.sha; + + //Using the basic API + SHA1 hash; + hash.start(); + ubyte[1024] data; + //Initialize data here... + hash.put(data); + ubyte[20] result = hash.finish(); +} + +@safe unittest +{ + import std.digest.sha; + + //Let's use the template features: + //Note: When passing a SHA1 to a function, it must be passed by reference! + void doSomething(T)(ref T hash) + if (isDigest!T) + { + hash.put(cast(ubyte) 0); + } + SHA1 sha; + sha.start(); + doSomething(sha); + assert(toHexString(sha.finish()) == "5BA93C9DB0CFF93F52B521D7420E43F6EDA2784F"); +} + +@safe unittest +{ + import std.digest.sha; + + ubyte[20] hash = sha1Of("abc"); + assert(hash == digest!SHA1("abc")); + + ubyte[28] hash224 = sha224Of("abc"); + assert(hash224 == digest!SHA224("abc")); + + ubyte[32] hash256 = sha256Of("abc"); + assert(hash256 == digest!SHA256("abc")); + + ubyte[48] hash384 = sha384Of("abc"); + assert(hash384 == digest!SHA384("abc")); + + ubyte[64] hash512 = sha512Of("abc"); + assert(hash512 == digest!SHA512("abc")); + + ubyte[28] hash512_224 = sha512_224Of("abc"); + assert(hash512_224 == digest!SHA512_224("abc")); + + ubyte[32] hash512_256 = sha512_256Of("abc"); + assert(hash512_256 == digest!SHA512_256("abc")); +} + +@safe unittest +{ + import std.digest.sha; + + //Simple example, hashing a string using Digest.digest helper function + auto sha = new SHA1Digest(); + ubyte[] hash = sha.digest("abc"); + //Let's get a hash string + assert(toHexString(hash) == "A9993E364706816ABA3E25717850C26C9CD0D89D"); + + //The same, but using SHA-224 + auto sha224 = new SHA224Digest(); + ubyte[] hash224 = sha224.digest("abc"); + //Let's get a hash string + assert(toHexString(hash224) == "23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7"); +} + +@system unittest +{ + import std.digest.sha; + + //Let's use the OOP features: + void test(Digest dig) + { + dig.put(cast(ubyte) 0); + } + auto sha = new SHA1Digest(); + test(sha); + + //Let's use a custom buffer: + ubyte[20] buf; + ubyte[] result = sha.finish(buf[]); + assert(toHexString(result) == "5BA93C9DB0CFF93F52B521D7420E43F6EDA2784F"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_encoding.d b/libphobos/testsuite/libphobos.phobos/std_encoding.d new file mode 100644 index 000000000000..15003e370c97 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_encoding.d @@ -0,0 +1,167 @@ +@safe unittest +{ + import std.encoding; + + assert(encodingName!(char) == "UTF-8"); + assert(encodingName!(wchar) == "UTF-16"); + assert(encodingName!(dchar) == "UTF-32"); + assert(encodingName!(AsciiChar) == "ASCII"); + assert(encodingName!(Latin1Char) == "ISO-8859-1"); + assert(encodingName!(Latin2Char) == "ISO-8859-2"); + assert(encodingName!(Windows1250Char) == "windows-1250"); + assert(encodingName!(Windows1251Char) == "windows-1251"); + assert(encodingName!(Windows1252Char) == "windows-1252"); +} + +@safe pure unittest +{ + import std.encoding; + + assert( canEncode!(Latin1Char)('A')); + assert( canEncode!(Latin2Char)('A')); + assert(!canEncode!(AsciiChar)('\u00A0')); + assert( canEncode!(Latin1Char)('\u00A0')); + assert( canEncode!(Latin2Char)('\u00A0')); + assert( canEncode!(Windows1250Char)('\u20AC')); + assert(!canEncode!(Windows1250Char)('\u20AD')); + assert(!canEncode!(Windows1250Char)('\uFFFD')); + assert( canEncode!(Windows1251Char)('\u0402')); + assert(!canEncode!(Windows1251Char)('\u20AD')); + assert(!canEncode!(Windows1251Char)('\uFFFD')); + assert( canEncode!(Windows1252Char)('\u20AC')); + assert(!canEncode!(Windows1252Char)('\u20AD')); + assert(!canEncode!(Windows1252Char)('\uFFFD')); + assert(!canEncode!(char)(cast(dchar) 0x110000)); +} + +@safe pure unittest +{ + import std.encoding; + + import std.algorithm.searching : find; + import std.utf : byDchar; + + assert("The quick brown fox" + .byDchar + .find!(x => !canEncode!AsciiChar(x)) + .empty); +} + +@system pure unittest +{ + import std.encoding; + + assert(!isValidCodeUnit(cast(char) 0xC0)); + assert(!isValidCodeUnit(cast(char) 0xFF)); + assert( isValidCodeUnit(cast(wchar) 0xD800)); + assert(!isValidCodeUnit(cast(dchar) 0xD800)); + assert(!isValidCodeUnit(cast(AsciiChar) 0xA0)); + assert( isValidCodeUnit(cast(Windows1250Char) 0x80)); + assert(!isValidCodeUnit(cast(Windows1250Char) 0x81)); + assert( isValidCodeUnit(cast(Windows1251Char) 0x80)); + assert(!isValidCodeUnit(cast(Windows1251Char) 0x98)); + assert( isValidCodeUnit(cast(Windows1252Char) 0x80)); + assert(!isValidCodeUnit(cast(Windows1252Char) 0x81)); +} + +@system pure unittest +{ + import std.encoding; + + assert( isValid("\u20AC100")); + assert(!isValid(cast(char[3])[167, 133, 175])); +} + +@system pure unittest +{ + import std.encoding; + + assert(sanitize("hello \xF0\x80world") == "hello \xEF\xBF\xBDworld"); +} + +@system pure unittest +{ + import std.encoding; + + assert(firstSequence("\u20AC1000") == "\u20AC".length); + assert(firstSequence("hel") == "h".length); +} + +@system pure unittest +{ + import std.encoding; + + assert(lastSequence("1000\u20AC") == "\u20AC".length); + assert(lastSequence("hellö") == "ö".length); +} + +@system pure unittest +{ + import std.encoding; + + assert(index("\u20AC100",1) == 3); + assert(index("hällo",2) == 3); +} + +@system unittest +{ + import std.encoding; + + string s = "hello"; + string t; + foreach (c;codePoints(s)) + { + t ~= cast(char) c; + } + assert(s == t); +} + +@system unittest +{ + import std.encoding; + + char[] a; + foreach (c;codeUnits!(char)(cast(dchar)'\u20AC')) + { + a ~= c; + } + assert(a.length == 3); + assert(a[0] == 0xE2); + assert(a[1] == 0x82); + assert(a[2] == 0xAC); +} + +@system pure unittest +{ + import std.encoding; + + wstring ws; + // transcode from UTF-8 to UTF-16 + transcode("hello world",ws); + assert(ws == "hello world"w); + + Latin1String ls; + // transcode from UTF-16 to ISO-8859-1 + transcode(ws, ls); + assert(ls == "hello world"); +} + +@system unittest +{ + import std.encoding; + + import std.format : format; + + auto ts = dchar(0x0000FEFF) ~ "Hello World"d; + + auto entry = getBOM(cast(ubyte[]) ts); + version (BigEndian) + { + assert(entry.schema == BOM.utf32be, format("%s", entry.schema)); + } + else + { + assert(entry.schema == BOM.utf32le, format("%s", entry.schema)); + } +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_exception.d b/libphobos/testsuite/libphobos.phobos/std_exception.d new file mode 100644 index 000000000000..8f973208c154 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_exception.d @@ -0,0 +1,543 @@ +@system unittest +{ + import std.exception; + + import core.stdc.stdlib : malloc, free; + import std.algorithm.comparison : equal; + import std.algorithm.iteration : map, splitter; + import std.algorithm.searching : endsWith; + import std.conv : ConvException, to; + import std.range : front, retro; + + // use enforce like assert + int a = 3; + enforce(a > 2, "a needs to be higher than 2."); + + // enforce can throw a custom exception + enforce!ConvException(a > 2, "a needs to be higher than 2."); + + // enforce will return it's input + enum size = 42; + auto memory = enforce(malloc(size), "malloc failed")[0 .. size]; + scope(exit) free(memory.ptr); + + // collectException can be used to test for exceptions + Exception e = collectException("abc".to!int); + assert(e.file.endsWith("conv.d")); + + // and just for the exception message + string msg = collectExceptionMsg("abc".to!int); + assert(msg == "Unexpected 'a' when converting from type string to type int"); + + // assertThrown can be used to assert that an exception is thrown + assertThrown!ConvException("abc".to!int); + + // ifThrown can be used to provide a default value if an exception is thrown + assert("x".to!int().ifThrown(0) == 0); + + // handle is a more advanced version of ifThrown for ranges + auto r = "12,1337z32,54".splitter(',').map!(a => to!int(a)); + auto h = r.handle!(ConvException, RangePrimitive.front, (e, r) => 0); + assert(h.equal([12, 0, 54])); + assertThrown!ConvException(h.retro.equal([54, 0, 12])); + + // basicExceptionCtors avoids the boilerplate when creating custom exceptions + static class MeaCulpa : Exception + { + mixin basicExceptionCtors; + } + e = collectException((){throw new MeaCulpa("diagnostic message");}()); + assert(e.msg == "diagnostic message"); + assert(e.file == __FILE__); + assert(e.line == __LINE__ - 3); + + // assumeWontThrow can be used to cast throwing code into `nothrow` + void exceptionFreeCode() nothrow + { + // auto-decoding only throws if an invalid UTF char is given + assumeWontThrow("abc".front); + } + + // assumeUnique can be used to cast mutable instance to an `immutable` one + // use with care + char[] str = " mutable".dup; + str[0 .. 2] = "im"; + immutable res = assumeUnique(str); + assert(res == "immutable"); +} + +@system unittest +{ + import std.exception; + + import core.exception : AssertError; + + import std.string; + assertNotThrown!StringException(enforce!StringException(true, "Error!")); + + //Exception is the default. + assertNotThrown(enforce!StringException(true, "Error!")); + + assert(collectExceptionMsg!AssertError(assertNotThrown!StringException( + enforce!StringException(false, "Error!"))) == + `assertNotThrown failed: StringException was thrown: Error!`); +} + +@system unittest +{ + import std.exception; + + import core.exception : AssertError; + import std.string; + + assertThrown!StringException(enforce!StringException(false, "Error!")); + + //Exception is the default. + assertThrown(enforce!StringException(false, "Error!")); + + assert(collectExceptionMsg!AssertError(assertThrown!StringException( + enforce!StringException(true, "Error!"))) == + `assertThrown failed: No StringException was thrown.`); +} + +@system unittest +{ + import std.exception; + + import core.stdc.stdlib : malloc, free; + import std.conv : ConvException, to; + + // use enforce like assert + int a = 3; + enforce(a > 2, "a needs to be higher than 2."); + + // enforce can throw a custom exception + enforce!ConvException(a > 2, "a needs to be higher than 2."); + + // enforce will return it's input + enum size = 42; + auto memory = enforce(malloc(size), "malloc failed")[0 .. size]; + scope(exit) free(memory.ptr); +} + +@safe unittest +{ + import std.exception; + + assertNotThrown(enforce(true, new Exception("this should not be thrown"))); + assertThrown(enforce(false, new Exception("this should be thrown"))); +} + +@safe unittest +{ + import std.exception; + + assert(enforce(123) == 123); + + try + { + enforce(false, "error"); + assert(false); + } + catch (Exception e) + { + assert(e.msg == "error"); + assert(e.file == __FILE__); + assert(e.line == __LINE__-7); + } +} + +@safe unittest +{ + import std.exception; + + import std.conv : ConvException; + alias convEnforce = enforce!ConvException; + assertNotThrown(convEnforce(true)); + assertThrown!ConvException(convEnforce(false, "blah")); +} + +@system unittest +{ + import std.exception; + + import core.stdc.stdio : fclose, fgets, fopen; + import std.file : thisExePath; + import std.string : toStringz; + + auto f = fopen(thisExePath.toStringz, "r").errnoEnforce; + scope(exit) fclose(f); + char[100] buf; + auto line = fgets(buf.ptr, buf.length, f); + enforce(line !is null); // expect a non-empty line +} + +@system unittest +{ + import std.exception; + + int b; + int foo() { throw new Exception("blah"); } + assert(collectException(foo(), b)); + + version (D_NoBoundsChecks) {} + else + { + // check for out of bounds error + int[] a = new int[3]; + import core.exception : RangeError; + assert(collectException!RangeError(a[4], b)); + } +} + +@safe unittest +{ + import std.exception; + + int foo() { throw new Exception("blah"); } + assert(collectException(foo()).msg == "blah"); +} + +@safe unittest +{ + import std.exception; + + void throwFunc() { throw new Exception("My Message."); } + assert(collectExceptionMsg(throwFunc()) == "My Message."); + + void nothrowFunc() {} + assert(collectExceptionMsg(nothrowFunc()) is null); + + void throwEmptyFunc() { throw new Exception(""); } + assert(collectExceptionMsg(throwEmptyFunc()) == emptyExceptionMsg); +} + +@system unittest +{ + import std.exception; + + int[] arr = new int[1]; + auto arr1 = arr.assumeUnique; + static assert(is(typeof(arr1) == immutable(int)[])); + assert(arr == null); + assert(arr1 == [0]); +} + +@system unittest +{ + import std.exception; + + int[string] arr = ["a":1]; + auto arr1 = arr.assumeUnique; + static assert(is(typeof(arr1) == immutable(int[string]))); + assert(arr == null); + assert(arr1.keys == ["a"]); +} + +@safe unittest +{ + import std.exception; + + import std.math.algebraic : sqrt; + + // This function may throw. + int squareRoot(int x) + { + if (x < 0) + throw new Exception("Tried to take root of negative number"); + return cast(int) sqrt(cast(double) x); + } + + // This function never throws. + int computeLength(int x, int y) nothrow + { + // Since x*x + y*y is always positive, we can safely assume squareRoot + // won't throw, and use it to implement this nothrow function. If it + // does throw (e.g., if x*x + y*y overflows a 32-bit value), then the + // program will terminate. + return assumeWontThrow(squareRoot(x*x + y*y)); + } + + assert(computeLength(3, 4) == 5); +} + +@system unittest +{ + import std.exception; + + int i = 0; + int* p = null; + assert(!p.doesPointTo(i)); + p = &i; + assert( p.doesPointTo(i)); +} + +@system unittest +{ + import std.exception; + + struct S + { + int v; + int* p; + } + int i; + auto s = S(0, &i); + + // structs and unions "own" their members + // pointsTo will answer true if one of the members pointsTo. + assert(!s.doesPointTo(s.v)); //s.v is just v member of s, so not pointed. + assert( s.p.doesPointTo(i)); //i is pointed by s.p. + assert( s .doesPointTo(i)); //which means i is pointed by s itself. + + // Unions will behave exactly the same. Points to will check each "member" + // individually, even if they share the same memory +} + +@system unittest +{ + import std.exception; + + int i; + // trick the compiler when initializing slice + // https://issues.dlang.org/show_bug.cgi?id=18637 + int* p = &i; + int[] slice = [0, 1, 2, 3, 4]; + int[5] arr = [0, 1, 2, 3, 4]; + int*[] slicep = [p]; + int*[1] arrp = [&i]; + + // A slice points to all of its members: + assert( slice.doesPointTo(slice[3])); + assert(!slice[0 .. 2].doesPointTo(slice[3])); // Object 3 is outside of the + // slice [0 .. 2] + + // Note that a slice will not take into account what its members point to. + assert( slicep[0].doesPointTo(i)); + assert(!slicep .doesPointTo(i)); + + // static arrays are objects that own their members, just like structs: + assert(!arr.doesPointTo(arr[0])); // arr[0] is just a member of arr, so not + // pointed. + assert( arrp[0].doesPointTo(i)); // i is pointed by arrp[0]. + assert( arrp .doesPointTo(i)); // which means i is pointed by arrp + // itself. + + // Notice the difference between static and dynamic arrays: + assert(!arr .doesPointTo(arr[0])); + assert( arr[].doesPointTo(arr[0])); + assert( arrp .doesPointTo(i)); + assert(!arrp[].doesPointTo(i)); +} + +@system unittest +{ + import std.exception; + + class C + { + this(int* p){this.p = p;} + int* p; + } + int i; + C a = new C(&i); + C b = a; + + // Classes are a bit particular, as they are treated like simple pointers + // to a class payload. + assert( a.p.doesPointTo(i)); // a.p points to i. + assert(!a .doesPointTo(i)); // Yet a itself does not point i. + + //To check the class payload itself, iterate on its members: + () + { + import std.traits : Fields; + + foreach (index, _; Fields!C) + if (doesPointTo(a.tupleof[index], i)) + return; + assert(0); + }(); + + // To check if a class points a specific payload, a direct memmory check + // can be done: + auto aLoc = cast(ubyte[__traits(classInstanceSize, C)]*) a; + assert(b.doesPointTo(*aLoc)); // b points to where a is pointing +} + +@safe unittest +{ + import std.exception; + + import core.stdc.errno : EAGAIN; + auto ex = new ErrnoException("oh no", EAGAIN); + assert(ex.errno == EAGAIN); +} + +@safe unittest +{ + import std.exception; + + import core.stdc.errno : errno, EAGAIN; + + auto old = errno; + scope(exit) errno = old; + + // fake that errno got set by the callee + errno = EAGAIN; + auto ex = new ErrnoException("oh no"); + assert(ex.errno == EAGAIN); +} + +@safe unittest +{ + import std.exception; + + import std.conv : to; + assert("x".to!int.ifThrown(0) == 0); +} + +@safe unittest +{ + import std.exception; + + import std.conv : ConvException, to; + string s = "true"; + assert(s.to!int.ifThrown(cast(int) s.to!double) + .ifThrown(cast(int) s.to!bool) == 1); + + s = "2.0"; + assert(s.to!int.ifThrown(cast(int) s.to!double) + .ifThrown(cast(int) s.to!bool) == 2); + + // Respond differently to different types of errors + alias orFallback = (lazy a) => a.ifThrown!ConvException("not a number") + .ifThrown!Exception("number too small"); + + assert(orFallback(enforce("x".to!int < 1).to!string) == "not a number"); + assert(orFallback(enforce("2".to!int < 1).to!string) == "number too small"); +} + +@safe unittest +{ + import std.exception; + + // null and new Object have a common type(Object). + static assert(is(typeof(null.ifThrown(new Object())) == Object)); + static assert(is(typeof((new Object()).ifThrown(null)) == Object)); + + // 1 and new Object do not have a common type. + static assert(!__traits(compiles, 1.ifThrown(new Object()))); + static assert(!__traits(compiles, (new Object()).ifThrown(1))); +} + +@system unittest +{ + import std.exception; + + import std.format : format; + assert("%s".format.ifThrown!Exception(e => typeid(e).name) == "std.format.FormatException"); +} + +pure @safe unittest +{ + import std.exception; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : map, splitter; + import std.conv : to, ConvException; + + auto s = "12,1337z32,54,2,7,9,1z,6,8"; + + // The next line composition will throw when iterated + // as some elements of the input do not convert to integer + auto r = s.splitter(',').map!(a => to!int(a)); + + // Substitute 0 for cases of ConvException + auto h = r.handle!(ConvException, RangePrimitive.front, (e, r) => 0); + assert(h.equal([12, 0, 54, 2, 7, 9, 0, 6, 8])); +} + +pure @safe unittest +{ + import std.exception; + + import std.algorithm.comparison : equal; + import std.range : retro; + import std.utf : UTFException; + + auto str = "hello\xFFworld"; // 0xFF is an invalid UTF-8 code unit + + auto handled = str.handle!(UTFException, RangePrimitive.access, + (e, r) => ' '); // Replace invalid code points with spaces + + assert(handled.equal("hello world")); // `front` is handled, + assert(handled.retro.equal("dlrow olleh")); // as well as `back` +} + +pure @safe unittest +{ + import std.exception; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : map, splitter; + import std.conv : to, ConvException; + + auto s = "12,1337z32,54,2,7,9,1z,6,8"; + + // The next line composition will throw when iterated + // as some elements of the input do not convert to integer + auto r = s.splitter(',').map!(a => to!int(a)); + + // Substitute 0 for cases of ConvException + auto h = r.handle!(ConvException, RangePrimitive.front, (e, r) => 0); + assert(h.equal([12, 0, 54, 2, 7, 9, 0, 6, 8])); +} + +pure @safe unittest +{ + import std.exception; + + import std.algorithm.comparison : equal; + import std.range : retro; + import std.utf : UTFException; + + auto str = "hello\xFFworld"; // 0xFF is an invalid UTF-8 code unit + + auto handled = str.handle!(UTFException, RangePrimitive.access, + (e, r) => ' '); // Replace invalid code points with spaces + + assert(handled.equal("hello world")); // `front` is handled, + assert(handled.retro.equal("dlrow olleh")); // as well as `back` +} + +@safe unittest +{ + import std.exception; + + class MeaCulpa: Exception + { + /// + mixin basicExceptionCtors; + } + + try + throw new MeaCulpa("test"); + catch (MeaCulpa e) + { + assert(e.msg == "test"); + assert(e.file == __FILE__); + assert(e.line == __LINE__ - 5); + } +} + +@safe pure nothrow unittest +{ + import std.exception; + + class TestException : Exception { mixin basicExceptionCtors; } + auto e = new Exception("msg"); + auto te1 = new TestException("foo"); + auto te2 = new TestException("foo", e); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_affix_allocator.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_affix_allocator.d new file mode 100644 index 000000000000..6b99e4e51f23 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_affix_allocator.d @@ -0,0 +1,14 @@ +@system unittest +{ + import std.experimental.allocator.building_blocks.affix_allocator; + + import std.experimental.allocator.mallocator : Mallocator; + // One word before and after each allocation. + alias A = AffixAllocator!(Mallocator, size_t, size_t); + auto b = A.instance.allocate(11); + A.instance.prefix(b) = 0xCAFE_BABE; + A.instance.suffix(b) = 0xDEAD_BEEF; + assert(A.instance.prefix(b) == 0xCAFE_BABE + && A.instance.suffix(b) == 0xDEAD_BEEF); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_aligned_block_list.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_aligned_block_list.d new file mode 100644 index 000000000000..b1d97226142b --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_aligned_block_list.d @@ -0,0 +1,139 @@ +@system unittest +{ + import std.experimental.allocator.building_blocks.aligned_block_list; + + import std.experimental.allocator.building_blocks.ascending_page_allocator : AscendingPageAllocator; + import std.experimental.allocator.building_blocks.segregator : Segregator; + import std.experimental.allocator.building_blocks.bitmapped_block : BitmappedBlock; + import std.typecons : Ternary; + + /* + In this example we use 'AlignedBlockList' in conjunction with other allocators + in order to create a more complex allocator. + + The 'SuperAllocator' uses a 'Segregator' to distribute allocations to sub-allocators, + based on the requested size. + + Each sub-allocator is represented by an 'AlignedBlockList' of 'BitmappedBlocks'. + Each 'AlignedBlockList' draws memory from a root allocator which in this case is an 'AscendingPageAllocator' + + Such an allocator not only provides good performance, but also a low degree of memory fragmentation. + */ + alias SuperAllocator = Segregator!( + 32, + AlignedBlockList!(BitmappedBlock!32, AscendingPageAllocator*, 1 << 12), + Segregator!( + + 64, + AlignedBlockList!(BitmappedBlock!64, AscendingPageAllocator*, 1 << 12), + Segregator!( + + 128, + AlignedBlockList!(BitmappedBlock!128, AscendingPageAllocator*, 1 << 12), + AscendingPageAllocator* + ))); + + SuperAllocator a; + auto pageAlloc = AscendingPageAllocator(128 * 4096); + + // Set the parent allocator for all the sub allocators + a.allocatorForSize!256 = &pageAlloc; + a.allocatorForSize!128.parent = &pageAlloc; + a.allocatorForSize!64.parent = &pageAlloc; + a.allocatorForSize!32.parent = &pageAlloc; + + enum testNum = 10; + void[][testNum] buf; + + // Allocations of size 32 will go to the first 'AlignedBlockList' + foreach (j; 0 .. testNum) + { + buf[j] = a.allocate(32); + assert(buf[j].length == 32); + + // This is owned by the first 'AlignedBlockList' + assert(a.allocatorForSize!32.owns(buf[j]) == Ternary.yes); + } + + // Free the memory + foreach (j; 0 .. testNum) + assert(a.deallocate(buf[j])); + + // Allocations of size 64 will go to the second 'AlignedBlockList' + foreach (j; 0 .. testNum) + { + buf[j] = a.allocate(64); + assert(buf[j].length == 64); + + // This is owned by the second 'AlignedBlockList' + assert(a.allocatorForSize!64.owns(buf[j]) == Ternary.yes); + } + + // Free the memory + foreach (j; 0 .. testNum) + assert(a.deallocate(buf[j])); + + // Allocations of size 128 will go to the third 'AlignedBlockList' + foreach (j; 0 .. testNum) + { + buf[j] = a.allocate(128); + assert(buf[j].length == 128); + + // This is owned by the third 'AlignedBlockList' + assert(a.allocatorForSize!128.owns(buf[j]) == Ternary.yes); + } + + // Free the memory + foreach (j; 0 .. testNum) + assert(a.deallocate(buf[j])); + + // Allocations which exceed 128, will go to the 'AscendingPageAllocator*' + void[] b = a.allocate(256); + assert(b.length == 256); + a.deallocate(b); +} + +@system unittest +{ + import std.experimental.allocator.building_blocks.aligned_block_list; + + import std.experimental.allocator.building_blocks.region : SharedBorrowedRegion; + import std.experimental.allocator.building_blocks.ascending_page_allocator : SharedAscendingPageAllocator; + import std.experimental.allocator.building_blocks.null_allocator : NullAllocator; + import core.thread : ThreadGroup; + + enum numThreads = 8; + enum size = 2048; + enum maxIter = 10; + + /* + In this example we use 'SharedAlignedBlockList' together with + 'SharedBorrowedRegion', in order to create a fast, thread-safe allocator. + */ + alias SuperAllocator = SharedAlignedBlockList!( + SharedBorrowedRegion!(1), + SharedAscendingPageAllocator, + 4096); + + SuperAllocator a; + // The 'SuperAllocator' will draw memory from a 'SharedAscendingPageAllocator' + a.parent = SharedAscendingPageAllocator(4096 * 1024); + + // Launch 'numThreads', each performing allocations + void fun() + { + foreach (i; 0 .. maxIter) + { + void[] b = a.allocate(size); + assert(b.length == size); + } + } + + auto tg = new ThreadGroup; + foreach (i; 0 .. numThreads) + { + tg.create(&fun); + } + tg.joinAll(); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_allocator_list.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_allocator_list.d new file mode 100644 index 000000000000..e43d9616ddab --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_allocator_list.d @@ -0,0 +1,45 @@ +@system unittest +{ + import std.experimental.allocator.building_blocks.allocator_list; + + import std.algorithm.comparison : max; + import std.experimental.allocator.building_blocks.free_list : ContiguousFreeList; + import std.experimental.allocator.building_blocks.null_allocator : NullAllocator; + import std.experimental.allocator.building_blocks.region : Region; + import std.experimental.allocator.building_blocks.segregator : Segregator; + import std.experimental.allocator.gc_allocator : GCAllocator; + import std.experimental.allocator.mmap_allocator : MmapAllocator; + + // Ouroboros allocator list based upon 4MB regions, fetched directly from + // mmap. All memory is released upon destruction. + alias A1 = AllocatorList!((n) => Region!MmapAllocator(max(n, 1024 * 4096)), + NullAllocator); + + // Allocator list based upon 4MB regions, fetched from the garbage + // collector. All memory is released upon destruction. + alias A2 = AllocatorList!((n) => Region!GCAllocator(max(n, 1024 * 4096))); + + // Ouroboros allocator list based upon 4MB regions, fetched from the garbage + // collector. Memory is left to the collector. + alias A3 = AllocatorList!( + (n) => Region!NullAllocator(new ubyte[max(n, 1024 * 4096)]), + NullAllocator); + + // Allocator list that creates one freelist for all objects + alias A4 = + Segregator!( + 64, AllocatorList!( + (n) => ContiguousFreeList!(NullAllocator, 0, 64)( + cast(ubyte[])(GCAllocator.instance.allocate(4096)))), + GCAllocator); + + A4 a; + auto small = a.allocate(64); + assert(small); + a.deallocate(small); + auto b1 = a.allocate(1024 * 8192); + assert(b1 !is null); // still works due to overdimensioning + b1 = a.allocate(1024 * 10); + assert(b1.length == 1024 * 10); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_ascending_page_allocator.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_ascending_page_allocator.d new file mode 100644 index 000000000000..086714dbd095 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_ascending_page_allocator.d @@ -0,0 +1,52 @@ +@system @nogc nothrow unittest +{ + import std.experimental.allocator.building_blocks.ascending_page_allocator; + + import core.memory : pageSize; + + size_t numPages = 100; + void[] buf; + void[] prevBuf = null; + AscendingPageAllocator a = AscendingPageAllocator(numPages * pageSize); + + foreach (i; 0 .. numPages) + { + // Allocation is rounded up to page size + buf = a.allocate(pageSize - 100); + assert(buf.length == pageSize - 100); + + // Allocations are served at increasing addresses + if (prevBuf) + assert(prevBuf.ptr + pageSize == buf.ptr); + + assert(a.deallocate(buf)); + prevBuf = buf; + } +} + +@system unittest +{ + import std.experimental.allocator.building_blocks.ascending_page_allocator; + + import core.memory : pageSize; + import core.thread : ThreadGroup; + + enum numThreads = 100; + shared SharedAscendingPageAllocator a = SharedAscendingPageAllocator(pageSize * numThreads); + + void fun() + { + void[] b = a.allocate(pageSize); + assert(b.length == pageSize); + + assert(a.deallocate(b)); + } + + auto tg = new ThreadGroup; + foreach (i; 0 .. numThreads) + { + tg.create(&fun); + } + tg.joinAll(); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_bitmapped_block.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_bitmapped_block.d new file mode 100644 index 000000000000..e3a3865aa183 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_bitmapped_block.d @@ -0,0 +1,139 @@ +@system unittest +{ + import std.experimental.allocator.building_blocks.bitmapped_block; + + // Create a block allocator on top of a 10KB stack region. + import std.experimental.allocator.building_blocks.region : InSituRegion; + import std.traits : hasMember; + InSituRegion!(10_240, 64) r; + auto a = BitmappedBlock!(64, 64)(cast(ubyte[])(r.allocateAll())); + static assert(hasMember!(InSituRegion!(10_240, 64), "allocateAll")); + const b = a.allocate(100); + assert(b.length == 100); +} + +@system unittest +{ + import std.experimental.allocator.building_blocks.bitmapped_block; + + import std.experimental.allocator.mallocator : Mallocator; + import std.typecons : Flag, Yes; + + enum blockSize = 64; + enum numBlocks = 10; + + // The 'BitmappedBlock' is implicitly instantiated with Yes.multiblock + auto a = BitmappedBlock!(blockSize, 8, Mallocator, Yes.multiblock)(numBlocks * blockSize); + + // Instantiated with Yes.multiblock, can allocate more than one block at a time + void[] buf = a.allocate(2 * blockSize); + assert(buf.length == 2 * blockSize); + assert(a.deallocate(buf)); + + // Can also allocate less than one block + buf = a.allocate(blockSize / 2); + assert(buf.length == blockSize / 2); + + // Expands inside the same block + assert(a.expand(buf, blockSize / 2)); + assert(buf.length == blockSize); + + // If Yes.multiblock, can expand past the size of a single block + assert(a.expand(buf, 3 * blockSize)); + assert(buf.length == 4 * blockSize); + assert(a.deallocate(buf)); +} + +@system unittest +{ + import std.experimental.allocator.building_blocks.bitmapped_block; + + import std.experimental.allocator.mallocator : Mallocator; + import std.typecons : Flag, No; + + enum blockSize = 64; + auto a = BitmappedBlock!(blockSize, 8, Mallocator, No.multiblock)(1024 * blockSize); + + // Since instantiated with No.multiblock, can only allocate at most the block size + void[] buf = a.allocate(blockSize + 1); + assert(buf is null); + + buf = a.allocate(blockSize); + assert(buf.length == blockSize); + assert(a.deallocate(buf)); + + // This is also fine, because it's less than the block size + buf = a.allocate(blockSize / 2); + assert(buf.length == blockSize / 2); + + // Can expand the buffer until its length is at most 64 + assert(a.expand(buf, blockSize / 2)); + assert(buf.length == blockSize); + + // Cannot expand anymore + assert(!a.expand(buf, 1)); + assert(a.deallocate(buf)); +} + +@system unittest +{ + import std.experimental.allocator.building_blocks.bitmapped_block; + + import std.experimental.allocator.mallocator : Mallocator; + import std.experimental.allocator.common : platformAlignment; + import std.typecons : Flag, Yes, No; + + // Create 'numThreads' threads, each allocating in parallel a chunk of memory + static void testAlloc(Allocator)(ref Allocator a, size_t allocSize) + { + import core.thread : ThreadGroup; + import std.algorithm.sorting : sort; + import core.internal.spinlock : SpinLock; + + SpinLock lock = SpinLock(SpinLock.Contention.brief); + enum numThreads = 10; + void[][numThreads] buf; + size_t count = 0; + + // Each threads allocates 'allocSize' + void fun() + { + void[] b = a.allocate(allocSize); + assert(b.length == allocSize); + + lock.lock(); + scope(exit) lock.unlock(); + + buf[count] = b; + count++; + } + + auto tg = new ThreadGroup; + foreach (i; 0 .. numThreads) + { + tg.create(&fun); + } + tg.joinAll(); + + // Sorting the allocations made by each thread, we expect the buffers to be + // adjacent inside the SharedBitmappedBlock + sort!((a, b) => a.ptr < b.ptr)(buf[0 .. numThreads]); + foreach (i; 0 .. numThreads - 1) + { + assert(buf[i].ptr + a.goodAllocSize(buf[i].length) <= buf[i + 1].ptr); + } + + // Deallocate everything + foreach (i; 0 .. numThreads) + { + assert(a.deallocate(buf[i])); + } + } + + enum blockSize = 64; + auto alloc1 = SharedBitmappedBlock!(blockSize, platformAlignment, Mallocator, Yes.multiblock)(1024 * 1024); + auto alloc2 = SharedBitmappedBlock!(blockSize, platformAlignment, Mallocator, No.multiblock)(1024 * 1024); + testAlloc(alloc1, 2 * blockSize); + testAlloc(alloc2, blockSize); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_bucketizer.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_bucketizer.d new file mode 100644 index 000000000000..b1282b48abdd --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_bucketizer.d @@ -0,0 +1,23 @@ +@system unittest +{ + import std.experimental.allocator.building_blocks.bucketizer; + + import std.algorithm.comparison : max; + import std.experimental.allocator.building_blocks.allocator_list : AllocatorList; + import std.experimental.allocator.building_blocks.free_list : FreeList; + import std.experimental.allocator.building_blocks.region : Region; + import std.experimental.allocator.common : unbounded; + import std.experimental.allocator.mallocator : Mallocator; + import std.typecons : Ternary; + Bucketizer!( + FreeList!( + AllocatorList!( + (size_t n) => Region!Mallocator(max(n, 1024 * 1024))), + 0, unbounded), + 65, 512, 64) a; + auto b = a.allocate(400); + assert(b.length == 400); + assert(a.owns(b) == Ternary.yes); + a.deallocate(b); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_fallback_allocator.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_fallback_allocator.d new file mode 100644 index 000000000000..6d89972266ff --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_fallback_allocator.d @@ -0,0 +1,16 @@ +@system unittest +{ + import std.experimental.allocator.building_blocks.fallback_allocator; + + import std.experimental.allocator.building_blocks.region : Region; + import std.experimental.allocator.gc_allocator : GCAllocator; + import std.typecons : Ternary; + auto a = fallbackAllocator(Region!GCAllocator(1024), GCAllocator.instance); + auto b1 = a.allocate(1020); + assert(b1.length == 1020); + assert(a.primary.owns(b1) == Ternary.yes); + auto b2 = a.allocate(10); + assert(b2.length == 10); + assert(a.primary.owns(b2) == Ternary.no); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_free_list.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_free_list.d new file mode 100644 index 000000000000..d15e4e562f8a --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_free_list.d @@ -0,0 +1,45 @@ +@safe unittest +{ + import std.experimental.allocator.building_blocks.free_list; + + import std.experimental.allocator.building_blocks.allocator_list + : AllocatorList; + import std.experimental.allocator.gc_allocator : GCAllocator; + + import std.experimental.allocator.common : unbounded; + + alias ScalableFreeList = AllocatorList!((n) => + ContiguousFreeList!(GCAllocator, 0, unbounded)(4096) + ); +} + +@safe unittest +{ + import std.experimental.allocator.building_blocks.free_list; + + import std.experimental.allocator.common : chooseAtRuntime; + import std.experimental.allocator.mallocator : Mallocator; + + shared SharedFreeList!(Mallocator, chooseAtRuntime, chooseAtRuntime) a; + a.setBounds(64, 128); + assert(a.max == 128); + assert(a.min == 64); +} + +@safe unittest +{ + import std.experimental.allocator.building_blocks.free_list; + + import std.experimental.allocator.common : chooseAtRuntime; + import std.experimental.allocator.mallocator : Mallocator; + + shared SharedFreeList!(Mallocator, 50, 50, chooseAtRuntime) a; + // Set the maxSize first so setting the minSize doesn't throw + a.approxMaxLength = 128; + assert(a.approxMaxLength == 128); + a.approxMaxLength = 1024; + assert(a.approxMaxLength == 1024); + a.approxMaxLength = 1; + assert(a.approxMaxLength == 1); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_kernighan_ritchie.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_kernighan_ritchie.d new file mode 100644 index 000000000000..18e63b33577d --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_kernighan_ritchie.d @@ -0,0 +1,40 @@ +@system unittest +{ + import std.experimental.allocator.building_blocks.kernighan_ritchie; + + import std.experimental.allocator.gc_allocator : GCAllocator; + auto alloc = KRRegion!GCAllocator(1024 * 64); + const b1 = alloc.allocate(2048); + assert(b1.length == 2048); + const b2 = alloc.allocateAll; + assert(b2.length == 1024 * 62); + +} + +@system unittest +{ + import std.experimental.allocator.building_blocks.kernighan_ritchie; + + import std.experimental.allocator.building_blocks.fallback_allocator + : fallbackAllocator; + import std.experimental.allocator.gc_allocator : GCAllocator; + import std.typecons : Ternary; + // KRRegion fronting a general-purpose allocator + align(KRRegion!().alignment) ubyte[1024 * 128] buf; + auto alloc = fallbackAllocator(KRRegion!()(buf), GCAllocator.instance); + auto b = alloc.allocate(100); + assert(b.length == 100); + assert((() pure nothrow @safe @nogc => alloc.primary.owns(b))() == Ternary.yes); +} + +@system unittest +{ + import std.experimental.allocator.building_blocks.kernighan_ritchie; + + import std.algorithm.comparison : max; + import std.experimental.allocator.building_blocks.allocator_list + : AllocatorList; + import std.experimental.allocator.mmap_allocator : MmapAllocator; + AllocatorList!(n => KRRegion!MmapAllocator(max(n * 16, 1024 * 1024))) alloc; +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_quantizer.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_quantizer.d new file mode 100644 index 000000000000..deaae0e8c217 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_quantizer.d @@ -0,0 +1,23 @@ +@system unittest +{ + import std.experimental.allocator.building_blocks.quantizer; + + import std.experimental.allocator.building_blocks.free_tree : FreeTree; + import std.experimental.allocator.gc_allocator : GCAllocator; + + size_t roundUpToMultipleOf(size_t s, uint base) + { + auto rem = s % base; + return rem ? s + base - rem : s; + } + + // Quantize small allocations to a multiple of cache line, large ones to a + // multiple of page size + alias MyAlloc = Quantizer!( + FreeTree!GCAllocator, + n => roundUpToMultipleOf(n, n <= 16_384 ? 64 : 4096)); + MyAlloc alloc; + const buf = alloc.allocate(256); + assert(buf.ptr); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_region.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_region.d new file mode 100644 index 000000000000..8b4e2be9bc3a --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_region.d @@ -0,0 +1,90 @@ +@system nothrow unittest +{ + import std.experimental.allocator.building_blocks.region; + + import std.algorithm.comparison : max; + import std.experimental.allocator.building_blocks.allocator_list + : AllocatorList; + import std.experimental.allocator.mallocator : Mallocator; + import std.typecons : Ternary; + // Create a scalable list of regions. Each gets at least 1MB at a time by + // using malloc. + auto batchAllocator = AllocatorList!( + (size_t n) => Region!Mallocator(max(n, 1024 * 1024)) + )(); + assert(batchAllocator.empty == Ternary.yes); + auto b = batchAllocator.allocate(101); + assert(b.length == 101); + assert(batchAllocator.empty == Ternary.no); + // This will cause a second allocation + b = batchAllocator.allocate(2 * 1024 * 1024); + assert(b.length == 2 * 1024 * 1024); + // Destructor will free the memory +} + +@system nothrow @nogc unittest +{ + import std.experimental.allocator.building_blocks.region; + + import std.typecons : Ternary; + + ubyte[1024] store; + auto myRegion = BorrowedRegion!(1)(store[]); + + assert(myRegion.empty == Ternary.yes); + assert(myRegion.available == store.length); + + void[] b = myRegion.allocate(101); + + assert(b.length == 101); + assert(myRegion.empty == Ternary.no); + assert(myRegion.owns(b) == Ternary.yes); + assert(myRegion.available == store.length - b.length); + + void[] b2 = myRegion.allocate(256); + + // Can only free the most recent allocation + assert(myRegion.deallocate(b) == false); + assert(myRegion.deallocate(b2) == true); + + myRegion.deallocateAll(); + + assert(myRegion.empty == Ternary.yes); +} + +@system unittest +{ + import std.experimental.allocator.building_blocks.region; + + // 128KB region, allocated to x86's cache line + InSituRegion!(128 * 1024, 16) r1; + auto a1 = r1.allocate(101); + assert(a1.length == 101); + + // 128KB region, with fallback to the garbage collector. + import std.experimental.allocator.building_blocks.fallback_allocator + : FallbackAllocator; + import std.experimental.allocator.building_blocks.free_list + : FreeList; + import std.experimental.allocator.building_blocks.bitmapped_block + : BitmappedBlock; + import std.experimental.allocator.gc_allocator : GCAllocator; + FallbackAllocator!(InSituRegion!(128 * 1024), GCAllocator) r2; + const a2 = r2.allocate(102); + assert(a2.length == 102); + + // Reap with GC fallback. + InSituRegion!(128 * 1024, 8) tmp3; + FallbackAllocator!(BitmappedBlock!(64, 8), GCAllocator) r3; + r3.primary = BitmappedBlock!(64, 8)(cast(ubyte[]) (tmp3.allocateAll())); + const a3 = r3.allocate(103); + assert(a3.length == 103); + + // Reap/GC with a freelist for small objects up to 16 bytes. + InSituRegion!(128 * 1024, 64) tmp4; + FreeList!(FallbackAllocator!(BitmappedBlock!(64, 64), GCAllocator), 0, 16) r4; + r4.parent.primary = BitmappedBlock!(64, 64)(cast(ubyte[]) (tmp4.allocateAll())); + const a4 = r4.allocate(104); + assert(a4.length == 104); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_scoped_allocator.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_scoped_allocator.d new file mode 100644 index 000000000000..923f621ca62f --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_scoped_allocator.d @@ -0,0 +1,13 @@ +@system unittest +{ + import std.experimental.allocator.building_blocks.scoped_allocator; + + import std.experimental.allocator.mallocator : Mallocator; + import std.typecons : Ternary; + ScopedAllocator!Mallocator alloc; + assert(alloc.empty == Ternary.yes); + const b = alloc.allocate(10); + assert(b.length == 10); + assert(alloc.empty == Ternary.no); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_segregator.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_segregator.d new file mode 100644 index 000000000000..49ee6344480a --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_segregator.d @@ -0,0 +1,43 @@ +@system unittest +{ + import std.experimental.allocator.building_blocks.segregator; + + import std.experimental.allocator.building_blocks.free_list : FreeList; + import std.experimental.allocator.gc_allocator : GCAllocator; + import std.experimental.allocator.mallocator : Mallocator; + alias A = + Segregator!( + 1024 * 4, + Segregator!( + 128, FreeList!(Mallocator, 0, 128), + GCAllocator), + Segregator!( + 1024 * 1024, Mallocator, + GCAllocator) + ); + A a; + auto b = a.allocate(200); + assert(b.length == 200); + a.deallocate(b); +} + +@system unittest +{ + import std.experimental.allocator.building_blocks.segregator; + + import std.experimental.allocator.building_blocks.free_list : FreeList; + import std.experimental.allocator.gc_allocator : GCAllocator; + import std.experimental.allocator.mallocator : Mallocator; + alias A = + Segregator!( + 128, FreeList!(Mallocator, 0, 128), + 1024 * 4, GCAllocator, + 1024 * 1024, Mallocator, + GCAllocator + ); + A a; + auto b = a.allocate(201); + assert(b.length == 201); + a.deallocate(b); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_stats_collector.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_stats_collector.d new file mode 100644 index 000000000000..1fbed435e3f7 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_building_blocks_stats_collector.d @@ -0,0 +1,33 @@ +@safe unittest +{ + import std.experimental.allocator.building_blocks.stats_collector; + + import std.experimental.allocator.gc_allocator : GCAllocator; + import std.experimental.allocator.building_blocks.free_list : FreeList; + alias Allocator = StatsCollector!(GCAllocator, Options.bytesUsed); +} + +@system unittest +{ + import std.experimental.allocator.building_blocks.stats_collector; + + import std.experimental.allocator.building_blocks.free_list : FreeList; + import std.experimental.allocator.gc_allocator : GCAllocator; + alias Allocator = StatsCollector!(GCAllocator, Options.all, Options.all); + + Allocator alloc; + auto b = alloc.allocate(10); + alloc.reallocate(b, 20); + alloc.deallocate(b); + + import std.file : deleteme, remove; + import std.range : walkLength; + import std.stdio : File; + + auto f = deleteme ~ "-dlang.std.experimental.allocator.stats_collector.txt"; + scope(exit) remove(f); + Allocator.reportPerCallStatistics(File(f, "w")); + alloc.reportStatistics(File(f, "a")); + assert(File(f).byLine.walkLength == 24); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_common.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_common.d new file mode 100644 index 000000000000..4751c010552a --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_common.d @@ -0,0 +1,33 @@ +@safe @nogc nothrow pure unittest +{ + import std.experimental.allocator.common; + + import std.experimental.allocator.building_blocks.null_allocator : NullAllocator; + import std.experimental.allocator.mallocator : Mallocator; + import std.experimental.allocator.gc_allocator : GCAllocator; + import std.experimental.allocator.mmap_allocator : MmapAllocator; + static assert(isAllocator!NullAllocator); + static assert(isAllocator!Mallocator); + static assert(isAllocator!GCAllocator); + static assert(isAllocator!MmapAllocator); + static assert(!isAllocator!int); +} + +@safe @nogc nothrow pure unittest +{ + import std.experimental.allocator.common; + + import std.experimental.allocator.building_blocks.null_allocator : NullAllocator; + import std.experimental.allocator.mallocator : Mallocator; + import std.experimental.allocator.gc_allocator : GCAllocator; + import std.experimental.allocator.mmap_allocator : MmapAllocator; + struct S + { + mixin AllocatorState!NullAllocator n; + mixin AllocatorState!GCAllocator g; + mixin AllocatorState!Mallocator m; + mixin AllocatorState!MmapAllocator p; + } + static assert(S.sizeof == 1); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_gc_allocator.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_gc_allocator.d new file mode 100644 index 000000000000..a6615b77aa42 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_gc_allocator.d @@ -0,0 +1,10 @@ +pure @system unittest +{ + import std.experimental.allocator.gc_allocator; + + auto buffer = GCAllocator.instance.allocate(1024 * 1024 * 4); + // deallocate upon scope's end (alternatively: leave it to collection) + scope(exit) GCAllocator.instance.deallocate(buffer); + //... +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_mallocator.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_mallocator.d new file mode 100644 index 000000000000..76fb3ec25395 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_mallocator.d @@ -0,0 +1,19 @@ +@nogc @system nothrow unittest +{ + import std.experimental.allocator.mallocator; + + auto buffer = Mallocator.instance.allocate(1024 * 1024 * 4); + scope(exit) Mallocator.instance.deallocate(buffer); + //... +} + +pure @nogc @system nothrow unittest +{ + import std.experimental.allocator.mallocator; + + auto buffer = AlignedMallocator.instance.alignedAllocate(1024 * 1024 * 4, + 128); + scope(exit) AlignedMallocator.instance.deallocate(buffer); + //... +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_package.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_package.d new file mode 100644 index 000000000000..e19efc54c0d0 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_package.d @@ -0,0 +1,263 @@ +@system unittest +{ + import std.experimental.allocator; + + // Install a new allocator that is faster for 128-byte allocations. + import std.experimental.allocator.building_blocks.free_list : FreeList; + import std.experimental.allocator.gc_allocator : GCAllocator; + auto oldAllocator = theAllocator; + scope(exit) theAllocator = oldAllocator; + theAllocator = allocatorObject(FreeList!(GCAllocator, 128)()); + // Use the now changed allocator to allocate an array + const ubyte[] arr = theAllocator.makeArray!ubyte(128); + assert(arr.ptr); + //... +} + +@system unittest +{ + import std.experimental.allocator; + + // Dynamically allocate one integer + const int* p1 = theAllocator.make!int; + // It's implicitly initialized with its .init value + assert(*p1 == 0); + // Dynamically allocate one double, initialize to 42.5 + const double* p2 = theAllocator.make!double(42.5); + assert(*p2 == 42.5); + + // Dynamically allocate a struct + static struct Point + { + int x, y, z; + } + // Use the generated constructor taking field values in order + const Point* p = theAllocator.make!Point(1, 2); + assert(p.x == 1 && p.y == 2 && p.z == 0); + + // Dynamically allocate a class object + static class Customer + { + uint id = uint.max; + this() {} + this(uint id) { this.id = id; } + // ... + } + Customer cust = theAllocator.make!Customer; + assert(cust.id == uint.max); // default initialized + cust = theAllocator.make!Customer(42); + assert(cust.id == 42); + + // explicit passing of outer pointer + static class Outer + { + int x = 3; + class Inner + { + auto getX() { return x; } + } + } + auto outer = theAllocator.make!Outer(); + auto inner = theAllocator.make!(Outer.Inner)(outer); + assert(outer.x == inner.getX); +} + +@system unittest +{ + import std.experimental.allocator; + + import std.algorithm.comparison : equal; + static void test(T)() + { + T[] a = theAllocator.makeArray!T(2); + assert(a.equal([0, 0])); + a = theAllocator.makeArray!T(3, 42); + assert(a.equal([42, 42, 42])); + import std.range : only; + a = theAllocator.makeArray!T(only(42, 43, 44)); + assert(a.equal([42, 43, 44])); + } + test!int(); + test!(shared int)(); + test!(const int)(); + test!(immutable int)(); +} + +@system unittest +{ + import std.experimental.allocator; + + auto arr = theAllocator.makeArray!int([1, 2, 3]); + assert(theAllocator.expandArray(arr, 2)); + assert(arr == [1, 2, 3, 0, 0]); + import std.range : only; + assert(theAllocator.expandArray(arr, only(4, 5))); + assert(arr == [1, 2, 3, 0, 0, 4, 5]); +} + +@system unittest +{ + import std.experimental.allocator; + + int[] a = theAllocator.makeArray!int(100, 42); + assert(a.length == 100); + assert(theAllocator.shrinkArray(a, 98)); + assert(a.length == 2); + assert(a == [42, 42]); +} + +@system unittest +{ + import std.experimental.allocator; + + import std.experimental.allocator.mallocator : Mallocator; + + auto mArray = Mallocator.instance.makeMultidimensionalArray!int(2, 3, 6); + + // deallocate when exiting scope + scope(exit) + { + Mallocator.instance.disposeMultidimensionalArray(mArray); + } + + assert(mArray.length == 2); + foreach (lvl2Array; mArray) + { + assert(lvl2Array.length == 3); + foreach (lvl3Array; lvl2Array) + assert(lvl3Array.length == 6); + } +} + +@system unittest +{ + import std.experimental.allocator; + + struct TestAllocator + { + import std.experimental.allocator.common : platformAlignment; + import std.experimental.allocator.mallocator : Mallocator; + + alias allocator = Mallocator.instance; + + private static struct ByteRange + { + void* ptr; + size_t length; + } + + private ByteRange[] _allocations; + + enum uint alignment = platformAlignment; + + void[] allocate(size_t numBytes) + { + auto ret = allocator.allocate(numBytes); + _allocations ~= ByteRange(ret.ptr, ret.length); + return ret; + } + + bool deallocate(void[] bytes) + { + import std.algorithm.mutation : remove; + import std.algorithm.searching : canFind; + + bool pred(ByteRange other) + { return other.ptr == bytes.ptr && other.length == bytes.length; } + + assert(_allocations.canFind!pred); + + _allocations = _allocations.remove!pred; + return allocator.deallocate(bytes); + } + + ~this() + { + assert(!_allocations.length); + } + } + + TestAllocator allocator; + + auto mArray = allocator.makeMultidimensionalArray!int(2, 3, 5, 6, 7, 2); + + allocator.disposeMultidimensionalArray(mArray); +} + +@system unittest +{ + import std.experimental.allocator; + + import std.experimental.allocator.mallocator : Mallocator; + + RCIAllocator a = allocatorObject(Mallocator.instance); + auto b = a.allocate(100); + assert(b.length == 100); + assert(a.deallocate(b)); + + // The in-situ region must be used by pointer + import std.experimental.allocator.building_blocks.region : InSituRegion; + auto r = InSituRegion!1024(); + a = allocatorObject(&r); + b = a.allocate(200); + assert(b.length == 200); + // In-situ regions can deallocate the last allocation + assert(a.deallocate(b)); +} + +@system unittest +{ + import std.experimental.allocator; + + import std.experimental.allocator.building_blocks.free_list : FreeList; + import std.experimental.allocator.gc_allocator : GCAllocator; + import std.experimental.allocator.mallocator : Mallocator; + + static assert(!is(ThreadLocal!Mallocator)); + static assert(!is(ThreadLocal!GCAllocator)); + alias Allocator = ThreadLocal!(FreeList!(GCAllocator, 0, 8)); + auto b = Allocator.instance.allocate(5); + static assert(__traits(hasMember, Allocator, "allocate")); +} + +@system unittest +{ + import std.experimental.allocator; + + import std.experimental.allocator.building_blocks.allocator_list : AllocatorList; + import std.experimental.allocator.building_blocks.bitmapped_block : BitmappedBlock; + import std.experimental.allocator.building_blocks.segregator : Segregator; + import std.experimental.allocator.building_blocks.bucketizer : Bucketizer; + import std.experimental.allocator.building_blocks.free_list : FreeList; + import std.experimental.allocator.gc_allocator : GCAllocator; + + /// Define an allocator bound to the built-in GC. + auto alloc = allocatorObject(GCAllocator.instance); + auto b = alloc.allocate(42); + assert(b.length == 42); + assert(alloc.deallocate(b)); + + import std.algorithm.comparison : max; + // Define an elaborate allocator and bind it to the class API. + alias FList = FreeList!(GCAllocator, 0, unbounded); + alias A = ThreadLocal!( + Segregator!( + 8, FreeList!(GCAllocator, 0, 8), + 128, Bucketizer!(FList, 1, 128, 16), + 256, Bucketizer!(FList, 129, 256, 32), + 512, Bucketizer!(FList, 257, 512, 64), + 1024, Bucketizer!(FList, 513, 1024, 128), + 2048, Bucketizer!(FList, 1025, 2048, 256), + 3584, Bucketizer!(FList, 2049, 3584, 512), + 4072 * 1024, AllocatorList!( + (n) => BitmappedBlock!(4096)(cast(ubyte[]) GCAllocator.instance.allocate( + max(n, 4072 * 1024)))), + GCAllocator + ) + ); + + auto alloc2 = allocatorObject(A.instance); + b = alloc2.allocate(101); + assert(alloc2.deallocate(b)); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_showcase.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_showcase.d new file mode 100644 index 000000000000..3cbb19cda3b2 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_showcase.d @@ -0,0 +1,22 @@ +@system unittest +{ + import std.experimental.allocator.showcase; + + StackFront!4096 a; + auto b = a.allocate(4000); + assert(b.length == 4000); + auto c = a.allocate(4000); + assert(c.length == 4000); + a.deallocate(b); + a.deallocate(c); +} + +@system unittest +{ + import std.experimental.allocator.showcase; + + auto alloc = mmapRegionList(1024 * 1024); + const b = alloc.allocate(100); + assert(b.length == 100); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_typed.d b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_typed.d new file mode 100644 index 000000000000..d9f0880144ad --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_experimental_allocator_typed.d @@ -0,0 +1,34 @@ +@system unittest +{ + import std.experimental.allocator.typed; + + import std.experimental.allocator.gc_allocator : GCAllocator; + import std.experimental.allocator.mallocator : Mallocator; + import std.experimental.allocator.mmap_allocator : MmapAllocator; + alias MyAllocator = TypedAllocator!(GCAllocator, + AllocFlag.fixedSize | AllocFlag.threadLocal, Mallocator, + AllocFlag.fixedSize | AllocFlag.threadLocal + | AllocFlag.hasNoIndirections, + MmapAllocator, + ); + + MyAllocator a; + auto b = &a.allocatorFor!0(); + static assert(is(typeof(*b) == shared const(GCAllocator))); + enum f1 = AllocFlag.fixedSize | AllocFlag.threadLocal; + auto c = &a.allocatorFor!f1(); + static assert(is(typeof(*c) == Mallocator)); + enum f2 = AllocFlag.fixedSize | AllocFlag.threadLocal; + static assert(is(typeof(a.allocatorFor!f2()) == Mallocator)); + // Partial match + enum f3 = AllocFlag.threadLocal; + static assert(is(typeof(a.allocatorFor!f3()) == Mallocator)); + + int* p = a.make!int; + scope(exit) a.dispose(p); + int[] arr = a.makeArray!int(42); + scope(exit) a.dispose(arr); + assert(a.expandArray(arr, 3)); + assert(a.shrinkArray(arr, 4)); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_file.d b/libphobos/testsuite/libphobos.phobos/std_file.d new file mode 100644 index 000000000000..49626d860dae --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_file.d @@ -0,0 +1,756 @@ +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + assertThrown!FileException("non.existing.file.".readText); +} + +@safe unittest +{ + import std.file; + + import std.utf : byChar; + scope(exit) + { + assert(exists(deleteme)); + remove(deleteme); + } + + std.file.write(deleteme, "1234"); // deleteme is the name of a temporary file + assert(read(deleteme, 2) == "12"); + assert(read(deleteme.byChar) == "1234"); + assert((cast(const(ubyte)[])read(deleteme)).length == 4); +} + +@safe unittest +{ + import std.file; + + write(deleteme, "abc"); // deleteme is the name of a temporary file + scope(exit) remove(deleteme); + string content = readText(deleteme); + assert(content == "abc"); +} + +@safe unittest +{ + import std.file; + + scope(exit) + { + assert(exists(deleteme)); + remove(deleteme); + } + + int[] a = [ 0, 1, 1, 2, 3, 5, 8 ]; + write(deleteme, a); // deleteme is the name of a temporary file + const bytes = read(deleteme); + const fileInts = () @trusted { return cast(int[]) bytes; }(); + assert(fileInts == a); +} + +@safe unittest +{ + import std.file; + + scope(exit) + { + assert(exists(deleteme)); + remove(deleteme); + } + + int[] a = [ 0, 1, 1, 2, 3, 5, 8 ]; + write(deleteme, a); // deleteme is the name of a temporary file + int[] b = [ 13, 21 ]; + append(deleteme, b); + const bytes = read(deleteme); + const fileInts = () @trusted { return cast(int[]) bytes; }(); + assert(fileInts == a ~ b); +} + +@safe unittest +{ + import std.file; + + auto t1 = deleteme, t2 = deleteme~"2"; + scope(exit) foreach (t; [t1, t2]) if (t.exists) t.remove(); + + t1.write("1"); + t1.rename(t2); + assert(t2.readText == "1"); + + t1.write("2"); + t1.rename(t2); + assert(t2.readText == "2"); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + deleteme.write("Hello"); + assert(deleteme.readText == "Hello"); + + deleteme.remove; + assertThrown!FileException(deleteme.readText); +} + +@safe unittest +{ + import std.file; + + scope(exit) deleteme.remove; + + // create a file of size 1 + write(deleteme, "a"); + assert(getSize(deleteme) == 1); + + // create a file of size 3 + write(deleteme, "abc"); + assert(getSize(deleteme) == 3); +} + +@safe unittest +{ + import std.file; + + import std.datetime : abs, SysTime; + + scope(exit) deleteme.remove; + write(deleteme, "a"); + + SysTime accessTime, modificationTime; + + getTimes(deleteme, accessTime, modificationTime); + + import std.datetime : Clock, seconds; + auto currTime = Clock.currTime(); + enum leeway = 5.seconds; + + auto diffAccess = accessTime - currTime; + auto diffModification = modificationTime - currTime; + assert(abs(diffAccess) <= leeway); + assert(abs(diffModification) <= leeway); +} + +@safe unittest +{ + import std.file; + + import std.datetime : DateTime, hnsecs, SysTime; + + scope(exit) deleteme.remove; + write(deleteme, "a"); + + SysTime accessTime = SysTime(DateTime(2010, 10, 4, 0, 0, 30)); + SysTime modificationTime = SysTime(DateTime(2018, 10, 4, 0, 0, 30)); + setTimes(deleteme, accessTime, modificationTime); + + SysTime accessTimeResolved, modificationTimeResolved; + getTimes(deleteme, accessTimeResolved, modificationTimeResolved); + + assert(accessTime == accessTimeResolved); + assert(modificationTime == modificationTimeResolved); +} + +@safe unittest +{ + import std.file; + + import std.datetime : abs, DateTime, hnsecs, SysTime; + scope(exit) deleteme.remove; + + import std.datetime : Clock, seconds; + auto currTime = Clock.currTime(); + enum leeway = 5.seconds; + deleteme.write("bb"); + assert(abs(deleteme.timeLastModified - currTime) <= leeway); +} + +@safe unittest +{ + import std.file; + + import std.datetime : SysTime; + + assert("file.does.not.exist".timeLastModified(SysTime.min) == SysTime.min); + + auto source = deleteme ~ "source"; + auto target = deleteme ~ "target"; + scope(exit) source.remove, target.remove; + + source.write("."); + assert(target.timeLastModified(SysTime.min) < source.timeLastModified); + target.write("."); + assert(target.timeLastModified(SysTime.min) >= source.timeLastModified); +} + +@safe unittest +{ + import std.file; + + auto f = deleteme ~ "does.not.exist"; + assert(!f.exists); + + f.write("hello"); + assert(f.exists); + + f.remove; + assert(!f.exists); +} + +@safe unittest +{ + import std.file; + + assert(".".exists); + assert(!"this file does not exist".exists); + deleteme.write("a\n"); + scope(exit) deleteme.remove; + assert(deleteme.exists); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto f = deleteme ~ "file"; + scope(exit) f.remove; + + assert(!f.exists); + assertThrown!FileException(f.getAttributes); + + f.write("."); + auto attributes = f.getAttributes; + assert(!attributes.attrIsDir); + assert(attributes.attrIsFile); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto dir = deleteme ~ "dir"; + scope(exit) dir.rmdir; + + assert(!dir.exists); + assertThrown!FileException(dir.getAttributes); + + dir.mkdir; + auto attributes = dir.getAttributes; + assert(attributes.attrIsDir); + assert(!attributes.attrIsFile); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto source = deleteme ~ "source"; + auto target = deleteme ~ "target"; + + assert(!source.exists); + assertThrown!FileException(source.getLinkAttributes); + + // symlinking isn't available on Windows + version (Posix) + { + scope(exit) source.remove, target.remove; + + target.write("target"); + target.symlink(source); + assert(source.readText == "target"); + assert(source.isSymlink); + assert(source.getLinkAttributes.attrIsSymlink); + } +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto f = deleteme ~ "file"; + scope(exit) f.remove; + + assert(!f.exists); + assertThrown!FileException(f.getLinkAttributes); + + f.write("."); + auto attributes = f.getLinkAttributes; + assert(!attributes.attrIsDir); + assert(attributes.attrIsFile); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto dir = deleteme ~ "dir"; + scope(exit) dir.rmdir; + + assert(!dir.exists); + assertThrown!FileException(dir.getLinkAttributes); + + dir.mkdir; + auto attributes = dir.getLinkAttributes; + assert(attributes.attrIsDir); + assert(!attributes.attrIsFile); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + import std.conv : octal; + + auto f = deleteme ~ "file"; + version (Posix) + { + scope(exit) f.remove; + + assert(!f.exists); + assertThrown!FileException(f.setAttributes(octal!777)); + + f.write("."); + auto attributes = f.getAttributes; + assert(!attributes.attrIsDir); + assert(attributes.attrIsFile); + + f.setAttributes(octal!777); + attributes = f.getAttributes; + + assert((attributes & 1023) == octal!777); + } +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + import std.conv : octal; + + auto dir = deleteme ~ "dir"; + version (Posix) + { + scope(exit) dir.rmdir; + + assert(!dir.exists); + assertThrown!FileException(dir.setAttributes(octal!777)); + + dir.mkdir; + auto attributes = dir.getAttributes; + assert(attributes.attrIsDir); + assert(!attributes.attrIsFile); + + dir.setAttributes(octal!777); + attributes = dir.getAttributes; + + assert((attributes & 1023) == octal!777); + } +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto dir = deleteme ~ "dir"; + auto f = deleteme ~ "f"; + scope(exit) dir.rmdir, f.remove; + + assert(!dir.exists); + assertThrown!FileException(dir.isDir); + + dir.mkdir; + assert(dir.isDir); + + f.write("."); + assert(!f.isDir); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto dir = deleteme ~ "dir"; + auto f = deleteme ~ "f"; + scope(exit) dir.rmdir, f.remove; + + assert(!dir.exists); + assertThrown!FileException(dir.getAttributes.attrIsDir); + + dir.mkdir; + assert(dir.isDir); + assert(dir.getAttributes.attrIsDir); + + f.write("."); + assert(!f.isDir); + assert(!f.getAttributes.attrIsDir); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto dir = deleteme ~ "dir"; + auto f = deleteme ~ "f"; + scope(exit) dir.rmdir, f.remove; + + dir.mkdir; + assert(!dir.isFile); + + assert(!f.exists); + assertThrown!FileException(f.isFile); + + f.write("."); + assert(f.isFile); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto dir = deleteme ~ "dir"; + auto f = deleteme ~ "f"; + scope(exit) dir.rmdir, f.remove; + + dir.mkdir; + assert(!dir.isFile); + assert(!dir.getAttributes.attrIsFile); + + assert(!f.exists); + assertThrown!FileException(f.getAttributes.attrIsFile); + + f.write("."); + assert(f.isFile); + assert(f.getAttributes.attrIsFile); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto source = deleteme ~ "source"; + auto target = deleteme ~ "target"; + + assert(!source.exists); + assertThrown!FileException(source.isSymlink); + + // symlinking isn't available on Windows + version (Posix) + { + scope(exit) source.remove, target.remove; + + target.write("target"); + target.symlink(source); + assert(source.readText == "target"); + assert(source.isSymlink); + assert(source.getLinkAttributes.attrIsSymlink); + } +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto source = deleteme ~ "source"; + auto target = deleteme ~ "target"; + + assert(!source.exists); + assertThrown!FileException(source.getLinkAttributes.attrIsSymlink); + + // symlinking isn't available on Windows + version (Posix) + { + scope(exit) source.remove, target.remove; + + target.write("target"); + target.symlink(source); + assert(source.readText == "target"); + assert(source.isSymlink); + assert(source.getLinkAttributes.attrIsSymlink); + } +} + +@system unittest +{ + import std.file; + + import std.algorithm.comparison : equal; + import std.algorithm.sorting : sort; + import std.array : array; + import std.path : buildPath; + + auto cwd = getcwd; + auto dir = deleteme ~ "dir"; + dir.mkdir; + scope(exit) cwd.chdir, dir.rmdirRecurse; + + dir.buildPath("a").write("."); + dir.chdir; // step into dir + "b".write("."); + assert(dirEntries(".", SpanMode.shallow).array.sort.equal( + [".".buildPath("a"), ".".buildPath("b")] + )); +} + +@safe unittest +{ + import std.file; + + import std.file : mkdir; + + auto dir = deleteme ~ "dir"; + scope(exit) dir.rmdir; + + dir.mkdir; + assert(dir.exists); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + assertThrown("a/b/c/d/e".mkdir); +} + +@safe unittest +{ + import std.file; + + import std.path : buildPath; + + auto dir = deleteme ~ "dir"; + scope(exit) dir.rmdirRecurse; + + dir.mkdir; + assert(dir.exists); + dir.mkdirRecurse; // does nothing + + // creates all parent directories as needed + auto nested = dir.buildPath("a", "b", "c"); + nested.mkdirRecurse; + assert(nested.exists); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + scope(exit) deleteme.remove; + deleteme.write("a"); + + // cannot make directory as it's already a file + assertThrown!FileException(deleteme.mkdirRecurse); +} + +@safe unittest +{ + import std.file; + + auto dir = deleteme ~ "dir"; + + dir.mkdir; + assert(dir.exists); + dir.rmdir; + assert(!dir.exists); +} + +@safe unittest +{ + import std.file; + + auto s = getcwd(); + assert(s.length); +} + +@safe unittest +{ + import std.file; + + import std.path : isAbsolute; + auto path = thisExePath(); + + assert(path.exists); + assert(path.isAbsolute); + assert(path.isFile); +} + +@safe unittest +{ + import std.file; + + auto source = deleteme ~ "source"; + auto target = deleteme ~ "target"; + auto targetNonExistent = deleteme ~ "target2"; + + scope(exit) source.remove, target.remove, targetNonExistent.remove; + + source.write("source"); + target.write("target"); + + assert(target.readText == "target"); + + source.copy(target); + assert(target.readText == "source"); + + source.copy(targetNonExistent); + assert(targetNonExistent.readText == "source"); +} + +@system unittest +{ + import std.file; + + import std.path : buildPath; + + auto dir = deleteme.buildPath("a", "b", "c"); + + dir.mkdirRecurse; + assert(dir.exists); + + deleteme.rmdirRecurse; + assert(!dir.exists); + assert(!deleteme.exists); +} + +@system unittest +{ + import std.file; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : map; + import std.algorithm.sorting : sort; + import std.array : array; + import std.path : buildPath, relativePath; + + auto root = deleteme ~ "root"; + scope(exit) root.rmdirRecurse; + root.mkdir; + + root.buildPath("animals").mkdir; + root.buildPath("animals", "cat").mkdir; + + alias removeRoot = (return scope e) => e.relativePath(root); + + assert(root.dirEntries(SpanMode.depth).map!removeRoot.equal( + [buildPath("animals", "cat"), "animals"])); + + assert(root.dirEntries(SpanMode.breadth).map!removeRoot.equal( + ["animals", buildPath("animals", "cat")])); + + root.buildPath("plants").mkdir; + + assert(root.dirEntries(SpanMode.shallow).array.sort.map!removeRoot.equal( + ["animals", "plants"])); +} + +@safe unittest +{ + import std.file; + + string[] listdir(string pathname) + { + import std.algorithm.iteration : map, filter; + import std.array : array; + import std.path : baseName; + + return dirEntries(pathname, SpanMode.shallow) + .filter!(a => a.isFile) + .map!((return a) => baseName(a.name)) + .array; + } + + // Can be safe only with -preview=dip1000 + @safe void main(string[] args) + { + import std.stdio : writefln; + + string[] files = listdir(args[1]); + writefln("%s", files); + } +} + +@system unittest +{ + import std.file; + + import std.typecons : tuple; + + scope(exit) + { + assert(exists(deleteme)); + remove(deleteme); + } + + write(deleteme, "12 12.25\n345 1.125"); // deleteme is the name of a temporary file + + // Load file; each line is an int followed by comma, whitespace and a + // double. + auto a = slurp!(int, double)(deleteme, "%s %s"); + assert(a.length == 2); + assert(a[0] == tuple(12, 12.25)); + assert(a[1] == tuple(345, 1.125)); +} + +@safe unittest +{ + import std.file; + + import std.ascii : letters; + import std.conv : to; + import std.path : buildPath; + import std.random : randomSample; + import std.utf : byCodeUnit; + + // random id with 20 letters + auto id = letters.byCodeUnit.randomSample(20).to!string; + auto myFile = tempDir.buildPath(id ~ "my_tmp_file"); + scope(exit) myFile.remove; + + myFile.write("hello"); + assert(myFile.readText == "hello"); +} + +@safe unittest +{ + import std.file; + + import std.exception : assertThrown; + + auto space = getAvailableDiskSpace("."); + assert(space > 0); + + assertThrown!FileException(getAvailableDiskSpace("ThisFileDoesNotExist123123")); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_format_package.d b/libphobos/testsuite/libphobos.phobos/std_format_package.d new file mode 100644 index 000000000000..2287ff2e3f93 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_format_package.d @@ -0,0 +1,139 @@ +@safe unittest +{ + import std.format; + + // Easiest way is to use `%s` everywhere: + assert(format("I got %s %s for %s euros.", 30, "eggs", 5.27) == "I got 30 eggs for 5.27 euros."); + + // Other format characters provide more control: + assert(format("I got %b %(%X%) for %f euros.", 30, "eggs", 5.27) == "I got 11110 65676773 for 5.270000 euros."); +} + +@safe unittest +{ + import std.format; + +/* +The trailing end of the sub-format string following the specifier for +each item is interpreted as the array delimiter, and is therefore +omitted following the last array item: + */ + assert(format("My items are %(%s %).", [1,2,3]) == "My items are 1 2 3."); + assert(format("My items are %(%s, %).", [1,2,3]) == "My items are 1, 2, 3."); + +/* +The "%|" delimiter specifier may be used to indicate where the +delimiter begins, so that the portion of the format string prior to +it will be retained in the last array element: + */ + assert(format("My items are %(-%s-%|, %).", [1,2,3]) == "My items are -1-, -2-, -3-."); + +/* +These compound format specifiers may be nested in the case of a +nested array argument: + */ + auto mat = [[1, 2, 3], + [4, 5, 6], + [7, 8, 9]]; + + assert(format("%(%(%d %) - %)", mat), "1 2 3 - 4 5 6 - 7 8 9"); + assert(format("[%(%(%d %) - %)]", mat), "[1 2 3 - 4 5 6 - 7 8 9]"); + assert(format("[%([%(%d %)]%| - %)]", mat), "[1 2 3] - [4 5 6] - [7 8 9]"); + +/* +Strings and characters are escaped automatically inside compound +format specifiers. To avoid this behavior, use "%-(" instead of "%(": + */ + assert(format("My friends are %s.", ["John", "Nancy"]) == `My friends are ["John", "Nancy"].`); + assert(format("My friends are %(%s, %).", ["John", "Nancy"]) == `My friends are "John", "Nancy".`); + assert(format("My friends are %-(%s, %).", ["John", "Nancy"]) == `My friends are John, Nancy.`); +} + +@safe unittest +{ + import std.format; + + // Flags can be used to influence to outcome: + assert(format("%g != %+#g", 3.14, 3.14) == "3.14 != +3.14000"); + + // Width and precision help to arrange the formatted result: + assert(format(">%10.2f<", 1234.56789) == "> 1234.57<"); + + // Numbers can be grouped: + assert(format("%,4d", int.max) == "21,4748,3647"); + + // It's possible to specify the position of an argument: + assert(format("%3$s %1$s", 3, 17, 5) == "5 3"); +} + +@safe unittest +{ + import std.format; + + // Width as argument + assert(format(">%*s<", 10, "abc") == "> abc<"); + + // Precision as argument + assert(format(">%.*f<", 5, 123.2) == ">123.20000<"); + + // Grouping as argument + assert(format("%,*d", 1, int.max) == "2,1,4,7,4,8,3,6,4,7"); + + // Grouping separator as argument + assert(format("%,3?d", '_', int.max) == "2_147_483_647"); + + // All at once + assert(format("%*.*,*?d", 20, 15, 6, '/', int.max) == " 000/002147/483647"); +} + +@safe unittest +{ + import std.format; + + import std.exception : assertThrown; + + assertThrown!FormatException(format("%d", "foo")); +} + +@safe pure unittest +{ + import std.format; + + assert(format("Here are %d %s.", 3, "apples") == "Here are 3 apples."); + + assert("Increase: %7.2f %%".format(17.4285) == "Increase: 17.43 %"); +} + +@safe pure unittest +{ + import std.format; + + auto s = format!"%s is %s"("Pi", 3.14); + assert(s == "Pi is 3.14"); + + // This line doesn't compile, because 3.14 cannot be formatted with %d: + // s = format!"%s is %d"("Pi", 3.14); +} + +@safe pure unittest +{ + import std.format; + + char[20] buf; + assert(sformat(buf[], "Here are %d %s.", 3, "apples") == "Here are 3 apples."); + + assert(buf[].sformat("Increase: %7.2f %%", 17.4285) == "Increase: 17.43 %"); +} + +@safe pure unittest +{ + import std.format; + + char[20] buf; + + assert(sformat!"Here are %d %s."(buf[], 3, "apples") == "Here are 3 apples."); + + // This line doesn't compile, because 3.14 cannot be formatted with %d: + // writeln(sformat!"Here are %d %s."(buf[], 3.14, "apples")); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_format_read.d b/libphobos/testsuite/libphobos.phobos/std_format_read.d new file mode 100644 index 000000000000..0beb307efb5d --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_format_read.d @@ -0,0 +1,275 @@ +@safe pure unittest +{ + import std.format.read; + + import std.format.spec : singleSpec; + + auto str = "false"; + auto spec = singleSpec("%s"); + assert(str.unformatValue!bool(spec) == false); + + str = "1"; + spec = singleSpec("%d"); + assert(str.unformatValue!bool(spec) == true); +} + +@safe pure unittest +{ + import std.format.read; + + import std.format.spec : singleSpec; + + auto str = "null"; + auto spec = singleSpec("%s"); + assert(str.unformatValue!(typeof(null))(spec) == null); +} + +@safe pure unittest +{ + import std.format.read; + + import std.format.spec : singleSpec; + + // signed decimal values + auto str = "123"; + auto spec = singleSpec("%s"); + assert(str.unformatValue!int(spec) == 123); + + // hexadecimal values + str = "ABC"; + spec = singleSpec("%X"); + assert(str.unformatValue!int(spec) == 2748); + + // octal values + str = "11610"; + spec = singleSpec("%o"); + assert(str.unformatValue!int(spec) == 5000); + + // raw read, depends on endianess + str = "\x75\x01"; + spec = singleSpec("%r"); + auto result = str.unformatValue!short(spec); + assert(result == 373 /* little endian */ || result == 29953 /* big endian */ ); +} + +@safe pure unittest +{ + import std.format.read; + + import std.format.spec : singleSpec; + import std.math.operations : isClose; + + // natural notation + auto str = "123.456"; + auto spec = singleSpec("%s"); + assert(str.unformatValue!double(spec).isClose(123.456)); + + // scientific notation + str = "1e17"; + spec = singleSpec("%e"); + assert(str.unformatValue!double(spec).isClose(1e17)); + + // raw read, depends on endianess + str = "\x40\x00\x00\xBF"; + spec = singleSpec("%r"); + auto result = str.unformatValue!float(spec); + assert(isClose(result, -0.5) /* little endian */ || isClose(result, 2.0) /* big endian */ ); +} + +@safe pure unittest +{ + import std.format.read; + + import std.format.spec : singleSpec; + + // only the first character is read + auto str = "abc"; + auto spec = singleSpec("%s"); + assert(str.unformatValue!char(spec) == 'a'); + + // using a numerical format character treats the read number as unicode code point + str = "65"; + spec = singleSpec("%d"); + assert(str.unformatValue!char(spec) == 'A'); + + str = "41"; + spec = singleSpec("%x"); + assert(str.unformatValue!char(spec) == 'A'); + + str = "10003"; + spec = singleSpec("%d"); + assert(str.unformatValue!dchar(spec) == '✓'); +} + +@safe pure unittest +{ + import std.format.read; + + import std.format.spec : singleSpec; + + // string value + string str = "aaa"; + auto spec = singleSpec("%s"); + assert(str.unformatValue!(dchar[])(spec) == "aaa"d); + + // fixed size array with characters + str = "aaa"; + spec = singleSpec("%s"); + dchar[3] ret = ['a', 'a', 'a']; + assert(str.unformatValue!(dchar[3])(spec) == ret); + + // dynamic array + str = "[1, 2, 3, 4]"; + spec = singleSpec("%s"); + assert(str.unformatValue!(int[])(spec) == [1, 2, 3, 4]); + + // fixed size array with integers + str = "[1, 2, 3, 4]"; + spec = singleSpec("%s"); + int[4] ret2 = [1, 2, 3, 4]; + assert(str.unformatValue!(int[4])(spec) == ret2); + + // compound specifiers can be used for more control + str = "1,2,3"; + spec = singleSpec("%(%s,%)"); + assert(str.unformatValue!(int[])(spec) == [1, 2, 3]); + + str = "cool"; + spec = singleSpec("%(%c%)"); + assert(str.unformatValue!(char[])(spec) == ['c', 'o', 'o', 'l']); +} + +@safe pure unittest +{ + import std.format.read; + + import std.format.spec : singleSpec; + + // as single value + auto str = `["one": 1, "two": 2]`; + auto spec = singleSpec("%s"); + assert(str.unformatValue!(int[string])(spec) == ["one": 1, "two": 2]); + + // with compound specifier for more control + str = "1/1, 2/4, 3/9"; + spec = singleSpec("%(%d/%d%|, %)"); + assert(str.unformatValue!(int[int])(spec) == [1: 1, 2: 4, 3: 9]); +} + +@safe pure unittest +{ + import std.format.read; + + string object; + char cmp; + int value; + + assert(formattedRead("angle < 36", "%s %c %d", object, cmp, value) == 3); + assert(object == "angle"); + assert(cmp == '<'); + assert(value == 36); + + // reading may end early: + assert(formattedRead("length >", "%s %c %d", object, cmp, value) == 2); + assert(object == "length"); + assert(cmp == '>'); + // value is not changed: + assert(value == 36); +} + +@safe pure unittest +{ + import std.format.read; + + string a; + int b; + double c; + + assert("hello!124:34.5".formattedRead!"%s!%s:%s"(a, b, c) == 3); + assert(a == "hello"); + assert(b == 124); + assert(c == 34.5); +} + +@safe pure unittest +{ + import std.format.read; + + string item; + double amount; + + assert("orange: (12%) 15.25".formattedRead("%s: (%*d%%) %f", item, amount) == 2); + assert(item == "orange"); + assert(amount == 15.25); + + // can also be used with tuples + import std.typecons : Tuple; + + Tuple!(int, float) t; + char[] line = "1 7643 2.125".dup; + formattedRead(line, "%s %*u %s", t); + assert(t[0] == 1 && t[1] == 2.125); +} + +@safe pure unittest +{ + import std.format.read; + + import std.exception : assertThrown; + import std.format : FormatException; + import std.typecons : tuple; + + auto complete = "hello!34.5:124".formattedRead!(string, double, int)("%s!%s:%s"); + assert(complete == tuple("hello", 34.5, 124)); + + // reading ends early + assertThrown!FormatException("hello!34.5:".formattedRead!(string, double, int)("%s!%s:%s")); +} + +@safe pure unittest +{ + import std.format.read; + + import std.format : FormatException; + import std.typecons : tuple; + + auto result = "orange: (12%) 15.25".formattedRead!(string, double)("%s: (%*d%%) %f"); + assert(result == tuple("orange", 15.25)); +} + +@safe pure unittest +{ + import std.format.read; + + import std.exception : assertThrown; + import std.format : FormatException; + import std.typecons : tuple; + + auto expected = tuple("hello", 124, 34.5); + auto result = "hello!124:34.5".formattedRead!("%s!%s:%s", string, int, double); + assert(result == expected); + + assertThrown!FormatException("hello!34.5:".formattedRead!("%s!%s:%s", string, double, int)); +} + +@safe pure unittest +{ + import std.format.read; + + import std.format : FormatException; + import std.typecons : tuple; + + static assert(!__traits(compiles, "orange: (12%) 15.25".formattedRead!("%s: (%*d%%) %f", string, double))); +} + +@safe pure unittest +{ + import std.format.read; + + import std.format.spec : singleSpec; + + string s = "42"; + auto spec = singleSpec("%s"); + assert(unformatValue!int(s, spec) == 42); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_format_spec.d b/libphobos/testsuite/libphobos.phobos/std_format_spec.d new file mode 100644 index 000000000000..a24c4779b8b5 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_format_spec.d @@ -0,0 +1,43 @@ +@safe pure unittest +{ + import std.format.spec; + + import std.array : appender; + + auto a = appender!(string)(); + auto fmt = "Number: %6.4e\nString: %s"; + auto f = FormatSpec!char(fmt); + + assert(f.writeUpToNextSpec(a)); + + assert(a.data == "Number: "); + assert(f.trailing == "\nString: %s"); + assert(f.spec == 'e'); + assert(f.width == 6); + assert(f.precision == 4); + + assert(f.writeUpToNextSpec(a)); + + assert(a.data == "Number: \nString: "); + assert(f.trailing == ""); + assert(f.spec == 's'); + + assert(!f.writeUpToNextSpec(a)); + + assert(a.data == "Number: \nString: "); +} + +@safe pure unittest +{ + import std.format.spec; + + import std.array : appender; + import std.format.write : formatValue; + + auto spec = singleSpec("%10.3e"); + auto writer = appender!string(); + writer.formatValue(42.0, spec); + + assert(writer.data == " 4.200e+01"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_format_write.d b/libphobos/testsuite/libphobos.phobos/std_format_write.d new file mode 100644 index 000000000000..aacd7fb0990c --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_format_write.d @@ -0,0 +1,421 @@ +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + auto w1 = appender!string(); + auto spec1 = singleSpec("%s"); + formatValue(w1, true, spec1); + + assert(w1.data == "true"); + + auto w2 = appender!string(); + auto spec2 = singleSpec("%#x"); + formatValue(w2, true, spec2); + + assert(w2.data == "0x1"); +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + auto w = appender!string(); + auto spec = singleSpec("%s"); + formatValue(w, null, spec); + + assert(w.data == "null"); +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + auto w1 = appender!string(); + auto spec1 = singleSpec("%d"); + formatValue(w1, -1337, spec1); + + assert(w1.data == "-1337"); + + auto w2 = appender!string(); + auto spec2 = singleSpec("%x"); + formatValue(w2, -1337, spec2); + + assert(w2.data == "fffffac7"); +} + +@safe unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + auto w1 = appender!string(); + auto spec1 = singleSpec("%.3f"); + formatValue(w1, 1337.7779, spec1); + + assert(w1.data == "1337.778"); + + auto w2 = appender!string(); + auto spec2 = singleSpec("%.3e"); + formatValue(w2, 1337.7779, spec2); + + assert(w2.data == "1.338e+03"); + + auto w3 = appender!string(); + auto spec3 = singleSpec("%.3g"); + formatValue(w3, 1337.7779, spec3); + + assert(w3.data == "1.34e+03"); + + auto w4 = appender!string(); + auto spec4 = singleSpec("%.3a"); + formatValue(w4, 1337.7779, spec4); + + assert(w4.data == "0x1.4e7p+10"); +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + auto w1 = appender!string(); + auto spec1 = singleSpec("%c"); + formatValue(w1, 'ì', spec1); + + assert(w1.data == "ì"); + + auto w2 = appender!string(); + auto spec2 = singleSpec("%#x"); + formatValue(w2, 'ì', spec2); + + assert(w2.data == "0xec"); +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + auto w1 = appender!string(); + auto spec1 = singleSpec("%s"); + formatValue(w1, "hello", spec1); + + assert(w1.data == "hello"); + + auto w2 = appender!string(); + auto spec2 = singleSpec("%(%#x%|/%)"); + formatValue(w2, "hello", spec2); + + assert(w2.data == "0x68/0x65/0x6c/0x6c/0x6f"); +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + auto w = appender!string(); + auto spec = singleSpec("%s"); + int[2] two = [1, 2]; + formatValue(w, two, spec); + + assert(w.data == "[1, 2]"); +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + auto w1 = appender!string(); + auto spec1 = singleSpec("%s"); + auto two = [1, 2]; + formatValue(w1, two, spec1); + + assert(w1.data == "[1, 2]"); + + auto w2 = appender!string(); + auto spec2 = singleSpec("%(%g%|, %)"); + auto consts = [3.1415926, 299792458, 6.67430e-11]; + formatValue(w2, consts, spec2); + + assert(w2.data == "3.14159, 2.99792e+08, 6.6743e-11"); + + // void[] is treated like ubyte[] + auto w3 = appender!string(); + auto spec3 = singleSpec("%s"); + void[] val = cast(void[]) cast(ubyte[])[1, 2, 3]; + formatValue(w3, val, spec3); + + assert(w3.data == "[1, 2, 3]"); +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + auto aa = [10:17.5, 20:9.99]; + + auto w1 = appender!string(); + auto spec1 = singleSpec("%s"); + formatValue(w1, aa, spec1); + + assert(w1.data == "[10:17.5, 20:9.99]" || w1.data == "[20:9.99, 10:17.5]"); + + auto w2 = appender!string(); + auto spec2 = singleSpec("%(%x = %.0e%| # %)"); + formatValue(w2, aa, spec2); + + assert(w2.data == "a = 2e+01 # 14 = 1e+01" || w2.data == "14 = 1e+01 # a = 2e+01"); +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + enum A { first, second, third } + + auto w1 = appender!string(); + auto spec1 = singleSpec("%s"); + formatValue(w1, A.second, spec1); + + assert(w1.data == "second"); + + auto w2 = appender!string(); + auto spec2 = singleSpec("%d"); + formatValue(w2, A.second, spec2); + + assert(w2.data == "1"); + + // values of an enum that have no name are formatted with %s using a cast + A a = A.third; + a++; + + auto w3 = appender!string(); + auto spec3 = singleSpec("%s"); + formatValue(w3, a, spec3); + + assert(w3.data == "cast(A)3"); +} + +@safe unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : FormatSpec, singleSpec; + + // Using a `toString` with a writer + static struct Point1 + { + import std.range.primitives : isOutputRange, put; + + int x, y; + + void toString(W)(ref W writer, scope const ref FormatSpec!char f) + if (isOutputRange!(W, char)) + { + put(writer, "("); + formatValue(writer, x, f); + put(writer, ","); + formatValue(writer, y, f); + put(writer, ")"); + } + } + + auto w1 = appender!string(); + auto spec1 = singleSpec("%s"); + auto p1 = Point1(16, 11); + + formatValue(w1, p1, spec1); + assert(w1.data == "(16,11)"); + + // Using a `toString` with a sink + static struct Point2 + { + int x, y; + + void toString(scope void delegate(scope const(char)[]) @safe sink, + scope const FormatSpec!char fmt) const + { + sink("("); + sink.formatValue(x, fmt); + sink(","); + sink.formatValue(y, fmt); + sink(")"); + } + } + + auto w2 = appender!string(); + auto spec2 = singleSpec("%03d"); + auto p2 = Point2(16,11); + + formatValue(w2, p2, spec2); + assert(w2.data == "(016,011)"); + + // Using `string toString()` + static struct Point3 + { + int x, y; + + string toString() + { + import std.conv : to; + + return "(" ~ to!string(x) ~ "," ~ to!string(y) ~ ")"; + } + } + + auto w3 = appender!string(); + auto spec3 = singleSpec("%s"); // has to be %s + auto p3 = Point3(16,11); + + formatValue(w3, p3, spec3); + assert(w3.data == "(16,11)"); + + // without `toString` + static struct Point4 + { + int x, y; + } + + auto w4 = appender!string(); + auto spec4 = singleSpec("%s"); // has to be %s + auto p4 = Point4(16,11); + + formatValue(w4, p4, spec3); + assert(w4.data == "Point4(16, 11)"); +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + auto w1 = appender!string(); + auto spec1 = singleSpec("%s"); + auto p1 = () @trusted { return cast(void*) 0xFFEECCAA; } (); + formatValue(w1, p1, spec1); + + assert(w1.data == "FFEECCAA"); + + // null pointers are printed as `"null"` when used with `%s` and as hexadecimal integer else + auto w2 = appender!string(); + auto spec2 = singleSpec("%s"); + auto p2 = () @trusted { return cast(void*) 0x00000000; } (); + formatValue(w2, p2, spec2); + + assert(w2.data == "null"); + + auto w3 = appender!string(); + auto spec3 = singleSpec("%x"); + formatValue(w3, p2, spec3); + + assert(w3.data == "0"); +} + +@safe unittest +{ + import std.format.write; + + import core.simd; // cannot be selective, because float4 might not be defined + import std.array : appender; + import std.format.spec : singleSpec; + + auto w = appender!string(); + auto spec = singleSpec("%s"); + + static if (is(float4)) + { + version (X86) {} + else + { + float4 f4; + f4.array[0] = 1; + f4.array[1] = 2; + f4.array[2] = 3; + f4.array[3] = 4; + + formatValue(w, f4, spec); + assert(w.data == "[1, 2, 3, 4]"); + } + } +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + + auto writer1 = appender!string(); + formattedWrite(writer1, "%s is the ultimate %s.", 42, "answer"); + assert(writer1[] == "42 is the ultimate answer."); + + auto writer2 = appender!string(); + formattedWrite(writer2, "Increase: %7.2f %%", 17.4285); + assert(writer2[] == "Increase: 17.43 %"); +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + + auto writer = appender!string(); + writer.formattedWrite!"%d is the ultimate %s."(42, "answer"); + assert(writer[] == "42 is the ultimate answer."); + + // This line doesn't compile, because 3.14 cannot be formatted with %d: + // writer.formattedWrite!"%d is the ultimate %s."(3.14, "answer"); +} + +@safe pure unittest +{ + import std.format.write; + + import std.array : appender; + import std.format.spec : singleSpec; + + auto writer = appender!string(); + auto spec = singleSpec("%08b"); + writer.formatValue(42, spec); + assert(writer.data == "00101010"); + + spec = singleSpec("%2s"); + writer.formatValue('=', spec); + assert(writer.data == "00101010 ="); + + spec = singleSpec("%+14.6e"); + writer.formatValue(42.0, spec); + assert(writer.data == "00101010 = +4.200000e+01"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_functional.d b/libphobos/testsuite/libphobos.phobos/std_functional.d new file mode 100644 index 000000000000..3bfab45658eb --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_functional.d @@ -0,0 +1,360 @@ +@safe unittest +{ + import std.functional; + + // Strings are compiled into functions: + alias isEven = unaryFun!("(a & 1) == 0"); + assert(isEven(2) && !isEven(1)); +} + +@safe unittest +{ + import std.functional; + + alias less = binaryFun!("a < b"); + assert(less(1, 2) && !less(2, 1)); + alias greater = binaryFun!("a > b"); + assert(!greater("1", "2") && greater("2", "1")); +} + +pure @safe @nogc nothrow unittest +{ + import std.functional; + + assert(lessThan(2, 3)); + assert(lessThan(2U, 3U)); + assert(lessThan(2, 3.0)); + assert(lessThan(-2, 3U)); + assert(lessThan(2, 3U)); + assert(!lessThan(3U, -2)); + assert(!lessThan(3U, 2)); + assert(!lessThan(0, 0)); + assert(!lessThan(0U, 0)); + assert(!lessThan(0, 0U)); +} + +@safe unittest +{ + import std.functional; + + assert(!greaterThan(2, 3)); + assert(!greaterThan(2U, 3U)); + assert(!greaterThan(2, 3.0)); + assert(!greaterThan(-2, 3U)); + assert(!greaterThan(2, 3U)); + assert(greaterThan(3U, -2)); + assert(greaterThan(3U, 2)); + assert(!greaterThan(0, 0)); + assert(!greaterThan(0U, 0)); + assert(!greaterThan(0, 0U)); +} + +@safe unittest +{ + import std.functional; + + assert(equalTo(0U, 0)); + assert(equalTo(0, 0U)); + assert(!equalTo(-1, ~0U)); +} + +@safe unittest +{ + import std.functional; + + alias gt = reverseArgs!(binaryFun!("a < b")); + assert(gt(2, 1) && !gt(1, 1)); +} + +@safe unittest +{ + import std.functional; + + int x = 42; + bool xyz(int a, int b) { return a * x < b / x; } + auto foo = &xyz; + foo(4, 5); + alias zyx = reverseArgs!(foo); + assert(zyx(5, 4) == foo(4, 5)); +} + +@safe unittest +{ + import std.functional; + + alias gt = reverseArgs!(binaryFun!("a < b")); + assert(gt(2, 1) && !gt(1, 1)); + int x = 42; + bool xyz(int a, int b) { return a * x < b / x; } + auto foo = &xyz; + foo(4, 5); + alias zyx = reverseArgs!(foo); + assert(zyx(5, 4) == foo(4, 5)); +} + +@safe unittest +{ + import std.functional; + + int abc(int a, int b, int c) { return a * b + c; } + alias cba = reverseArgs!abc; + assert(abc(91, 17, 32) == cba(32, 17, 91)); +} + +@safe unittest +{ + import std.functional; + + int a(int a) { return a * 2; } + alias _a = reverseArgs!a; + assert(a(2) == _a(2)); +} + +@safe unittest +{ + import std.functional; + + int b() { return 4; } + alias _b = reverseArgs!b; + assert(b() == _b()); +} + +@safe unittest +{ + import std.functional; + + import std.algorithm.searching : find; + import std.uni : isWhite; + string a = " Hello, world!"; + assert(find!(not!isWhite)(a) == "Hello, world!"); +} + +@safe unittest +{ + import std.functional; + + int fun(int a, int b) { return a + b; } + alias fun5 = partial!(fun, 5); + assert(fun5(6) == 11); + // Note that in most cases you'd use an alias instead of a value + // assignment. Using an alias allows you to partially evaluate template + // functions without committing to a particular type of the function. +} + +@safe unittest +{ + import std.functional; + + // Overloads are resolved when the partially applied function is called + // with the remaining arguments. + struct S + { + static char fun(int i, string s) { return s[i]; } + static int fun(int a, int b) { return a * b; } + } + alias fun3 = partial!(S.fun, 3); + assert(fun3("hello") == 'l'); + assert(fun3(10) == 30); +} + +pure @safe @nogc nothrow unittest +{ + import std.functional; + + int f(int x, int y, int z) + { + return x + y + z; + } + auto cf = curry!f; + auto cf1 = cf(1); + auto cf2 = cf(2); + + assert(cf1(2)(3) == f(1, 2, 3)); + assert(cf2(2)(3) == f(2, 2, 3)); +} + +pure @safe @nogc nothrow unittest +{ + import std.functional; + + //works with callable structs too + struct S + { + int w; + int opCall(int x, int y, int z) + { + return w + x + y + z; + } + } + + S s; + s.w = 5; + + auto cs = curry(s); + auto cs1 = cs(1); + auto cs2 = cs(2); + + assert(cs1(2)(3) == s(1, 2, 3)); + assert(cs1(2)(3) == (1 + 2 + 3 + 5)); + assert(cs2(2)(3) ==s(2, 2, 3)); +} + +@safe unittest +{ + import std.functional; + + import std.typecons : Tuple; + static bool f1(int a) { return a != 0; } + static int f2(int a) { return a / 2; } + auto x = adjoin!(f1, f2)(5); + assert(is(typeof(x) == Tuple!(bool, int))); + assert(x[0] == true && x[1] == 2); +} + +@safe unittest +{ + import std.functional; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : map; + import std.array : split; + import std.conv : to; + + // First split a string in whitespace-separated tokens and then + // convert each token into an integer + assert(compose!(map!(to!(int)), split)("1 2 3").equal([1, 2, 3])); +} + +@safe unittest +{ + import std.functional; + + import std.conv : to; + string foo(int a) { return to!(string)(a); } + int bar(string a) { return to!(int)(a) + 1; } + double baz(int a) { return a + 0.5; } + assert(compose!(baz, bar, foo)(1) == 2.5); + assert(pipe!(foo, bar, baz)(1) == 2.5); + + assert(compose!(baz, `to!(int)(a) + 1`, foo)(1) == 2.5); + assert(compose!(baz, bar)("1"[]) == 2.5); + + assert(compose!(baz, bar)("1") == 2.5); + + assert(compose!(`a + 0.5`, `to!(int)(a) + 1`, foo)(1) == 2.5); +} + +@safe nothrow unittest +{ + import std.functional; + + ulong fib(ulong n) @safe nothrow + { + return n < 2 ? n : memoize!fib(n - 2) + memoize!fib(n - 1); + } + assert(fib(10) == 55); +} + +@safe unittest +{ + import std.functional; + + ulong fact(ulong n) @safe + { + return n < 2 ? 1 : n * memoize!fact(n - 1); + } + assert(fact(10) == 3628800); +} + +@safe unittest +{ + import std.functional; + + ulong factImpl(ulong n) @safe + { + return n < 2 ? 1 : n * factImpl(n - 1); + } + alias fact = memoize!factImpl; + assert(fact(10) == 3628800); +} + +@system unittest +{ + import std.functional; + + ulong fact(ulong n) + { + // Memoize no more than 8 values + return n < 2 ? 1 : n * memoize!(fact, 8)(n - 1); + } + assert(fact(8) == 40320); + // using more entries than maxSize will overwrite existing entries + assert(fact(10) == 3628800); +} + +@safe unittest +{ + import std.functional; + + static int inc(ref uint num) { + num++; + return 8675309; + } + + uint myNum = 0; + auto incMyNumDel = toDelegate(&inc); + auto returnVal = incMyNumDel(myNum); + assert(myNum == 1); +} + +@safe unittest +{ + import std.functional; + + import std.typecons : tuple; + + auto name = tuple("John", "Doe"); + string full = name.bind!((first, last) => first ~ " " ~ last); + assert(full == "John Doe"); +} + +@safe unittest +{ + import std.functional; + + import std.algorithm.comparison : min, max; + + struct Pair + { + int a; + int b; + } + + auto p = Pair(123, 456); + assert(p.bind!min == 123); // min(p.a, p.b) + assert(p.bind!max == 456); // max(p.a, p.b) +} + +@safe unittest +{ + import std.functional; + + import std.algorithm.iteration : map, filter; + import std.algorithm.comparison : equal; + import std.typecons : tuple; + + auto ages = [ + tuple("Alice", 35), + tuple("Bob", 64), + tuple("Carol", 21), + tuple("David", 39), + tuple("Eve", 50) + ]; + + auto overForty = ages + .filter!(bind!((name, age) => age > 40)) + .map!(bind!((name, age) => name)); + + assert(overForty.equal(["Bob", "Eve"])); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_getopt.d b/libphobos/testsuite/libphobos.phobos/std_getopt.d new file mode 100644 index 000000000000..12d81f387809 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_getopt.d @@ -0,0 +1,18 @@ +@safe unittest +{ + import std.getopt; + + auto args = ["prog", "--foo", "-b"]; + + bool foo; + bool bar; + auto rslt = getopt(args, "foo|f", "Some information about foo.", &foo, "bar|b", + "Some help message about bar.", &bar); + + if (rslt.helpWanted) + { + defaultGetoptPrinter("Some information about the program.", + rslt.options); + } +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_int128.d b/libphobos/testsuite/libphobos.phobos/std_int128.d new file mode 100644 index 000000000000..71548fd124a7 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_int128.d @@ -0,0 +1,128 @@ +@safe unittest +{ + import std.int128; + + const Int128 a = Int128(0xffff_ffff_ffff_ffffL, 0x0123_4567_89ab_cdefL); + assert(cast(long) a == 0x0123_4567_89ab_cdefL); + assert(cast(int) a == 0x89ab_cdef); + assert(cast(byte) a == cast(byte) 0xef); + +} + +@safe unittest +{ + import std.int128; + + const Int128 a = Int128(-1L << 60); + assert(cast(double) a == -(2.0 ^^ 60)); + assert(cast(double) (a * a) == 2.0 ^^ 120); + +} + +@safe unittest +{ + import std.int128; + + import std.format : format; + + assert(format("%s", Int128.max) == "170141183460469231731687303715884105727"); + assert(format("%s", Int128.min) == "-170141183460469231731687303715884105728"); + assert(format("%x", Int128.max) == "7fffffffffffffffffffffffffffffff"); + assert(format("%X", Int128.max) == "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + assert(format("%032X", Int128(123L)) == "0000000000000000000000000000007B"); + assert(format("%+ 40d", Int128(123L)) == " +123"); + assert(format("%+-40d", Int128(123L)) == "+123 "); + +} + +@safe unittest +{ + import std.int128; + + import std.conv : to; + + assert(to!wstring(Int128.max) == "170141183460469231731687303715884105727"w); + assert(to!dstring(Int128.max) == "170141183460469231731687303715884105727"d); + +} + +@safe pure nothrow @nogc unittest +{ + import std.int128; + + Int128 c = Int128(5, 6); + assert(c == c); + assert(c == +c); + assert(c == - -c); + assert(~c == Int128(~5, ~6)); + ++c; + assert(c == Int128(5, 7)); + assert(--c == Int128(5, 6)); + assert(!!c); + assert(!Int128()); + + assert(c + Int128(10, 20) == Int128(15, 26)); + assert(c - Int128(1, 2) == Int128(4, 4)); + assert(c * Int128(100, 2) == Int128(610, 12)); + assert(c / Int128(3, 2) == Int128(0, 1)); + assert(c % Int128(3, 2) == Int128(2, 4)); + assert((c & Int128(3, 2)) == Int128(1, 2)); + assert((c | Int128(3, 2)) == Int128(7, 6)); + assert((c ^ Int128(3, 2)) == Int128(6, 4)); + + assert(c + 15 == Int128(5, 21)); + assert(c - 15 == Int128(4, -9)); + assert(c * 15 == Int128(75, 90)); + assert(c / 15 == Int128(0, 6148914691236517205)); + assert(c % 15 == Int128(0, 11)); + assert((c & 15) == Int128(0, 6)); + assert((c | 15) == Int128(5, 15)); + assert((c ^ 15) == Int128(5, 9)); + + assert(15 + c == Int128(5, 21)); + assert(15 - c == Int128(-5, 9)); + assert(15 * c == Int128(75, 90)); + assert(15 / c == Int128(0, 0)); + assert(15 % c == Int128(0, 15)); + assert((15 & c) == Int128(0, 6)); + assert((15 | c) == Int128(5, 15)); + assert((15 ^ c) == Int128(5, 9)); + + assert(c << 1 == Int128(10, 12)); + assert(-c >> 1 == Int128(-3, 9223372036854775805)); + assert(-c >>> 1 == Int128(9223372036854775805, 9223372036854775805)); + + assert((c += 1) == Int128(5, 7)); + assert((c -= 1) == Int128(5, 6)); + assert((c += Int128(0, 1)) == Int128(5, 7)); + assert((c -= Int128(0, 1)) == Int128(5, 6)); + assert((c *= 2) == Int128(10, 12)); + assert((c /= 2) == Int128(5, 6)); + assert((c %= 2) == Int128()); + c += Int128(5, 6); + assert((c *= Int128(10, 20)) == Int128(160, 120)); + assert((c /= Int128(10, 20)) == Int128(0, 15)); + c += Int128(72, 0); + assert((c %= Int128(10, 20)) == Int128(1, -125)); + assert((c &= Int128(3, 20)) == Int128(1, 0)); + assert((c |= Int128(8, 2)) == Int128(9, 2)); + assert((c ^= Int128(8, 2)) == Int128(1, 0)); + c |= Int128(10, 5); + assert((c <<= 1) == Int128(11 * 2, 5 * 2)); + assert((c >>>= 1) == Int128(11, 5)); + c = Int128(long.min, long.min); + assert((c >>= 1) == Int128(long.min >> 1, cast(ulong) long.min >> 1)); + + assert(-Int128.min == Int128.min); + assert(Int128.max + 1 == Int128.min); + + c = Int128(5, 6); + assert(c < Int128(6, 5)); + assert(c > 10); + + c = Int128(-1UL); + assert(c == -1UL); + c = Int128(-1L); + assert(c == -1L); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_internal_cstring.d b/libphobos/testsuite/libphobos.phobos/std_internal_cstring.d new file mode 100644 index 000000000000..8cb8d6187d18 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_internal_cstring.d @@ -0,0 +1,47 @@ +@safe unittest +{ + import std.internal.cstring; + + version (Posix) + { + import core.stdc.stdlib : free; + import core.sys.posix.stdlib : setenv; + import std.exception : enforce; + + void setEnvironment(scope const(char)[] name, scope const(char)[] value) + { enforce(setenv(name.tempCString(), value.tempCString(), 1) != -1); } + } + + version (Windows) + { + import core.sys.windows.winbase : SetEnvironmentVariableW; + import std.exception : enforce; + + void setEnvironment(scope const(char)[] name, scope const(char)[] value) + { enforce(SetEnvironmentVariableW(name.tempCStringW(), value.tempCStringW())); } + } +} + +nothrow @nogc @system unittest +{ + import std.internal.cstring; + + import core.stdc.string; + + string str = "abc"; + + // Intended usage + assert(strlen(str.tempCString()) == 3); + + // Correct usage + auto tmp = str.tempCString(); + assert(strlen(tmp) == 3); // or `tmp.ptr`, or `tmp.buffPtr` + + // $(RED WARNING): $(RED Incorrect usage) + auto pInvalid1 = str.tempCString().ptr; + const char* pInvalid2 = str.tempCString(); + // Both pointers refer to invalid memory here as + // returned values aren't assigned to a variable and + // both primary expressions are ended. +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_internal_scopebuffer.d b/libphobos/testsuite/libphobos.phobos/std_internal_scopebuffer.d new file mode 100644 index 000000000000..adecde1f5029 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_internal_scopebuffer.d @@ -0,0 +1,9 @@ +@system unittest +{ + import std.internal.scopebuffer; + + ubyte[10] tmpbuf = void; + auto sb = scopeBuffer(tmpbuf); + scope(exit) sb.free(); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_json.d b/libphobos/testsuite/libphobos.phobos/std_json.d new file mode 100644 index 000000000000..5d686fb18d4e --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_json.d @@ -0,0 +1,252 @@ +@system unittest +{ + import std.json; + + import std.conv : to; + + // parse a file or string of json into a usable structure + string s = `{ "language": "D", "rating": 3.5, "code": "42" }`; + JSONValue j = parseJSON(s); + // j and j["language"] return JSONValue, + // j["language"].str returns a string + assert(j["language"].str == "D"); + assert(j["rating"].floating == 3.5); + + // check a type + long x; + if (const(JSONValue)* code = "code" in j) + { + if (code.type() == JSONType.integer) + x = code.integer; + else + x = to!int(code.str); + } + + // create a json struct + JSONValue jj = [ "language": "D" ]; + // rating doesnt exist yet, so use .object to assign + jj.object["rating"] = JSONValue(3.5); + // create an array to assign to list + jj.object["list"] = JSONValue( ["a", "b", "c"] ); + // list already exists, so .object optional + jj["list"].array ~= JSONValue("D"); + + string jjStr = `{"language":"D","list":["a","b","c","D"],"rating":3.5}`; + assert(jj.toString == jjStr); +} + +@safe unittest +{ + import std.json; + + string s = "{ \"language\": \"D\" }"; + JSONValue j = parseJSON(s); + assert(j.type == JSONType.object); + assert(j["language"].type == JSONType.string); + +} + +@safe unittest +{ + import std.json; + + JSONValue j = [ "language": "D" ]; + + // get value + assert(j["language"].str == "D"); + + // change existing key to new string + j["language"].str = "Perl"; + assert(j["language"].str == "Perl"); + +} + +@safe unittest +{ + import std.json; + + JSONValue j = true; + assert(j.boolean == true); + + j.boolean = false; + assert(j.boolean == false); + + j.integer = 12; + import std.exception : assertThrown; + assertThrown!JSONException(j.boolean); + +} + +@safe unittest +{ + import std.json; + + import std.exception; + import std.conv; + string s = + `{ + "a": 123, + "b": 3.1415, + "c": "text", + "d": true, + "e": [1, 2, 3], + "f": { "a": 1 }, + "g": -45, + "h": ` ~ ulong.max.to!string ~ `, + }`; + + struct a { } + + immutable json = parseJSON(s); + assert(json["a"].get!double == 123.0); + assert(json["a"].get!int == 123); + assert(json["a"].get!uint == 123); + assert(json["b"].get!double == 3.1415); + assertThrown!JSONException(json["b"].get!int); + assert(json["c"].get!string == "text"); + assert(json["d"].get!bool == true); + assertNotThrown(json["e"].get!(JSONValue[])); + assertNotThrown(json["f"].get!(JSONValue[string])); + static assert(!__traits(compiles, json["a"].get!a)); + assertThrown!JSONException(json["e"].get!float); + assertThrown!JSONException(json["d"].get!(JSONValue[string])); + assertThrown!JSONException(json["f"].get!(JSONValue[])); + assert(json["g"].get!int == -45); + assertThrown!ConvException(json["g"].get!uint); + assert(json["h"].get!ulong == ulong.max); + assertThrown!ConvException(json["h"].get!uint); + assertNotThrown(json["h"].get!float); + +} + +@safe unittest +{ + import std.json; + + JSONValue j = JSONValue( "a string" ); + j = JSONValue(42); + + j = JSONValue( [1, 2, 3] ); + assert(j.type == JSONType.array); + + j = JSONValue( ["language": "D"] ); + assert(j.type == JSONType.object); + +} + +@system unittest +{ + import std.json; + + JSONValue obj1 = JSONValue.emptyObject; + assert(obj1.type == JSONType.object); + obj1.object["a"] = JSONValue(1); + assert(obj1.object["a"] == JSONValue(1)); + + JSONValue obj2 = JSONValue.emptyObject; + assert("a" !in obj2.object); + obj2.object["b"] = JSONValue(5); + assert(obj1 != obj2); + +} + +@system unittest +{ + import std.json; + + JSONValue obj = JSONValue.emptyOrderedObject; + assert(obj.type == JSONType.object); + assert(obj.isOrdered); + obj["b"] = JSONValue(2); + obj["a"] = JSONValue(1); + assert(obj["a"] == JSONValue(1)); + assert(obj["b"] == JSONValue(2)); + + string[] keys; + foreach (string k, JSONValue v; obj) + keys ~= k; + assert(keys == ["b", "a"]); + +} + +@system unittest +{ + import std.json; + + JSONValue arr1 = JSONValue.emptyArray; + assert(arr1.type == JSONType.array); + assert(arr1.array.length == 0); + arr1.array ~= JSONValue("Hello"); + assert(arr1.array.length == 1); + assert(arr1.array[0] == JSONValue("Hello")); + + JSONValue arr2 = JSONValue.emptyArray; + assert(arr2.array.length == 0); + assert(arr1 != arr2); + +} + +@safe unittest +{ + import std.json; + + JSONValue j = JSONValue( [42, 43, 44] ); + assert( j[0].integer == 42 ); + assert( j[1].integer == 43 ); + +} + +@safe unittest +{ + import std.json; + + JSONValue j = JSONValue( ["language": "D"] ); + assert( j["language"].str == "D" ); + +} + +@safe unittest +{ + import std.json; + + JSONValue j = JSONValue( ["language": "D"] ); + j["language"].str = "Perl"; + assert( j["language"].str == "Perl" ); + +} + +@safe unittest +{ + import std.json; + + JSONValue j = JSONValue( ["Perl", "C"] ); + j[1].str = "D"; + assert( j[1].str == "D" ); + +} + +@safe unittest +{ + import std.json; + + JSONValue j = [ "language": "D", "author": "walter" ]; + string a = ("author" in j).str; + *("author" in j) = "Walter"; + assert(j["author"].str == "Walter"); + +} + +@safe unittest +{ + import std.json; + + assert(JSONValue(10).opEquals(JSONValue(10.0))); + assert(JSONValue(10) != (JSONValue(10.5))); + + assert(JSONValue(1) != JSONValue(true)); + assert(JSONValue.emptyArray != JSONValue.emptyObject); + + assert(parseJSON(`{"a": 1, "b": 2}`).opEquals(parseJSON(`{"b": 2, "a": 1}`))); + +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_logger_core.d b/libphobos/testsuite/libphobos.phobos/std_logger_core.d new file mode 100644 index 000000000000..f8206db199ae --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_logger_core.d @@ -0,0 +1,22 @@ +@safe unittest +{ + import std.logger.core; + + auto nl1 = new StdForwardLogger(LogLevel.all); +} + +@system unittest +{ + import std.logger.core; + + import std.logger.filelogger : FileLogger; + import std.file : deleteme, remove; + Logger l = stdThreadLocalLog; + stdThreadLocalLog = new FileLogger(deleteme ~ "-someFile.log"); + scope(exit) remove(deleteme ~ "-someFile.log"); + + auto tempLog = stdThreadLocalLog; + stdThreadLocalLog = l; + destroy(tempLog); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_logger_nulllogger.d b/libphobos/testsuite/libphobos.phobos/std_logger_nulllogger.d new file mode 100644 index 000000000000..6c4444312f90 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_logger_nulllogger.d @@ -0,0 +1,10 @@ +@safe unittest +{ + import std.logger.nulllogger; + + import std.logger.core : LogLevel; + auto nl1 = new NullLogger(LogLevel.all); + nl1.info("You will never read this."); + nl1.fatal("You will never read this, either and it will not throw"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_math_algebraic.d b/libphobos/testsuite/libphobos.phobos/std_math_algebraic.d new file mode 100644 index 000000000000..7b20a13ca26e --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_math_algebraic.d @@ -0,0 +1,163 @@ +@safe pure nothrow @nogc unittest +{ + import std.math.algebraic; + + import std.math.traits : isIdentical, isNaN; + + assert(isIdentical(abs(-0.0L), 0.0L)); + assert(isNaN(abs(real.nan))); + assert(abs(-real.infinity) == real.infinity); + assert(abs(-56) == 56); + assert(abs(2321312L) == 2321312L); + assert(abs(23u) == 23u); +} + +@safe unittest +{ + import std.math.algebraic; + + import std.math.traits : isIdentical; + + assert(isIdentical(fabs(0.0f), 0.0f)); + assert(isIdentical(fabs(-0.0f), 0.0f)); + assert(fabs(-10.0f) == 10.0f); + + assert(isIdentical(fabs(0.0), 0.0)); + assert(isIdentical(fabs(-0.0), 0.0)); + assert(fabs(-10.0) == 10.0); + + assert(isIdentical(fabs(0.0L), 0.0L)); + assert(isIdentical(fabs(-0.0L), 0.0L)); + assert(fabs(-10.0L) == 10.0L); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.algebraic; + + import std.math.operations : feqrel; + import std.math.traits : isNaN; + + assert(sqrt(2.0).feqrel(1.4142) > 16); + assert(sqrt(9.0).feqrel(3.0) > 16); + + assert(isNaN(sqrt(-1.0f))); + assert(isNaN(sqrt(-1.0))); + assert(isNaN(sqrt(-1.0L))); +} + +@safe unittest +{ + import std.math.algebraic; + + import std.math.operations : feqrel; + + assert(cbrt(1.0).feqrel(1.0) > 16); + assert(cbrt(27.0).feqrel(3.0) > 16); + assert(cbrt(15.625).feqrel(2.5) > 16); +} + +@safe unittest +{ + import std.math.algebraic; + + import std.math.operations : feqrel; + + assert(hypot(1.0, 1.0).feqrel(1.4142) > 16); + assert(hypot(3.0, 4.0).feqrel(5.0) > 16); + assert(hypot(real.infinity, 1.0L) == real.infinity); + assert(hypot(real.infinity, real.nan) == real.infinity); +} + +@safe unittest +{ + import std.math.algebraic; + + import std.math.operations : isClose; + + assert(isClose(hypot(1.0, 2.0, 2.0), 3.0)); + assert(isClose(hypot(2.0, 3.0, 6.0), 7.0)); + assert(isClose(hypot(1.0, 4.0, 8.0), 9.0)); +} + +@safe nothrow @nogc unittest +{ + import std.math.algebraic; + + real x = 3.1L; + static real[] pp = [56.1L, 32.7L, 6]; + + assert(poly(x, pp) == (56.1L + (32.7L + 6.0L * x) * x)); +} + +@safe @nogc pure nothrow unittest +{ + import std.math.algebraic; + + assert(nextPow2(2) == 4); + assert(nextPow2(10) == 16); + assert(nextPow2(4000) == 4096); + + assert(nextPow2(-2) == -4); + assert(nextPow2(-10) == -16); + + assert(nextPow2(uint.max) == 0); + assert(nextPow2(uint.min) == 0); + assert(nextPow2(size_t.max) == 0); + assert(nextPow2(size_t.min) == 0); + + assert(nextPow2(int.max) == 0); + assert(nextPow2(int.min) == 0); + assert(nextPow2(long.max) == 0); + assert(nextPow2(long.min) == 0); +} + +@safe @nogc pure nothrow unittest +{ + import std.math.algebraic; + + assert(nextPow2(2.1) == 4.0); + assert(nextPow2(-2.0) == -4.0); + assert(nextPow2(0.25) == 0.5); + assert(nextPow2(-4.0) == -8.0); + + assert(nextPow2(double.max) == 0.0); + assert(nextPow2(double.infinity) == double.infinity); +} + +@safe @nogc pure nothrow unittest +{ + import std.math.algebraic; + + assert(truncPow2(3) == 2); + assert(truncPow2(4) == 4); + assert(truncPow2(10) == 8); + assert(truncPow2(4000) == 2048); + + assert(truncPow2(-5) == -4); + assert(truncPow2(-20) == -16); + + assert(truncPow2(uint.max) == int.max + 1); + assert(truncPow2(uint.min) == 0); + assert(truncPow2(ulong.max) == long.max + 1); + assert(truncPow2(ulong.min) == 0); + + assert(truncPow2(int.max) == (int.max / 2) + 1); + assert(truncPow2(int.min) == int.min); + assert(truncPow2(long.max) == (long.max / 2) + 1); + assert(truncPow2(long.min) == long.min); +} + +@safe @nogc pure nothrow unittest +{ + import std.math.algebraic; + + assert(truncPow2(2.1) == 2.0); + assert(truncPow2(7.0) == 4.0); + assert(truncPow2(-1.9) == -1.0); + assert(truncPow2(0.24) == 0.125); + assert(truncPow2(-7.0) == -4.0); + + assert(truncPow2(double.infinity) == double.infinity); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_math_exponential.d b/libphobos/testsuite/libphobos.phobos/std_math_exponential.d new file mode 100644 index 000000000000..3ba0a828fa2b --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_math_exponential.d @@ -0,0 +1,279 @@ +@safe pure nothrow @nogc unittest +{ + import std.math.exponential; + + import std.math.operations : feqrel; + + assert(pow(2.0, 5) == 32.0); + assert(pow(1.5, 9).feqrel(38.4433) > 16); + assert(pow(real.nan, 2) is real.nan); + assert(pow(real.infinity, 2) == real.infinity); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.exponential; + + assert(pow(2, 3) == 8); + assert(pow(3, 2) == 9); + + assert(pow(2, 10) == 1_024); + assert(pow(2, 20) == 1_048_576); + assert(pow(2, 30) == 1_073_741_824); + + assert(pow(0, 0) == 1); + + assert(pow(1, -5) == 1); + assert(pow(1, -6) == 1); + assert(pow(-1, -5) == -1); + assert(pow(-1, -6) == 1); + + assert(pow(-2, 5) == -32); + assert(pow(-2, -5) == 0); + assert(pow(cast(double) -2, -5) == -0.03125); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.exponential; + + assert(pow(2, 5.0) == 32.0); + assert(pow(7, 3.0) == 343.0); + assert(pow(2, real.nan) is real.nan); + assert(pow(2, real.infinity) == real.infinity); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.exponential; + + import std.math.operations : isClose; + + assert(isClose(pow(2.0, 3.0), 8.0)); + assert(isClose(pow(1.5, 10.0), 57.6650390625)); + + // square root of 9 + assert(isClose(pow(9.0, 0.5), 3.0)); + // 10th root of 1024 + assert(isClose(pow(1024.0, 0.1), 2.0)); + + assert(isClose(pow(-4.0, 3.0), -64.0)); + + // reciprocal of 4 ^^ 2 + assert(isClose(pow(4.0, -2.0), 0.0625)); + // reciprocal of (-2) ^^ 3 + assert(isClose(pow(-2.0, -3.0), -0.125)); + + assert(isClose(pow(-2.5, 3.0), -15.625)); + // reciprocal of 2.5 ^^ 3 + assert(isClose(pow(2.5, -3.0), 0.064)); + // reciprocal of (-2.5) ^^ 3 + assert(isClose(pow(-2.5, -3.0), -0.064)); + + // reciprocal of square root of 4 + assert(isClose(pow(4.0, -0.5), 0.5)); + + // per definition + assert(isClose(pow(0.0, 0.0), 1.0)); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.exponential; + + import std.math.operations : isClose; + + // the result is a complex number + // which cannot be represented as floating point number + import std.math.traits : isNaN; + assert(isNaN(pow(-2.5, -1.5))); + + // use the ^^-operator of std.complex instead + import std.complex : complex; + auto c1 = complex(-2.5, 0.0); + auto c2 = complex(-1.5, 0.0); + auto result = c1 ^^ c2; + // exact result apparently depends on `real` precision => increased tolerance + assert(isClose(result.re, -4.64705438e-17, 2e-4)); + assert(isClose(result.im, 2.52982e-1, 2e-4)); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.exponential; + + assert(powmod(1U, 10U, 3U) == 1); + assert(powmod(3U, 2U, 6U) == 3); + assert(powmod(5U, 5U, 15U) == 5); + assert(powmod(2U, 3U, 5U) == 3); + assert(powmod(2U, 4U, 5U) == 1); + assert(powmod(2U, 5U, 5U) == 2); +} + +@safe unittest +{ + import std.math.exponential; + + import std.math.operations : feqrel; + import std.math.constants : E; + + assert(exp(0.0) == 1.0); + assert(exp(3.0).feqrel(E * E * E) > 16); +} + +@safe unittest +{ + import std.math.exponential; + + import std.math.traits : isIdentical; + import std.math.operations : feqrel; + + assert(isIdentical(expm1(0.0), 0.0)); + assert(expm1(1.0).feqrel(1.71828) > 16); + assert(expm1(2.0).feqrel(6.3890) > 16); +} + +@safe unittest +{ + import std.math.exponential; + + import std.math.traits : isIdentical; + import std.math.operations : feqrel; + + assert(isIdentical(exp2(0.0), 1.0)); + assert(exp2(2.0).feqrel(4.0) > 16); + assert(exp2(8.0).feqrel(256.0) > 16); +} + +@safe unittest +{ + import std.math.exponential; + + import std.math.operations : isClose; + + int exp; + real mantissa = frexp(123.456L, exp); + + assert(isClose(mantissa * pow(2.0L, cast(real) exp), 123.456L)); + + assert(frexp(-real.nan, exp) && exp == int.min); + assert(frexp(real.nan, exp) && exp == int.min); + assert(frexp(-real.infinity, exp) == -real.infinity && exp == int.min); + assert(frexp(real.infinity, exp) == real.infinity && exp == int.max); + assert(frexp(-0.0, exp) == -0.0 && exp == 0); + assert(frexp(0.0, exp) == 0.0 && exp == 0); +} + +@safe pure unittest +{ + import std.math.exponential; + + assert(ilogb(1) == 0); + assert(ilogb(3) == 1); + assert(ilogb(3.0) == 1); + assert(ilogb(100_000_000) == 26); + + assert(ilogb(0) == FP_ILOGB0); + assert(ilogb(0.0) == FP_ILOGB0); + assert(ilogb(double.nan) == FP_ILOGBNAN); + assert(ilogb(double.infinity) == int.max); +} + +@safe pure unittest +{ + import std.math.exponential; + + assert(ilogb(0) == FP_ILOGB0); + assert(ilogb(0.0) == FP_ILOGB0); + assert(ilogb(double.nan) == FP_ILOGBNAN); +} + +@nogc @safe pure nothrow unittest +{ + import std.math.exponential; + + import std.meta : AliasSeq; + static foreach (T; AliasSeq!(float, double, real)) + {{ + T r; + + r = ldexp(3.0L, 3); + assert(r == 24); + + r = ldexp(cast(T) 3.0, cast(int) 3); + assert(r == 24); + + T n = 3.0; + int exp = 3; + r = ldexp(n, exp); + assert(r == 24); + }} +} + +@safe pure nothrow @nogc unittest +{ + import std.math.exponential; + + import std.math.operations : feqrel; + import std.math.constants : E; + + assert(feqrel(log(E), 1) >= real.mant_dig - 1); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.exponential; + + import std.math.algebraic : fabs; + + assert(fabs(log10(1000.0L) - 3) < .000001); +} + +@safe pure unittest +{ + import std.math.exponential; + + import std.math.traits : isIdentical, isNaN; + import std.math.operations : feqrel; + + assert(isIdentical(log1p(0.0), 0.0)); + assert(log1p(1.0).feqrel(0.69314) > 16); + + assert(log1p(-1.0) == -real.infinity); + assert(isNaN(log1p(-2.0))); + assert(log1p(real.nan) is real.nan); + assert(log1p(-real.nan) is -real.nan); + assert(log1p(real.infinity) == real.infinity); +} + +@safe unittest +{ + import std.math.exponential; + + import std.math.operations : isClose; + + assert(isClose(log2(1024.0L), 10)); +} + +@safe @nogc nothrow unittest +{ + import std.math.exponential; + + assert(logb(1.0) == 0); + assert(logb(100.0) == 6); + + assert(logb(0.0) == -real.infinity); + assert(logb(real.infinity) == real.infinity); + assert(logb(-real.infinity) == real.infinity); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.exponential; + + assert(scalbn(0x1.2345678abcdefp0L, 999) == 0x1.2345678abcdefp999L); + assert(scalbn(-real.infinity, 5) == -real.infinity); + assert(scalbn(2.0,10) == 2048.0); + assert(scalbn(2048.0f,-10) == 2.0f); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_math_hardware.d b/libphobos/testsuite/libphobos.phobos/std_math_hardware.d new file mode 100644 index 000000000000..c88f59f10419 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_math_hardware.d @@ -0,0 +1,18 @@ +@safe unittest +{ + import std.math.hardware; + + import std.math.rounding : lrint; + + FloatingPointControl fpctrl; + + fpctrl.rounding = FloatingPointControl.roundDown; + assert(lrint(1.5) == 1.0); + + fpctrl.rounding = FloatingPointControl.roundUp; + assert(lrint(1.4) == 2.0); + + fpctrl.rounding = FloatingPointControl.roundToNearest; + assert(lrint(1.5) == 2.0); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_math_operations.d b/libphobos/testsuite/libphobos.phobos/std_math_operations.d new file mode 100644 index 000000000000..b0678f10c364 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_math_operations.d @@ -0,0 +1,217 @@ +@safe @nogc pure nothrow unittest +{ + import std.math.operations; + + import std.math.traits : isNaN; + + real a = NaN(1_000_000); + assert(isNaN(a)); + assert(getNaNPayload(a) == 1_000_000); +} + +@safe @nogc pure nothrow unittest +{ + import std.math.operations; + + import std.math.traits : isNaN; + + real a = NaN(1_000_000); + assert(isNaN(a)); + assert(getNaNPayload(a) == 1_000_000); +} + +@safe @nogc pure nothrow unittest +{ + import std.math.operations; + + assert(nextUp(1.0 - 1.0e-6).feqrel(0.999999) > 16); + assert(nextUp(1.0 - real.epsilon).feqrel(1.0) > 16); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.operations; + + assert( nextDown(1.0 + real.epsilon) == 1.0); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.operations; + + import std.math.traits : isNaN; + + float a = 1; + assert(is(typeof(nextafter(a, a)) == float)); + assert(nextafter(a, a.infinity) > a); + assert(isNaN(nextafter(a, a.nan))); + assert(isNaN(nextafter(a.nan, a))); + + double b = 2; + assert(is(typeof(nextafter(b, b)) == double)); + assert(nextafter(b, b.infinity) > b); + assert(isNaN(nextafter(b, b.nan))); + assert(isNaN(nextafter(b.nan, b))); + + real c = 3; + assert(is(typeof(nextafter(c, c)) == real)); + assert(nextafter(c, c.infinity) > c); + assert(isNaN(nextafter(c, c.nan))); + assert(isNaN(nextafter(c.nan, c))); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.operations; + + import std.math.traits : isNaN; + + assert(fdim(2.0, 0.0) == 2.0); + assert(fdim(-2.0, 0.0) == 0.0); + assert(fdim(real.infinity, 2.0) == real.infinity); + assert(isNaN(fdim(real.nan, 2.0))); + assert(isNaN(fdim(2.0, real.nan))); + assert(isNaN(fdim(real.nan, real.nan))); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.operations; + + import std.meta : AliasSeq; + static foreach (F; AliasSeq!(float, double, real)) + { + assert(fmax(F(0.0), F(2.0)) == 2.0); + assert(fmax(F(-2.0), 0.0) == F(0.0)); + assert(fmax(F.infinity, F(2.0)) == F.infinity); + assert(fmax(F.nan, F(2.0)) == F(2.0)); + assert(fmax(F(2.0), F.nan) == F(2.0)); + } +} + +@safe pure nothrow @nogc unittest +{ + import std.math.operations; + + import std.meta : AliasSeq; + static foreach (F; AliasSeq!(float, double, real)) + { + assert(fmin(F(0.0), F(2.0)) == 0.0); + assert(fmin(F(-2.0), F(0.0)) == -2.0); + assert(fmin(F.infinity, F(2.0)) == 2.0); + assert(fmin(F.nan, F(2.0)) == 2.0); + assert(fmin(F(2.0), F.nan) == 2.0); + } +} + +@safe pure nothrow @nogc unittest +{ + import std.math.operations; + + assert(fma(0.0, 2.0, 2.0) == 2.0); + assert(fma(2.0, 2.0, 2.0) == 6.0); + assert(fma(real.infinity, 2.0, 2.0) == real.infinity); + assert(fma(real.nan, 2.0, 2.0) is real.nan); + assert(fma(2.0, 2.0, real.nan) is real.nan); +} + +@safe pure unittest +{ + import std.math.operations; + + assert(feqrel(2.0, 2.0) == 53); + assert(feqrel(2.0f, 2.0f) == 24); + assert(feqrel(2.0, double.nan) == 0); + + // Test that numbers are within n digits of each + // other by testing if feqrel > n * log2(10) + + // five digits + assert(feqrel(2.0, 2.00001) > 16); + // ten digits + assert(feqrel(2.0, 2.00000000001) > 33); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.operations; + + assert(isClose(1.0,0.999_999_999)); + assert(isClose(0.001, 0.000_999_999_999)); + assert(isClose(1_000_000_000.0,999_999_999.0)); + + assert(isClose(17.123_456_789, 17.123_456_78)); + assert(!isClose(17.123_456_789, 17.123_45)); + + // use explicit 3rd parameter for less (or more) accuracy + assert(isClose(17.123_456_789, 17.123_45, 1e-6)); + assert(!isClose(17.123_456_789, 17.123_45, 1e-7)); + + // use 4th parameter when comparing close to zero + assert(!isClose(1e-100, 0.0)); + assert(isClose(1e-100, 0.0, 0.0, 1e-90)); + assert(!isClose(1e-10, -1e-10)); + assert(isClose(1e-10, -1e-10, 0.0, 1e-9)); + assert(!isClose(1e-300, 1e-298)); + assert(isClose(1e-300, 1e-298, 0.0, 1e-200)); + + // different default limits for different floating point types + assert(isClose(1.0f, 0.999_99f)); + assert(!isClose(1.0, 0.999_99)); + static if (real.sizeof > double.sizeof) + assert(!isClose(1.0L, 0.999_999_999L)); +} + +@safe pure nothrow unittest +{ + import std.math.operations; + + assert(isClose([1.0, 2.0, 3.0], [0.999_999_999, 2.000_000_001, 3.0])); + assert(!isClose([1.0, 2.0], [0.999_999_999, 2.000_000_001, 3.0])); + assert(!isClose([1.0, 2.0, 3.0], [0.999_999_999, 2.000_000_001])); + + assert(isClose([2.0, 1.999_999_999, 2.000_000_001], 2.0)); + assert(isClose(2.0, [2.0, 1.999_999_999, 2.000_000_001])); +} + +@safe unittest +{ + import std.math.operations; + + assert(cmp(-double.infinity, -double.max) < 0); + assert(cmp(-double.max, -100.0) < 0); + assert(cmp(-100.0, -0.5) < 0); + assert(cmp(-0.5, 0.0) < 0); + assert(cmp(0.0, 0.5) < 0); + assert(cmp(0.5, 100.0) < 0); + assert(cmp(100.0, double.max) < 0); + assert(cmp(double.max, double.infinity) < 0); + + assert(cmp(1.0, 1.0) == 0); +} + +@safe unittest +{ + import std.math.operations; + + assert(cmp(-0.0, +0.0) < 0); + assert(cmp(+0.0, -0.0) > 0); +} + +@safe unittest +{ + import std.math.operations; + + assert(cmp(-double.nan, -double.infinity) < 0); + assert(cmp(double.infinity, double.nan) < 0); + assert(cmp(-double.nan, double.nan) < 0); +} + +@safe unittest +{ + import std.math.operations; + + assert(cmp(NaN(10), NaN(20)) < 0); + assert(cmp(-NaN(20), -NaN(10)) < 0); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_math_remainder.d b/libphobos/testsuite/libphobos.phobos/std_math_remainder.d new file mode 100644 index 000000000000..114b5d546f32 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_math_remainder.d @@ -0,0 +1,54 @@ +@safe unittest +{ + import std.math.remainder; + + import std.math.operations : feqrel; + import std.math.traits : isIdentical, isNaN; + + assert(isIdentical(fmod(0.0, 1.0), 0.0)); + assert(fmod(5.0, 3.0).feqrel(2.0) > 16); + assert(isNaN(fmod(5.0, 0.0))); +} + +@safe unittest +{ + import std.math.remainder; + + import std.math.operations : feqrel; + + real frac; + real intpart; + + frac = modf(3.14159, intpart); + assert(intpart.feqrel(3.0) > 16); + assert(frac.feqrel(0.14159) > 16); +} + +@safe @nogc nothrow unittest +{ + import std.math.remainder; + + import std.math.operations : feqrel; + import std.math.traits : isNaN; + + assert(remainder(5.1, 3.0).feqrel(-0.9) > 16); + assert(remainder(-5.1, 3.0).feqrel(0.9) > 16); + assert(remainder(0.0, 3.0) == 0.0); + + assert(isNaN(remainder(1.0, 0.0))); + assert(isNaN(remainder(-1.0, 0.0))); +} + +@safe @nogc nothrow unittest +{ + import std.math.remainder; + + import std.math.operations : feqrel; + + int n; + + assert(remquo(5.1, 3.0, n).feqrel(-0.9) > 16 && n == 2); + assert(remquo(-5.1, 3.0, n).feqrel(0.9) > 16 && n == -2); + assert(remquo(0.0, 3.0, n) == 0.0 && n == 0); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_math_rounding.d b/libphobos/testsuite/libphobos.phobos/std_math_rounding.d new file mode 100644 index 000000000000..8c8704550fd7 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_math_rounding.d @@ -0,0 +1,171 @@ +@safe pure nothrow @nogc unittest +{ + import std.math.rounding; + + import std.math.traits : isNaN; + + assert(ceil(+123.456L) == +124); + assert(ceil(-123.456L) == -123); + assert(ceil(-1.234L) == -1); + assert(ceil(-0.123L) == 0); + assert(ceil(0.0L) == 0); + assert(ceil(+0.123L) == 1); + assert(ceil(+1.234L) == 2); + assert(ceil(real.infinity) == real.infinity); + assert(isNaN(ceil(real.nan))); + assert(isNaN(ceil(real.init))); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.rounding; + + import std.math.traits : isNaN; + + assert(floor(+123.456L) == +123); + assert(floor(-123.456L) == -124); + assert(floor(+123.0L) == +123); + assert(floor(-124.0L) == -124); + assert(floor(-1.234L) == -2); + assert(floor(-0.123L) == -1); + assert(floor(0.0L) == 0); + assert(floor(+0.123L) == 0); + assert(floor(+1.234L) == 1); + assert(floor(real.infinity) == real.infinity); + assert(isNaN(floor(real.nan))); + assert(isNaN(floor(real.init))); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.rounding; + + import std.math.operations : isClose; + + assert(isClose(12345.6789L.quantize(0.01L), 12345.68L)); + assert(isClose(12345.6789L.quantize!floor(0.01L), 12345.67L)); + assert(isClose(12345.6789L.quantize(22.0L), 12342.0L)); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.rounding; + + import std.math.operations : isClose; + import std.math.traits : isNaN; + + assert(isClose(12345.6789L.quantize(0), 12345.6789L)); + assert(12345.6789L.quantize(real.infinity).isNaN); + assert(12345.6789L.quantize(real.nan).isNaN); + assert(real.infinity.quantize(0.01L) == real.infinity); + assert(real.infinity.quantize(real.nan).isNaN); + assert(real.nan.quantize(0.01L).isNaN); + assert(real.nan.quantize(real.infinity).isNaN); + assert(real.nan.quantize(real.nan).isNaN); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.rounding; + + import std.math.operations : isClose; + + assert(isClose(12345.6789L.quantize!10(-2), 12345.68L)); + assert(isClose(12345.6789L.quantize!(10, -2), 12345.68L)); + assert(isClose(12345.6789L.quantize!(10, floor)(-2), 12345.67L)); + assert(isClose(12345.6789L.quantize!(10, -2, floor), 12345.67L)); + + assert(isClose(12345.6789L.quantize!22(1), 12342.0L)); + assert(isClose(12345.6789L.quantize!22, 12342.0L)); +} + +@safe pure unittest +{ + import std.math.rounding; + + import std.math.traits : isNaN; + + assert(nearbyint(0.4) == 0); + assert(nearbyint(0.5) == 0); + assert(nearbyint(0.6) == 1); + assert(nearbyint(100.0) == 100); + + assert(isNaN(nearbyint(real.nan))); + assert(nearbyint(real.infinity) == real.infinity); + assert(nearbyint(-real.infinity) == -real.infinity); +} + +@safe unittest +{ + import std.math.rounding; + + import std.math.traits : isNaN; + + version (IeeeFlagsSupport) resetIeeeFlags(); + assert(rint(0.4) == 0); + version (GNU) { /* inexact bit not set with enabled optimizations */ } else + version (IeeeFlagsSupport) assert(ieeeFlags.inexact); + + assert(rint(0.5) == 0); + assert(rint(0.6) == 1); + assert(rint(100.0) == 100); + + assert(isNaN(rint(real.nan))); + assert(rint(real.infinity) == real.infinity); + assert(rint(-real.infinity) == -real.infinity); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.rounding; + + assert(lrint(4.5) == 4); + assert(lrint(5.5) == 6); + assert(lrint(-4.5) == -4); + assert(lrint(-5.5) == -6); + + assert(lrint(int.max - 0.5) == 2147483646L); + assert(lrint(int.max + 0.5) == 2147483648L); + assert(lrint(int.min - 0.5) == -2147483648L); + assert(lrint(int.min + 0.5) == -2147483648L); +} + +@safe nothrow @nogc unittest +{ + import std.math.rounding; + + assert(round(4.5) == 5); + assert(round(5.4) == 5); + assert(round(-4.5) == -5); + assert(round(-5.1) == -5); +} + +@safe nothrow @nogc unittest +{ + import std.math.rounding; + + assert(lround(0.49) == 0); + assert(lround(0.5) == 1); + assert(lround(1.5) == 2); +} + +@safe pure unittest +{ + import std.math.rounding; + + assert(trunc(0.01) == 0); + assert(trunc(0.49) == 0); + assert(trunc(0.5) == 0); + assert(trunc(1.5) == 1); +} + +@safe unittest +{ + import std.math.rounding; + + assert(rndtol(1.0) == 1L); + assert(rndtol(1.2) == 1L); + assert(rndtol(1.7) == 2L); + assert(rndtol(1.0001) == 1L); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_math_traits.d b/libphobos/testsuite/libphobos.phobos/std_math_traits.d new file mode 100644 index 000000000000..952de85c98d7 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_math_traits.d @@ -0,0 +1,189 @@ +@safe pure nothrow @nogc unittest +{ + import std.math.traits; + + assert( isNaN(float.init)); + assert( isNaN(-double.init)); + assert( isNaN(real.nan)); + assert( isNaN(-real.nan)); + assert(!isNaN(cast(float) 53.6)); + assert(!isNaN(cast(real)-53.6)); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.traits; + + assert( isFinite(1.23f)); + assert( isFinite(float.max)); + assert( isFinite(float.min_normal)); + assert(!isFinite(float.nan)); + assert(!isFinite(float.infinity)); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.traits; + + float f = 3; + double d = 500; + real e = 10e+48; + + assert(isNormal(f)); + assert(isNormal(d)); + assert(isNormal(e)); + f = d = e = 0; + assert(!isNormal(f)); + assert(!isNormal(d)); + assert(!isNormal(e)); + assert(!isNormal(real.infinity)); + assert(isNormal(-real.max)); + assert(!isNormal(real.min_normal/4)); + +} + +@safe pure nothrow @nogc unittest +{ + import std.math.traits; + + import std.meta : AliasSeq; + + static foreach (T; AliasSeq!(float, double, real)) + {{ + T f; + for (f = 1.0; !isSubnormal(f); f /= 2) + assert(f != 0); + }} +} + +@nogc @safe pure nothrow unittest +{ + import std.math.traits; + + assert(!isInfinity(float.init)); + assert(!isInfinity(-float.init)); + assert(!isInfinity(float.nan)); + assert(!isInfinity(-float.nan)); + assert(isInfinity(float.infinity)); + assert(isInfinity(-float.infinity)); + assert(isInfinity(-1.0f / 0.0f)); +} + +@safe @nogc pure nothrow unittest +{ + import std.math.traits; + + // We're forcing the CTFE to run by assigning the result of the function to an enum + enum test1 = isIdentical(1.0,1.0); + enum test2 = isIdentical(real.nan,real.nan); + enum test3 = isIdentical(real.infinity, real.infinity); + enum test4 = isIdentical(real.infinity, real.infinity); + enum test5 = isIdentical(0.0, 0.0); + + assert(test1); + assert(test2); + assert(test3); + assert(test4); + assert(test5); + + enum test6 = !isIdentical(0.0, -0.0); + enum test7 = !isIdentical(real.nan, -real.nan); + enum test8 = !isIdentical(real.infinity, -real.infinity); + + assert(test6); + assert(test7); + assert(test8); +} + +@nogc @safe pure nothrow unittest +{ + import std.math.traits; + + assert(!signbit(float.nan)); + assert(signbit(-float.nan)); + assert(!signbit(168.1234f)); + assert(signbit(-168.1234f)); + assert(!signbit(0.0f)); + assert(signbit(-0.0f)); + assert(signbit(-float.max)); + assert(!signbit(float.max)); + + assert(!signbit(double.nan)); + assert(signbit(-double.nan)); + assert(!signbit(168.1234)); + assert(signbit(-168.1234)); + assert(!signbit(0.0)); + assert(signbit(-0.0)); + assert(signbit(-double.max)); + assert(!signbit(double.max)); + + assert(!signbit(real.nan)); + assert(signbit(-real.nan)); + assert(!signbit(168.1234L)); + assert(signbit(-168.1234L)); + assert(!signbit(0.0L)); + assert(signbit(-0.0L)); + assert(signbit(-real.max)); + assert(!signbit(real.max)); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.traits; + + assert(copysign(1.0, 1.0) == 1.0); + assert(copysign(1.0, -0.0) == -1.0); + assert(copysign(1UL, -1.0) == -1.0); + assert(copysign(-1.0, -1.0) == -1.0); + + assert(copysign(real.infinity, -1.0) == -real.infinity); + assert(copysign(real.nan, 1.0) is real.nan); + assert(copysign(-real.nan, 1.0) is real.nan); + assert(copysign(real.nan, -1.0) is -real.nan); +} + +@safe pure nothrow @nogc unittest +{ + import std.math.traits; + + assert(sgn(168.1234) == 1); + assert(sgn(-168.1234) == -1); + assert(sgn(0.0) == 0); + assert(sgn(-0.0) == 0); +} + +@safe unittest +{ + import std.math.traits; + + import std.math.exponential : pow; + + assert( isPowerOf2(1.0L)); + assert( isPowerOf2(2.0L)); + assert( isPowerOf2(0.5L)); + assert( isPowerOf2(pow(2.0L, 96))); + assert( isPowerOf2(pow(2.0L, -77))); + + assert(!isPowerOf2(-2.0L)); + assert(!isPowerOf2(-0.5L)); + assert(!isPowerOf2(0.0L)); + assert(!isPowerOf2(4.315)); + assert(!isPowerOf2(1.0L / 3.0L)); + + assert(!isPowerOf2(real.nan)); + assert(!isPowerOf2(real.infinity)); +} + +@safe unittest +{ + import std.math.traits; + + assert( isPowerOf2(1)); + assert( isPowerOf2(2)); + assert( isPowerOf2(1uL << 63)); + + assert(!isPowerOf2(-4)); + assert(!isPowerOf2(0)); + assert(!isPowerOf2(1337u)); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_math_trigonometry.d b/libphobos/testsuite/libphobos.phobos/std_math_trigonometry.d new file mode 100644 index 000000000000..88a43976e968 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_math_trigonometry.d @@ -0,0 +1,168 @@ +@safe unittest +{ + import std.math.trigonometry; + + import std.math.operations : isClose; + + assert(cos(0.0) == 1.0); + assert(cos(1.0).isClose(0.5403023059)); + assert(cos(3.0).isClose(-0.9899924966)); +} + +@safe unittest +{ + import std.math.trigonometry; + + import std.math.constants : PI; + import std.stdio : writefln; + + void someFunc() + { + real x = 30.0; + auto result = sin(x * (PI / 180)); // convert degrees to radians + writefln("The sine of %s degrees is %s", x, result); + } +} + +@safe unittest +{ + import std.math.trigonometry; + + import std.math.operations : isClose; + import std.math.traits : isIdentical; + import std.math.constants : PI; + import std.math.algebraic : sqrt; + + assert(isIdentical(tan(0.0), 0.0)); + assert(tan(PI).isClose(0, 0.0, 1e-10)); + assert(tan(PI / 3).isClose(sqrt(3.0))); +} + +@safe unittest +{ + import std.math.trigonometry; + + import std.math.operations : isClose; + import std.math.traits : isNaN; + import std.math.constants : PI; + + assert(acos(0.0).isClose(1.570796327)); + assert(acos(0.5).isClose(PI / 3)); + assert(acos(PI).isNaN); +} + +@safe unittest +{ + import std.math.trigonometry; + + import std.math.operations : isClose; + import std.math.traits : isIdentical, isNaN; + import std.math.constants : PI; + + assert(isIdentical(asin(0.0), 0.0)); + assert(asin(0.5).isClose(PI / 6)); + assert(asin(PI).isNaN); +} + +@safe unittest +{ + import std.math.trigonometry; + + import std.math.operations : isClose; + import std.math.traits : isIdentical; + import std.math.constants : PI; + import std.math.algebraic : sqrt; + + assert(isIdentical(atan(0.0), 0.0)); + assert(atan(sqrt(3.0)).isClose(PI / 3)); +} + +@safe unittest +{ + import std.math.trigonometry; + + import std.math.operations : isClose; + import std.math.constants : PI; + import std.math.algebraic : sqrt; + + assert(atan2(1.0, sqrt(3.0)).isClose(PI / 6)); +} + +@safe unittest +{ + import std.math.trigonometry; + + import std.math.constants : E; + import std.math.operations : isClose; + + assert(cosh(0.0) == 1.0); + assert(cosh(1.0).isClose((E + 1.0 / E) / 2)); +} + +@safe unittest +{ + import std.math.trigonometry; + + import std.math.constants : E; + import std.math.operations : isClose; + import std.math.traits : isIdentical; + + enum sinh1 = (E - 1.0 / E) / 2; + import std.meta : AliasSeq; + static foreach (F; AliasSeq!(float, double, real)) + { + assert(isIdentical(sinh(F(0.0)), F(0.0))); + assert(sinh(F(1.0)).isClose(F(sinh1))); + } +} + +@safe unittest +{ + import std.math.trigonometry; + + import std.math.operations : isClose; + import std.math.traits : isIdentical; + + assert(isIdentical(tanh(0.0), 0.0)); + assert(tanh(1.0).isClose(sinh(1.0) / cosh(1.0))); +} + +@safe @nogc nothrow unittest +{ + import std.math.trigonometry; + + import std.math.traits : isIdentical, isNaN; + + assert(isNaN(acosh(0.9))); + assert(isNaN(acosh(real.nan))); + assert(isIdentical(acosh(1.0), 0.0)); + assert(acosh(real.infinity) == real.infinity); + assert(isNaN(acosh(0.5))); +} + +@safe @nogc nothrow unittest +{ + import std.math.trigonometry; + + import std.math.traits : isIdentical, isNaN; + + assert(isIdentical(asinh(0.0), 0.0)); + assert(isIdentical(asinh(-0.0), -0.0)); + assert(asinh(real.infinity) == real.infinity); + assert(asinh(-real.infinity) == -real.infinity); + assert(isNaN(asinh(real.nan))); +} + +@safe @nogc nothrow unittest +{ + import std.math.trigonometry; + + import std.math.traits : isIdentical, isNaN; + + assert(isIdentical(atanh(0.0), 0.0)); + assert(isIdentical(atanh(-0.0),-0.0)); + assert(isNaN(atanh(real.nan))); + assert(isNaN(atanh(-real.infinity))); + assert(atanh(0.0) == 0); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_meta.d b/libphobos/testsuite/libphobos.phobos/std_meta.d new file mode 100644 index 000000000000..d5928462f1ed --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_meta.d @@ -0,0 +1,525 @@ +@safe unittest +{ + import std.meta; + + import std.meta; + alias TL = AliasSeq!(int, double); + + int foo(TL td) // same as int foo(int, double); + { + return td[0] + cast(int) td[1]; + } +} + +@safe unittest +{ + import std.meta; + + alias TL = AliasSeq!(int, double); + + alias Types = AliasSeq!(TL, char); + static assert(is(Types == AliasSeq!(int, double, char))); +} + +@safe unittest +{ + import std.meta; + + // Creates a compile-time sequence of function call expressions + // that each call `func` with the next variadic template argument + template Map(alias func, args...) + { + auto ref lazyItem() {return func(args[0]);} + + static if (args.length == 1) + { + alias Map = lazyItem; + } + else + { + // recurse + alias Map = AliasSeq!(lazyItem, Map!(func, args[1 .. $])); + } + } + + static void test(int a, int b) + { + assert(a == 4); + assert(b == 16); + } + + static int a = 2; + static int b = 4; + + test(Map!(i => i ^^ 2, a, b)); + assert(a == 2); + assert(b == 4); + + test(Map!((ref i) => i *= i, a, b)); + assert(a == 4); + assert(b == 16); + + static void testRef(ref int a, ref int b) + { + assert(a++ == 16); + assert(b++ == 256); + } + + testRef(Map!(function ref(ref i) => i *= i, a, b)); + assert(a == 17); + assert(b == 257); +} + +@safe unittest +{ + import std.meta; + + // Without Alias this would fail if Args[0] was e.g. a value and + // some logic would be needed to detect when to use enum instead + alias Head(Args...) = Alias!(Args[0]); + alias Tail(Args...) = Args[1 .. $]; + + alias Blah = AliasSeq!(3, int, "hello"); + static assert(Head!Blah == 3); + static assert(is(Head!(Tail!Blah) == int)); + static assert((Tail!Blah)[1] == "hello"); +} + +@safe unittest +{ + import std.meta; + + alias a = Alias!(123); + static assert(a == 123); + + enum abc = 1; + alias b = Alias!(abc); + static assert(b == 1); + + alias c = Alias!(3 + 4); + static assert(c == 7); + + alias concat = (s0, s1) => s0 ~ s1; + alias d = Alias!(concat("Hello", " World!")); + static assert(d == "Hello World!"); + + alias e = Alias!(int); + static assert(is(e == int)); + + alias f = Alias!(AliasSeq!(int)); + static assert(!is(typeof(f[0]))); //not an AliasSeq + static assert(is(f == int)); + + auto g = 6; + alias h = Alias!g; + ++h; + assert(g == 7); +} + +@safe unittest +{ + import std.meta; + + import std.stdio; + + void foo() + { + writefln("The index of long is %s", + staticIndexOf!(long, AliasSeq!(int, long, double))); + // prints: The index of long is 1 + } +} + +@safe unittest +{ + import std.meta; + + alias Types = AliasSeq!(int, long, double, char); + alias TL = Erase!(long, Types); + static assert(is(TL == AliasSeq!(int, double, char))); +} + +@safe unittest +{ + import std.meta; + + alias Types = AliasSeq!(int, long, long, int); + static assert(is(EraseAll!(long, Types) == AliasSeq!(int, int))); +} + +@safe unittest +{ + import std.meta; + + alias Types = AliasSeq!(int, long, long, int, float); + + alias TL = NoDuplicates!(Types); + static assert(is(TL == AliasSeq!(int, long, float))); +} + +@safe unittest +{ + import std.meta; + + alias Types = AliasSeq!(int, long, long, int, float); + + alias TL = Replace!(long, char, Types); + static assert(is(TL == AliasSeq!(int, char, long, int, float))); +} + +@safe unittest +{ + import std.meta; + + alias Types = AliasSeq!(int, long, long, int, float); + + alias TL = ReplaceAll!(long, char, Types); + static assert(is(TL == AliasSeq!(int, char, char, int, float))); +} + +@safe unittest +{ + import std.meta; + + alias Types = AliasSeq!(int, long, long, int, float, byte, ubyte, short, ushort, uint); + + alias TL = Reverse!(Types); + static assert(is(TL == AliasSeq!(uint, ushort, short, ubyte, byte, float, int, long, long, int))); +} + +@safe unittest +{ + import std.meta; + + class A { } + class B : A { } + class C : B { } + alias Types = AliasSeq!(A, C, B); + + MostDerived!(Object, Types) x; // x is declared as type C + static assert(is(typeof(x) == C)); +} + +@safe unittest +{ + import std.meta; + + class A { } + class B : A { } + class C : B { } + alias Types = AliasSeq!(A, C, B); + + alias TL = DerivedToFront!(Types); + static assert(is(TL == AliasSeq!(C, B, A))); + + alias TL2 = DerivedToFront!(A, A, A, B, B, B, C, C, C); + static assert(is(TL2 == AliasSeq!(C, C, C, B, B, B, A, A, A))); +} + +@safe unittest +{ + import std.meta; + + import std.traits : Unqual; + alias TL = staticMap!(Unqual, int, const int, immutable int, uint, ubyte, byte, short, ushort); + static assert(is(TL == AliasSeq!(int, int, int, uint, ubyte, byte, short, ushort))); +} + +@safe unittest +{ + import std.meta; + + import std.traits : isIntegral; + + static assert(!allSatisfy!(isIntegral, int, double)); + static assert( allSatisfy!(isIntegral, int, long)); +} + +@safe unittest +{ + import std.meta; + + import std.traits : isIntegral; + + static assert(!anySatisfy!(isIntegral, string, double)); + static assert( anySatisfy!(isIntegral, int, double)); +} + +@safe unittest +{ + import std.meta; + + import std.traits : isNarrowString, isUnsigned; + + alias Types1 = AliasSeq!(string, wstring, dchar[], char[], dstring, int); + alias TL1 = Filter!(isNarrowString, Types1); + static assert(is(TL1 == AliasSeq!(string, wstring, char[]))); + + alias Types2 = AliasSeq!(int, byte, ubyte, dstring, dchar, uint, ulong); + alias TL2 = Filter!(isUnsigned, Types2); + static assert(is(TL2 == AliasSeq!(ubyte, uint, ulong))); +} + +@safe unittest +{ + import std.meta; + + import std.traits : isPointer; + + alias isNoPointer = templateNot!isPointer; + static assert(!isNoPointer!(int*)); + static assert(allSatisfy!(isNoPointer, string, char, float)); +} + +@safe unittest +{ + import std.meta; + + import std.traits : isNumeric, isUnsigned; + + alias storesNegativeNumbers = templateAnd!(isNumeric, templateNot!isUnsigned); + static assert(storesNegativeNumbers!int); + static assert(!storesNegativeNumbers!string && !storesNegativeNumbers!uint); + + // An empty sequence of predicates always yields true. + alias alwaysTrue = templateAnd!(); + static assert(alwaysTrue!int); +} + +@safe unittest +{ + import std.meta; + + import std.traits : isPointer, isUnsigned; + + alias isPtrOrUnsigned = templateOr!(isPointer, isUnsigned); + static assert( isPtrOrUnsigned!uint && isPtrOrUnsigned!(short*)); + static assert(!isPtrOrUnsigned!int && !isPtrOrUnsigned!(string)); + + // An empty sequence of predicates never yields true. + alias alwaysFalse = templateOr!(); + static assert(!alwaysFalse!int); +} + +@safe unittest +{ + import std.meta; + + import std.algorithm.iteration : map; + import std.algorithm.sorting : sort; + import std.string : capitalize; + + struct S + { + int a; + int c; + int b; + } + + alias capMembers = aliasSeqOf!([__traits(allMembers, S)].sort().map!capitalize()); + static assert(capMembers[0] == "A"); + static assert(capMembers[1] == "B"); + static assert(capMembers[2] == "C"); +} + +@safe unittest +{ + import std.meta; + + static immutable REF = [0, 1, 2, 3]; + foreach (I, V; aliasSeqOf!([0, 1, 2, 3])) + { + static assert(V == I); + static assert(V == REF[I]); + } +} + +@safe unittest +{ + import std.meta; + + // enum bool isImplicitlyConvertible(From, To) + import std.traits : isImplicitlyConvertible; + + static assert(allSatisfy!( + ApplyLeft!(isImplicitlyConvertible, ubyte), + short, ushort, int, uint, long, ulong)); + + static assert(is(Filter!(ApplyRight!(isImplicitlyConvertible, short), + ubyte, string, short, float, int) == AliasSeq!(ubyte, short))); +} + +@safe unittest +{ + import std.meta; + + import std.traits : hasMember, ifTestable; + + struct T1 + { + bool foo; + } + + struct T2 + { + struct Test + { + bool opCast(T : bool)() { return true; } + } + + Test foo; + } + + static assert(allSatisfy!(ApplyRight!(hasMember, "foo"), T1, T2)); + static assert(allSatisfy!(ApplyRight!(ifTestable, a => a.foo), T1, T2)); +} + +@safe unittest +{ + import std.meta; + + import std.traits : Largest; + + alias Types = AliasSeq!(byte, short, int, long); + + static assert(is(staticMap!(ApplyLeft!(Largest, short), Types) == + AliasSeq!(short, short, int, long))); + static assert(is(staticMap!(ApplyLeft!(Largest, int), Types) == + AliasSeq!(int, int, int, long))); +} + +@safe unittest +{ + import std.meta; + + import std.traits : FunctionAttribute, SetFunctionAttributes; + + static void foo() @system; + static int bar(int) @system; + + alias SafeFunctions = AliasSeq!( + void function() @safe, + int function(int) @safe); + + static assert(is(staticMap!(ApplyRight!( + SetFunctionAttributes, "D", FunctionAttribute.safe), + typeof(&foo), typeof(&bar)) == SafeFunctions)); +} + +@safe unittest +{ + import std.meta; + + alias ImInt0 = Repeat!(0, int); + static assert(is(ImInt0 == AliasSeq!())); + + alias ImInt1 = Repeat!(1, immutable(int)); + static assert(is(ImInt1 == AliasSeq!(immutable(int)))); + + alias Real3 = Repeat!(3, real); + static assert(is(Real3 == AliasSeq!(real, real, real))); + + alias Real12 = Repeat!(4, Real3); + static assert(is(Real12 == AliasSeq!(real, real, real, real, real, real, + real, real, real, real, real, real))); + + alias Composite = AliasSeq!(uint, int); + alias Composite2 = Repeat!(2, Composite); + static assert(is(Composite2 == AliasSeq!(uint, int, uint, int))); + + alias ImInt10 = Repeat!(10, int); + static assert(is(ImInt10 == AliasSeq!(int, int, int, int, int, int, int, int, int, int))); + + alias Big = Repeat!(1_000_000, int); +} + +@safe unittest +{ + import std.meta; + + auto staticArray(T, size_t n)(Repeat!(n, T) elems) + { + T[n] a = [elems]; + return a; + } + + auto a = staticArray!(long, 3)(3, 1, 4); + assert(is(typeof(a) == long[3])); + assert(a == [3, 1, 4]); +} + +@safe unittest +{ + import std.meta; + + alias Nums = AliasSeq!(7, 2, 3, 23); + enum Comp(int N1, int N2) = N1 < N2; + static assert(AliasSeq!(2, 3, 7, 23) == staticSort!(Comp, Nums)); +} + +@safe unittest +{ + import std.meta; + + alias Types = AliasSeq!(uint, short, ubyte, long, ulong); + enum Comp(T1, T2) = __traits(isUnsigned, T2) - __traits(isUnsigned, T1); + static assert(is(AliasSeq!(uint, ubyte, ulong, short, long) == staticSort!(Comp, + Types))); +} + +@safe unittest +{ + import std.meta; + + enum Comp(int N1, int N2) = N1 < N2; + static assert( staticIsSorted!(Comp, 2, 2)); + static assert( staticIsSorted!(Comp, 2, 3, 7, 23)); + static assert(!staticIsSorted!(Comp, 7, 2, 3, 23)); +} + +@safe unittest +{ + import std.meta; + + enum Comp(T1, T2) = __traits(isUnsigned, T2) - __traits(isUnsigned, T1); + static assert( staticIsSorted!(Comp, uint, ubyte, ulong, short, long)); + static assert(!staticIsSorted!(Comp, uint, short, ubyte, long, ulong)); +} + +@safe unittest +{ + import std.meta; + + static assert(is(Stride!(1, short, int, long) == AliasSeq!(short, int, long))); + static assert(is(Stride!(2, short, int, long) == AliasSeq!(short, long))); + static assert(is(Stride!(-1, short, int, long) == AliasSeq!(long, int, short))); + static assert(is(Stride!(-2, short, int, long) == AliasSeq!(long, short))); + + alias attribs = AliasSeq!(short, int, long, ushort, uint, ulong); + static assert(is(Stride!(3, attribs) == AliasSeq!(short, ushort))); + static assert(is(Stride!(3, attribs[1 .. $]) == AliasSeq!(int, uint))); + static assert(is(Stride!(-3, attribs) == AliasSeq!(ulong, long))); +} + +@safe unittest +{ + import std.meta; + + // ApplyRight combined with Instantiate can be used to apply various + // templates to the same parameters. + import std.string : leftJustify, center, rightJustify; + alias functions = staticMap!(ApplyRight!(Instantiate, string), + leftJustify, center, rightJustify); + string result = ""; + static foreach (f; functions) + { + { + auto x = &f; // not a template, but a function instantiation + result ~= x("hello", 7); + result ~= ";"; + } + } + + assert(result == "hello ; hello ; hello;"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_mmfile.d b/libphobos/testsuite/libphobos.phobos/std_mmfile.d new file mode 100644 index 000000000000..73f2291e136d --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_mmfile.d @@ -0,0 +1,43 @@ +@system unittest +{ + import std.mmfile; + + import std.file; + std.file.write(deleteme, "hello"); // deleteme is a temporary filename + scope(exit) remove(deleteme); + + // Use a scope class so the file will be closed at the end of this function + scope mmfile = new MmFile(deleteme); + + assert(mmfile.length == "hello".length); + + // Access file contents with the slice operator + // This is typed as `void[]`, so cast to `char[]` or `ubyte[]` to use it + const data = cast(const(char)[]) mmfile[]; + + // At this point, the file content may not have been read yet. + // In that case, the following memory access will intentionally + // trigger a page fault, causing the kernel to load the file contents + assert(data[0 .. 5] == "hello"); +} + +@system unittest +{ + import std.mmfile; + + import std.file; + scope(exit) remove(deleteme); + + scope mmfile = new MmFile(deleteme, MmFile.Mode.readWriteNew, 5, null); + assert(mmfile.length == 5); + + auto data = cast(ubyte[]) mmfile[]; + + // This write to memory will be reflected in the file contents + data[] = '\n'; + + mmfile.flush(); + + assert(std.file.read(deleteme) == "\n\n\n\n\n"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_numeric.d b/libphobos/testsuite/libphobos.phobos/std_numeric.d new file mode 100644 index 000000000000..e88b5e5b2d5f --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_numeric.d @@ -0,0 +1,203 @@ +@safe unittest +{ + import std.numeric; + + import std.math.trigonometry : sin, cos; + + // Define a 16-bit floating point values + CustomFloat!16 x; // Using the number of bits + CustomFloat!(10, 5) y; // Using the precision and exponent width + CustomFloat!(10, 5,CustomFloatFlags.ieee) z; // Using the precision, exponent width and format flags + CustomFloat!(10, 5,CustomFloatFlags.ieee, 15) w; // Using the precision, exponent width, format flags and exponent offset bias + + // Use the 16-bit floats mostly like normal numbers + w = x*y - 1; + + // Functions calls require conversion + z = sin(+x) + cos(+y); // Use unary plus to concisely convert to a real + z = sin(x.get!float) + cos(y.get!float); // Or use get!T + z = sin(cast(float) x) + cos(cast(float) y); // Or use cast(T) to explicitly convert + + // Define a 8-bit custom float for storing probabilities + alias Probability = CustomFloat!(4, 4, CustomFloatFlags.ieee^CustomFloatFlags.probability^CustomFloatFlags.signed ); + auto p = Probability(0.5); +} + +@safe unittest +{ + import std.numeric; + + import std.math.operations : isClose; + + // Average numbers in an array + double avg(in double[] a) + { + if (a.length == 0) return 0; + FPTemporary!double result = 0; + foreach (e; a) result += e; + return result / a.length; + } + + auto a = [1.0, 2.0, 3.0]; + assert(isClose(avg(a), 2)); +} + +@safe unittest +{ + import std.numeric; + + import std.math.operations : isClose; + import std.math.trigonometry : cos; + + float f(float x) + { + return cos(x) - x*x*x; + } + auto x = secantMethod!(f)(0f, 1f); + assert(isClose(x, 0.865474)); +} + +@safe unittest +{ + import std.numeric; + + import std.math.operations : isClose; + + auto ret = findLocalMin((double x) => (x-4)^^2, -1e7, 1e7); + assert(ret.x.isClose(4.0)); + assert(ret.y.isClose(0.0, 0.0, 1e-10)); +} + +@safe unittest +{ + import std.numeric; + + double[] a = []; + assert(!normalize(a)); + a = [ 1.0, 3.0 ]; + assert(normalize(a)); + assert(a == [ 0.25, 0.75 ]); + assert(normalize!(typeof(a))(a, 50)); // a = [12.5, 37.5] + a = [ 0.0, 0.0 ]; + assert(!normalize(a)); + assert(a == [ 0.5, 0.5 ]); +} + +@safe unittest +{ + import std.numeric; + + import std.math.traits : isNaN; + + assert(sumOfLog2s(new double[0]) == 0); + assert(sumOfLog2s([0.0L]) == -real.infinity); + assert(sumOfLog2s([-0.0L]) == -real.infinity); + assert(sumOfLog2s([2.0L]) == 1); + assert(sumOfLog2s([-2.0L]).isNaN()); + assert(sumOfLog2s([real.nan]).isNaN()); + assert(sumOfLog2s([-real.nan]).isNaN()); + assert(sumOfLog2s([real.infinity]) == real.infinity); + assert(sumOfLog2s([-real.infinity]).isNaN()); + assert(sumOfLog2s([ 0.25, 0.25, 0.25, 0.125 ]) == -9); +} + +@safe unittest +{ + import std.numeric; + + import std.math.operations : isClose; + + double[] p = [ 0.0, 0, 0, 1 ]; + assert(kullbackLeiblerDivergence(p, p) == 0); + double[] p1 = [ 0.25, 0.25, 0.25, 0.25 ]; + assert(kullbackLeiblerDivergence(p1, p1) == 0); + assert(kullbackLeiblerDivergence(p, p1) == 2); + assert(kullbackLeiblerDivergence(p1, p) == double.infinity); + double[] p2 = [ 0.2, 0.2, 0.2, 0.4 ]; + assert(isClose(kullbackLeiblerDivergence(p1, p2), 0.0719281, 1e-5)); + assert(isClose(kullbackLeiblerDivergence(p2, p1), 0.0780719, 1e-5)); +} + +@safe unittest +{ + import std.numeric; + + import std.math.operations : isClose; + + double[] p = [ 0.0, 0, 0, 1 ]; + assert(jensenShannonDivergence(p, p) == 0); + double[] p1 = [ 0.25, 0.25, 0.25, 0.25 ]; + assert(jensenShannonDivergence(p1, p1) == 0); + assert(isClose(jensenShannonDivergence(p1, p), 0.548795, 1e-5)); + double[] p2 = [ 0.2, 0.2, 0.2, 0.4 ]; + assert(isClose(jensenShannonDivergence(p1, p2), 0.0186218, 1e-5)); + assert(isClose(jensenShannonDivergence(p2, p1), 0.0186218, 1e-5)); + assert(isClose(jensenShannonDivergence(p2, p1, 0.005), 0.00602366, 1e-5)); +} + +@system unittest +{ + import std.numeric; + + import std.math.operations : isClose; + import std.math.algebraic : sqrt; + + string[] s = ["Hello", "brave", "new", "world"]; + string[] t = ["Hello", "new", "world"]; + assert(gapWeightedSimilarity(s, s, 1) == 15); + assert(gapWeightedSimilarity(t, t, 1) == 7); + assert(gapWeightedSimilarity(s, t, 1) == 7); + assert(isClose(gapWeightedSimilarityNormalized(s, t, 1), + 7.0 / sqrt(15.0 * 7), 0.01)); +} + +@system unittest +{ + import std.numeric; + + string[] s = ["Hello", "brave", "new", "world"]; + string[] t = ["Hello", "new", "world"]; + auto simIter = gapWeightedSimilarityIncremental(s, t, 1.0); + assert(simIter.front == 3); // three 1-length matches + simIter.popFront(); + assert(simIter.front == 3); // three 2-length matches + simIter.popFront(); + assert(simIter.front == 1); // one 3-length match + simIter.popFront(); + assert(simIter.empty); // no more match +} + +@safe unittest +{ + import std.numeric; + + assert(gcd(2 * 5 * 7 * 7, 5 * 7 * 11) == 5 * 7); + const int a = 5 * 13 * 23 * 23, b = 13 * 59; + assert(gcd(a, b) == 13); +} + +@safe unittest +{ + import std.numeric; + + assert(lcm(1, 2) == 2); + assert(lcm(3, 4) == 12); + assert(lcm(5, 6) == 30); +} + +@safe pure @nogc unittest +{ + import std.numeric; + + ubyte[21] fac; + size_t idx = decimalToFactorial(2982, fac); + + assert(fac[0] == 4); + assert(fac[1] == 0); + assert(fac[2] == 4); + assert(fac[3] == 1); + assert(fac[4] == 0); + assert(fac[5] == 0); + assert(fac[6] == 0); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_outbuffer.d b/libphobos/testsuite/libphobos.phobos/std_outbuffer.d new file mode 100644 index 000000000000..fd0d9b7cf756 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_outbuffer.d @@ -0,0 +1,95 @@ +@safe unittest +{ + import std.outbuffer; + + OutBuffer buf = new OutBuffer(); + buf.write(cast(ubyte) 1); + buf.align2(); + assert(buf.toBytes() == "\x01\x00"); + buf.write(cast(ubyte) 2); + buf.align4(); + assert(buf.toBytes() == "\x01\x00\x02\x00"); + buf.write(cast(ubyte) 3); + buf.alignSize(8); + assert(buf.toBytes() == "\x01\x00\x02\x00\x03\x00\x00\x00"); + +} + +@safe unittest +{ + import std.outbuffer; + + OutBuffer buf = new OutBuffer(); + buf.write(cast(ubyte) 1); + buf.align2(0x55); + assert(buf.toBytes() == "\x01\x55"); + buf.write(cast(ubyte) 2); + buf.align4(0x55); + assert(buf.toBytes() == "\x01\x55\x02\x55"); + buf.write(cast(ubyte) 3); + buf.alignSize(8, 0x55); + assert(buf.toBytes() == "\x01\x55\x02\x55\x03\x55\x55\x55"); + +} + +@safe unittest +{ + import std.outbuffer; + + OutBuffer b = new OutBuffer(); + b.writef("a%sb", 16); + assert(b.toString() == "a16b"); + +} + +@safe unittest +{ + import std.outbuffer; + + OutBuffer b = new OutBuffer(); + b.writef!"a%sb"(16); + assert(b.toString() == "a16b"); + +} + +@safe unittest +{ + import std.outbuffer; + + OutBuffer b = new OutBuffer(); + b.writefln("a%sb", 16); + assert(b.toString() == "a16b\n"); + +} + +@safe unittest +{ + import std.outbuffer; + + OutBuffer b = new OutBuffer(); + b.writefln!"a%sb"(16); + assert(b.toString() == "a16b\n"); + +} + +@safe unittest +{ + import std.outbuffer; + + import std.string : cmp; + + OutBuffer buf = new OutBuffer(); + + assert(buf.offset == 0); + buf.write("hello"); + buf.write(cast(byte) 0x20); + buf.write("world"); + buf.writef(" %d", 62665); + assert(cmp(buf.toString(), "hello world 62665") == 0); + + buf.clear(); + assert(cmp(buf.toString(), "") == 0); + buf.write("New data"); + assert(cmp(buf.toString(),"New data") == 0); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_package.d b/libphobos/testsuite/libphobos.phobos/std_package.d new file mode 100644 index 000000000000..46a4f866484c --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_package.d @@ -0,0 +1,27 @@ +@safe unittest +{ + import std; + + import std; + + int len; + const r = 6.iota + .filter!(a => a % 2) // 1 3 5 + .map!(a => a * 2) // 2 6 10 + .tee!(_ => len++) + .substitute(6, -6) // 2 -6 10 + .sum + .reverseArgs!format("Sum: %d"); + + assert(len == 3); + assert(r == "Sum: 6"); +} + +@safe unittest +{ + import std; + + import std; + assert(10.iota.map!(a => pow(2, a)).sum == 1023); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_parallelism.d b/libphobos/testsuite/libphobos.phobos/std_parallelism.d new file mode 100644 index 000000000000..18418ac2a43c --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_parallelism.d @@ -0,0 +1,37 @@ +@system unittest +{ + import std.parallelism; + + import std.algorithm.iteration : map; + import std.math.operations : isClose; + import std.parallelism : taskPool; + import std.range : iota; + + // Parallel reduce can be combined with + // std.algorithm.iteration.map to interesting effect. + // The following example (thanks to Russel Winder) + // calculates pi by quadrature using + // std.algorithm.map and TaskPool.reduce. + // getTerm is evaluated in parallel as needed by + // TaskPool.reduce. + // + // Timings on an Intel i5-3450 quad core machine + // for n = 1_000_000_000: + // + // TaskPool.reduce: 1.067 s + // std.algorithm.reduce: 4.011 s + + enum n = 1_000_000; + enum delta = 1.0 / n; + + alias getTerm = (int i) + { + immutable x = ( i - 0.5 ) * delta; + return delta / ( 1.0 + x * x ) ; + }; + + immutable pi = 4.0 * taskPool.reduce!"a + b"(n.iota.map!getTerm); + + assert(pi.isClose(3.14159, 1e-5)); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_path.d b/libphobos/testsuite/libphobos.phobos/std_path.d new file mode 100644 index 000000000000..33ca98755190 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_path.d @@ -0,0 +1,611 @@ +@safe pure nothrow @nogc unittest +{ + import std.path; + + version (Windows) + { + assert( '/'.isDirSeparator); + assert( '\\'.isDirSeparator); + } + else + { + assert( '/'.isDirSeparator); + assert(!'\\'.isDirSeparator); + } +} + +@safe unittest +{ + import std.path; + + assert(baseName!(CaseSensitive.no)("dir/file.EXT", ".ext") == "file"); + assert(baseName!(CaseSensitive.yes)("dir/file.EXT", ".ext") != "file"); + + version (Posix) + assert(relativePath!(CaseSensitive.no)("/FOO/bar", "/foo/baz") == "../bar"); + else + assert(relativePath!(CaseSensitive.no)(`c:\FOO\bar`, `c:\foo\baz`) == `..\bar`); +} + +@safe unittest +{ + import std.path; + + assert(baseName("dir/file.ext") == "file.ext"); + assert(baseName("dir/file.ext", ".ext") == "file"); + assert(baseName("dir/file.ext", ".xyz") == "file.ext"); + assert(baseName("dir/filename", "name") == "file"); + assert(baseName("dir/subdir/") == "subdir"); + + version (Windows) + { + assert(baseName(`d:file.ext`) == "file.ext"); + assert(baseName(`d:\dir\file.ext`) == "file.ext"); + } +} + +@safe unittest +{ + import std.path; + + assert(dirName("") == "."); + assert(dirName("file"w) == "."); + assert(dirName("dir/"d) == "."); + assert(dirName("dir///") == "."); + assert(dirName("dir/file"w.dup) == "dir"); + assert(dirName("dir///file"d.dup) == "dir"); + assert(dirName("dir/subdir/") == "dir"); + assert(dirName("/dir/file"w) == "/dir"); + assert(dirName("/file"d) == "/"); + assert(dirName("/") == "/"); + assert(dirName("///") == "/"); + + version (Windows) + { + assert(dirName(`dir\`) == `.`); + assert(dirName(`dir\\\`) == `.`); + assert(dirName(`dir\file`) == `dir`); + assert(dirName(`dir\\\file`) == `dir`); + assert(dirName(`dir\subdir\`) == `dir`); + assert(dirName(`\dir\file`) == `\dir`); + assert(dirName(`\file`) == `\`); + assert(dirName(`\`) == `\`); + assert(dirName(`\\\`) == `\`); + assert(dirName(`d:`) == `d:`); + assert(dirName(`d:file`) == `d:`); + assert(dirName(`d:\`) == `d:\`); + assert(dirName(`d:\file`) == `d:\`); + assert(dirName(`d:\dir\file`) == `d:\dir`); + assert(dirName(`\\server\share\dir\file`) == `\\server\share\dir`); + assert(dirName(`\\server\share\file`) == `\\server\share`); + assert(dirName(`\\server\share\`) == `\\server\share`); + assert(dirName(`\\server\share`) == `\\server\share`); + } +} + +@safe unittest +{ + import std.path; + + assert(rootName("") is null); + assert(rootName("foo") is null); + assert(rootName("/") == "/"); + assert(rootName("/foo/bar") == "/"); + + version (Windows) + { + assert(rootName("d:foo") is null); + assert(rootName(`d:\foo`) == `d:\`); + assert(rootName(`\\server\share\foo`) == `\\server\share`); + assert(rootName(`\\server\share`) == `\\server\share`); + } +} + +@safe unittest +{ + import std.path; + + import std.range : empty; + version (Posix) assert(driveName("c:/foo").empty); + version (Windows) + { + assert(driveName(`dir\file`).empty); + assert(driveName(`d:file`) == "d:"); + assert(driveName(`d:\file`) == "d:"); + assert(driveName("d:") == "d:"); + assert(driveName(`\\server\share\file`) == `\\server\share`); + assert(driveName(`\\server\share\`) == `\\server\share`); + assert(driveName(`\\server\share`) == `\\server\share`); + + static assert(driveName(`d:\file`) == "d:"); + } +} + +@safe unittest +{ + import std.path; + + version (Windows) + { + assert(stripDrive(`d:\dir\file`) == `\dir\file`); + assert(stripDrive(`\\server\share\dir\file`) == `\dir\file`); + } +} + +@safe unittest +{ + import std.path; + + import std.range : empty; + assert(extension("file").empty); + assert(extension("file.") == "."); + assert(extension("file.ext"w) == ".ext"); + assert(extension("file.ext1.ext2"d) == ".ext2"); + assert(extension(".foo".dup).empty); + assert(extension(".foo.ext"w.dup) == ".ext"); + + static assert(extension("file").empty); + static assert(extension("file.ext") == ".ext"); +} + +@safe unittest +{ + import std.path; + + assert(stripExtension("file") == "file"); + assert(stripExtension("file.ext") == "file"); + assert(stripExtension("file.ext1.ext2") == "file.ext1"); + assert(stripExtension("file.") == "file"); + assert(stripExtension(".file") == ".file"); + assert(stripExtension(".file.ext") == ".file"); + assert(stripExtension("dir/file.ext") == "dir/file"); +} + +@safe unittest +{ + import std.path; + + assert(setExtension("file", "ext") == "file.ext"); + assert(setExtension("file"w, ".ext"w) == "file.ext"); + assert(setExtension("file."d, "ext"d) == "file.ext"); + assert(setExtension("file.", ".ext") == "file.ext"); + assert(setExtension("file.old"w, "new"w) == "file.new"); + assert(setExtension("file.old"d, ".new"d) == "file.new"); +} + +@safe unittest +{ + import std.path; + + import std.array; + assert(withExtension("file", "ext").array == "file.ext"); + assert(withExtension("file"w, ".ext"w).array == "file.ext"); + assert(withExtension("file.ext"w, ".").array == "file."); + + import std.utf : byChar, byWchar; + assert(withExtension("file".byChar, "ext").array == "file.ext"); + assert(withExtension("file"w.byWchar, ".ext"w).array == "file.ext"w); + assert(withExtension("file.ext"w.byWchar, ".").array == "file."w); +} + +@safe unittest +{ + import std.path; + + assert(defaultExtension("file", "ext") == "file.ext"); + assert(defaultExtension("file", ".ext") == "file.ext"); + assert(defaultExtension("file.", "ext") == "file."); + assert(defaultExtension("file.old", "new") == "file.old"); + assert(defaultExtension("file.old", ".new") == "file.old"); +} + +@safe unittest +{ + import std.path; + + import std.array; + assert(withDefaultExtension("file", "ext").array == "file.ext"); + assert(withDefaultExtension("file"w, ".ext").array == "file.ext"w); + assert(withDefaultExtension("file.", "ext").array == "file."); + assert(withDefaultExtension("file", "").array == "file."); + + import std.utf : byChar, byWchar; + assert(withDefaultExtension("file".byChar, "ext").array == "file.ext"); + assert(withDefaultExtension("file"w.byWchar, ".ext").array == "file.ext"w); + assert(withDefaultExtension("file.".byChar, "ext"d).array == "file."); + assert(withDefaultExtension("file".byChar, "").array == "file."); +} + +@safe unittest +{ + import std.path; + + version (Posix) + { + assert(buildPath("foo", "bar", "baz") == "foo/bar/baz"); + assert(buildPath("/foo/", "bar/baz") == "/foo/bar/baz"); + assert(buildPath("/foo", "/bar") == "/bar"); + } + + version (Windows) + { + assert(buildPath("foo", "bar", "baz") == `foo\bar\baz`); + assert(buildPath(`c:\foo`, `bar\baz`) == `c:\foo\bar\baz`); + assert(buildPath("foo", `d:\bar`) == `d:\bar`); + assert(buildPath("foo", `\bar`) == `\bar`); + assert(buildPath(`c:\foo`, `\bar`) == `c:\bar`); + } +} + +@safe unittest +{ + import std.path; + + import std.array; + version (Posix) + { + assert(chainPath("foo", "bar", "baz").array == "foo/bar/baz"); + assert(chainPath("/foo/", "bar/baz").array == "/foo/bar/baz"); + assert(chainPath("/foo", "/bar").array == "/bar"); + } + + version (Windows) + { + assert(chainPath("foo", "bar", "baz").array == `foo\bar\baz`); + assert(chainPath(`c:\foo`, `bar\baz`).array == `c:\foo\bar\baz`); + assert(chainPath("foo", `d:\bar`).array == `d:\bar`); + assert(chainPath("foo", `\bar`).array == `\bar`); + assert(chainPath(`c:\foo`, `\bar`).array == `c:\bar`); + } + + import std.utf : byChar; + version (Posix) + { + assert(chainPath("foo", "bar", "baz").array == "foo/bar/baz"); + assert(chainPath("/foo/".byChar, "bar/baz").array == "/foo/bar/baz"); + assert(chainPath("/foo", "/bar".byChar).array == "/bar"); + } + + version (Windows) + { + assert(chainPath("foo", "bar", "baz").array == `foo\bar\baz`); + assert(chainPath(`c:\foo`.byChar, `bar\baz`).array == `c:\foo\bar\baz`); + assert(chainPath("foo", `d:\bar`).array == `d:\bar`); + assert(chainPath("foo", `\bar`.byChar).array == `\bar`); + assert(chainPath(`c:\foo`, `\bar`w).array == `c:\bar`); + } +} + +@safe unittest +{ + import std.path; + + assert(buildNormalizedPath("foo", "..") == "."); + + version (Posix) + { + assert(buildNormalizedPath("/foo/./bar/..//baz/") == "/foo/baz"); + assert(buildNormalizedPath("../foo/.") == "../foo"); + assert(buildNormalizedPath("/foo", "bar/baz/") == "/foo/bar/baz"); + assert(buildNormalizedPath("/foo", "/bar/..", "baz") == "/baz"); + assert(buildNormalizedPath("foo/./bar", "../../", "../baz") == "../baz"); + assert(buildNormalizedPath("/foo/./bar", "../../baz") == "/baz"); + } + + version (Windows) + { + assert(buildNormalizedPath(`c:\foo\.\bar/..\\baz\`) == `c:\foo\baz`); + assert(buildNormalizedPath(`..\foo\.`) == `..\foo`); + assert(buildNormalizedPath(`c:\foo`, `bar\baz\`) == `c:\foo\bar\baz`); + assert(buildNormalizedPath(`c:\foo`, `bar/..`) == `c:\foo`); + assert(buildNormalizedPath(`\\server\share\foo`, `..\bar`) == + `\\server\share\bar`); + } +} + +@safe unittest +{ + import std.path; + + import std.array; + assert(asNormalizedPath("foo/..").array == "."); + + version (Posix) + { + assert(asNormalizedPath("/foo/./bar/..//baz/").array == "/foo/baz"); + assert(asNormalizedPath("../foo/.").array == "../foo"); + assert(asNormalizedPath("/foo/bar/baz/").array == "/foo/bar/baz"); + assert(asNormalizedPath("/foo/./bar/../../baz").array == "/baz"); + } + + version (Windows) + { + assert(asNormalizedPath(`c:\foo\.\bar/..\\baz\`).array == `c:\foo\baz`); + assert(asNormalizedPath(`..\foo\.`).array == `..\foo`); + assert(asNormalizedPath(`c:\foo\bar\baz\`).array == `c:\foo\bar\baz`); + assert(asNormalizedPath(`c:\foo\bar/..`).array == `c:\foo`); + assert(asNormalizedPath(`\\server\share\foo\..\bar`).array == + `\\server\share\bar`); + } +} + +@safe unittest +{ + import std.path; + + import std.algorithm.comparison : equal; + import std.conv : to; + + assert(equal(pathSplitter("/"), ["/"])); + assert(equal(pathSplitter("/foo/bar"), ["/", "foo", "bar"])); + assert(equal(pathSplitter("foo/../bar//./"), ["foo", "..", "bar", "."])); + + version (Posix) + { + assert(equal(pathSplitter("//foo/bar"), ["/", "foo", "bar"])); + } + + version (Windows) + { + assert(equal(pathSplitter(`foo\..\bar\/.\`), ["foo", "..", "bar", "."])); + assert(equal(pathSplitter("c:"), ["c:"])); + assert(equal(pathSplitter(`c:\foo\bar`), [`c:\`, "foo", "bar"])); + assert(equal(pathSplitter(`c:foo\bar`), ["c:foo", "bar"])); + } +} + +@safe unittest +{ + import std.path; + + version (Posix) + { + assert( isRooted("/")); + assert( isRooted("/foo")); + assert(!isRooted("foo")); + assert(!isRooted("../foo")); + } + + version (Windows) + { + assert( isRooted(`\`)); + assert( isRooted(`\foo`)); + assert( isRooted(`d:\foo`)); + assert( isRooted(`\\foo\bar`)); + assert(!isRooted("foo")); + assert(!isRooted("d:foo")); + } +} + +@safe unittest +{ + import std.path; + + version (Posix) + { + assert(absolutePath("some/file", "/foo/bar") == "/foo/bar/some/file"); + assert(absolutePath("../file", "/foo/bar") == "/foo/bar/../file"); + assert(absolutePath("/some/file", "/foo/bar") == "/some/file"); + } + + version (Windows) + { + assert(absolutePath(`some\file`, `c:\foo\bar`) == `c:\foo\bar\some\file`); + assert(absolutePath(`..\file`, `c:\foo\bar`) == `c:\foo\bar\..\file`); + assert(absolutePath(`c:\some\file`, `c:\foo\bar`) == `c:\some\file`); + assert(absolutePath(`\`, `c:\`) == `c:\`); + assert(absolutePath(`\some\file`, `c:\foo\bar`) == `c:\some\file`); + } +} + +@system unittest +{ + import std.path; + + import std.array; + assert(asAbsolutePath(cast(string) null).array == ""); + version (Posix) + { + assert(asAbsolutePath("/foo").array == "/foo"); + } + version (Windows) + { + assert(asAbsolutePath("c:/foo").array == "c:/foo"); + } + asAbsolutePath("foo"); +} + +@safe unittest +{ + import std.path; + + assert(relativePath("foo") == "foo"); + + version (Posix) + { + assert(relativePath("foo", "/bar") == "foo"); + assert(relativePath("/foo/bar", "/foo/bar") == "."); + assert(relativePath("/foo/bar", "/foo/baz") == "../bar"); + assert(relativePath("/foo/bar/baz", "/foo/woo/wee") == "../../bar/baz"); + assert(relativePath("/foo/bar/baz", "/foo/bar") == "baz"); + } + version (Windows) + { + assert(relativePath("foo", `c:\bar`) == "foo"); + assert(relativePath(`c:\foo\bar`, `c:\foo\bar`) == "."); + assert(relativePath(`c:\foo\bar`, `c:\foo\baz`) == `..\bar`); + assert(relativePath(`c:\foo\bar\baz`, `c:\foo\woo\wee`) == `..\..\bar\baz`); + assert(relativePath(`c:\foo\bar\baz`, `c:\foo\bar`) == "baz"); + assert(relativePath(`c:\foo\bar`, `d:\foo`) == `c:\foo\bar`); + } +} + +@safe unittest +{ + import std.path; + + import std.array; + version (Posix) + { + assert(asRelativePath("foo", "/bar").array == "foo"); + assert(asRelativePath("/foo/bar", "/foo/bar").array == "."); + assert(asRelativePath("/foo/bar", "/foo/baz").array == "../bar"); + assert(asRelativePath("/foo/bar/baz", "/foo/woo/wee").array == "../../bar/baz"); + assert(asRelativePath("/foo/bar/baz", "/foo/bar").array == "baz"); + } + else version (Windows) + { + assert(asRelativePath("foo", `c:\bar`).array == "foo"); + assert(asRelativePath(`c:\foo\bar`, `c:\foo\bar`).array == "."); + assert(asRelativePath(`c:\foo\bar`, `c:\foo\baz`).array == `..\bar`); + assert(asRelativePath(`c:\foo\bar\baz`, `c:\foo\woo\wee`).array == `..\..\bar\baz`); + assert(asRelativePath(`c:/foo/bar/baz`, `c:\foo\woo\wee`).array == `..\..\bar\baz`); + assert(asRelativePath(`c:\foo\bar\baz`, `c:\foo\bar`).array == "baz"); + assert(asRelativePath(`c:\foo\bar`, `d:\foo`).array == `c:\foo\bar`); + assert(asRelativePath(`\\foo\bar`, `c:\foo`).array == `\\foo\bar`); + } + else + static assert(0); +} + +@safe unittest +{ + import std.path; + + assert(filenameCharCmp('a', 'a') == 0); + assert(filenameCharCmp('a', 'b') < 0); + assert(filenameCharCmp('b', 'a') > 0); + + version (linux) + { + // Same as calling filenameCharCmp!(CaseSensitive.yes)(a, b) + assert(filenameCharCmp('A', 'a') < 0); + assert(filenameCharCmp('a', 'A') > 0); + } + version (Windows) + { + // Same as calling filenameCharCmp!(CaseSensitive.no)(a, b) + assert(filenameCharCmp('a', 'A') == 0); + assert(filenameCharCmp('a', 'B') < 0); + assert(filenameCharCmp('A', 'b') < 0); + } +} + +@safe unittest +{ + import std.path; + + assert(filenameCmp("abc", "abc") == 0); + assert(filenameCmp("abc", "abd") < 0); + assert(filenameCmp("abc", "abb") > 0); + assert(filenameCmp("abc", "abcd") < 0); + assert(filenameCmp("abcd", "abc") > 0); + + version (linux) + { + // Same as calling filenameCmp!(CaseSensitive.yes)(filename1, filename2) + assert(filenameCmp("Abc", "abc") < 0); + assert(filenameCmp("abc", "Abc") > 0); + } + version (Windows) + { + // Same as calling filenameCmp!(CaseSensitive.no)(filename1, filename2) + assert(filenameCmp("Abc", "abc") == 0); + assert(filenameCmp("abc", "Abc") == 0); + assert(filenameCmp("Abc", "abD") < 0); + assert(filenameCmp("abc", "AbB") > 0); + } +} + +@safe @nogc unittest +{ + import std.path; + + assert(globMatch("foo.bar", "*")); + assert(globMatch("foo.bar", "*.*")); + assert(globMatch(`foo/foo\bar`, "f*b*r")); + assert(globMatch("foo.bar", "f???bar")); + assert(globMatch("foo.bar", "[fg]???bar")); + assert(globMatch("foo.bar", "[!gh]*bar")); + assert(globMatch("bar.fooz", "bar.{foo,bif}z")); + assert(globMatch("bar.bifz", "bar.{foo,bif}z")); + + version (Windows) + { + // Same as calling globMatch!(CaseSensitive.no)(path, pattern) + assert(globMatch("foo", "Foo")); + assert(globMatch("Goo.bar", "[fg]???bar")); + } + version (linux) + { + // Same as calling globMatch!(CaseSensitive.yes)(path, pattern) + assert(!globMatch("foo", "Foo")); + assert(!globMatch("Goo.bar", "[fg]???bar")); + } +} + +@safe pure @nogc nothrow unittest +{ + import std.path; + + import std.utf : byCodeUnit; + + assert(isValidFilename("hello.exe".byCodeUnit)); +} + +@safe pure @nogc nothrow unittest +{ + import std.path; + + assert(isValidPath("/foo/bar")); + assert(!isValidPath("/foo\0/bar")); + assert(isValidPath("/")); + assert(isValidPath("a")); + + version (Windows) + { + assert(isValidPath(`c:\`)); + assert(isValidPath(`c:\foo`)); + assert(isValidPath(`c:\foo\.\bar\\\..\`)); + assert(!isValidPath(`!:\foo`)); + assert(!isValidPath(`c::\foo`)); + assert(!isValidPath(`c:\foo?`)); + assert(!isValidPath(`c:\foo.`)); + + assert(isValidPath(`\\server\share`)); + assert(isValidPath(`\\server\share\foo`)); + assert(isValidPath(`\\server\share\\foo`)); + assert(!isValidPath(`\\\server\share\foo`)); + assert(!isValidPath(`\\server\\share\foo`)); + assert(!isValidPath(`\\ser*er\share\foo`)); + assert(!isValidPath(`\\server\sha?e\foo`)); + assert(!isValidPath(`\\server\share\|oo`)); + + assert(isValidPath(`\\?\<>:"?*|/\..\.`)); + assert(!isValidPath("\\\\?\\foo\0bar")); + + assert(!isValidPath(`\\.\PhysicalDisk1`)); + assert(!isValidPath(`\\`)); + } + + import std.utf : byCodeUnit; + assert(isValidPath("/foo/bar".byCodeUnit)); +} + +@safe unittest +{ + import std.path; + + version (Posix) + { + import std.process : environment; + + auto oldHome = environment["HOME"]; + scope(exit) environment["HOME"] = oldHome; + + environment["HOME"] = "dmd/test"; + assert(expandTilde("~/") == "dmd/test/"); + assert(expandTilde("~") == "dmd/test"); + } +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_random.d b/libphobos/testsuite/libphobos.phobos/std_random.d new file mode 100644 index 000000000000..89147d312955 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_random.d @@ -0,0 +1,578 @@ +@safe unittest +{ + import std.random; + + import std.algorithm.comparison : among, equal; + import std.range : iota; + + // seed a random generator with a constant + auto rnd = Random(42); + + // Generate a uniformly-distributed integer in the range [0, 14] + // If no random generator is passed, the global `rndGen` would be used + auto i = uniform(0, 15, rnd); + assert(i >= 0 && i < 15); + + // Generate a uniformly-distributed real in the range [0, 100) + auto r = uniform(0.0L, 100.0L, rnd); + assert(r >= 0 && r < 100); + + // Sample from a custom type + enum Fruit { apple, mango, pear } + auto f = rnd.uniform!Fruit; + with(Fruit) + assert(f.among(apple, mango, pear)); + + // Generate a 32-bit random number + auto u = uniform!uint(rnd); + static assert(is(typeof(u) == uint)); + + // Generate a random number in the range in the range [0, 1) + auto u2 = uniform01(rnd); + assert(u2 >= 0 && u2 < 1); + + // Select an element randomly + auto el = 10.iota.choice(rnd); + assert(0 <= el && el < 10); + + // Throw a dice with custom proportions + // 0: 20%, 1: 10%, 2: 60% + auto val = rnd.dice(0.2, 0.1, 0.6); + assert(0 <= val && val <= 2); + + auto rnd2 = MinstdRand0(42); + + // Select a random subsample from a range + assert(10.iota.randomSample(3, rnd2).equal([7, 8, 9])); + + // Cover all elements in an array in random order + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 + assert(10.iota.randomCover(rnd2).equal([7, 4, 2, 0, 1, 6, 8, 3, 9, 5])); + else + assert(10.iota.randomCover(rnd2).equal([4, 8, 7, 3, 5, 9, 2, 6, 0, 1])); + + // Shuffle an array + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 + assert([0, 1, 2, 4, 5].randomShuffle(rnd2).equal([2, 0, 4, 5, 1])); + else + assert([0, 1, 2, 4, 5].randomShuffle(rnd2).equal([4, 2, 5, 0, 1])); +} + +@safe unittest +{ + import std.random; + + struct NoRng + { + @property uint front() {return 0;} + @property bool empty() {return false;} + void popFront() {} + } + static assert(!isUniformRNG!(NoRng)); + + struct validRng + { + @property uint front() {return 0;} + @property bool empty() {return false;} + void popFront() {} + + enum isUniformRandom = true; + } + static assert(isUniformRNG!(validRng, uint)); + static assert(isUniformRNG!(validRng)); +} + +@safe unittest +{ + import std.random; + + struct validRng + { + @property uint front() {return 0;} + @property bool empty() {return false;} + void popFront() {} + + enum isUniformRandom = true; + } + static assert(!isSeedable!(validRng, uint)); + static assert(!isSeedable!(validRng)); + + struct seedRng + { + @property uint front() {return 0;} + @property bool empty() {return false;} + void popFront() {} + void seed(uint val){} + enum isUniformRandom = true; + } + static assert(isSeedable!(seedRng, uint)); + static assert(!isSeedable!(seedRng, ulong)); + static assert(isSeedable!(seedRng)); +} + +@safe unittest +{ + import std.random; + + alias CPP11LCG = LinearCongruentialEngine!(uint, 48271, 0, 2_147_483_647); + + // seed with a constant + auto rnd = CPP11LCG(42); + auto n = rnd.front; // same for each run + assert(n == 2027382); +} + +@safe unittest +{ + import std.random; + + // glibc's LCG + alias GLibcLCG = LinearCongruentialEngine!(uint, 1103515245, 12345, 2_147_483_648); + + // Seed with an unpredictable value + auto rnd = GLibcLCG(unpredictableSeed); + auto n = rnd.front; // different across runs +} + +@safe unittest +{ + import std.random; + + // Visual C++'s LCG + alias MSVCLCG = LinearCongruentialEngine!(uint, 214013, 2531011, 0); + + // seed with a constant + auto rnd = MSVCLCG(1); + auto n = rnd.front; // same for each run + assert(n == 2745024); +} + +@safe @nogc unittest +{ + import std.random; + + // seed with a constant + auto rnd0 = MinstdRand0(1); + auto n = rnd0.front; + // same for each run + assert(n == 16807); + + // Seed with an unpredictable value + rnd0.seed(unpredictableSeed); + n = rnd0.front; // different across runs +} + +@safe unittest +{ + import std.random; + + // seed with a constant + Mt19937 gen; + auto n = gen.front; // same for each run + assert(n == 3499211612); + + // Seed with an unpredictable value + gen.seed(unpredictableSeed); + n = gen.front; // different across runs +} + +@safe @nogc unittest +{ + import std.random; + + // seed with a constant + Mt19937 gen; + auto n = gen.front; // same for each run + assert(n == 3499211612); + + // Seed with an unpredictable value + gen.seed(unpredictableSeed); + n = gen.front; // different across runs +} + +@safe @nogc unittest +{ + import std.random; + + // Seed with a constant + auto gen = Mt19937_64(12345); + auto n = gen.front; // same for each run + assert(n == 6597103971274460346); + + // Seed with an unpredictable value + gen.seed(unpredictableSeed!ulong); + n = gen.front; // different across runs +} + +@safe unittest +{ + import std.random; + + alias Xorshift96 = XorshiftEngine!(uint, 96, 10, 5, 26); + auto rnd = Xorshift96(42); + auto num = rnd.front; // same for each run + assert(num == 2704588748); +} + +@safe @nogc unittest +{ + import std.random; + + // Seed with a constant + auto rnd = Xorshift(1); + auto num = rnd.front; // same for each run + assert(num == 1405313047); + + // Seed with an unpredictable value + rnd.seed(unpredictableSeed); + num = rnd.front; // different across rnd +} + +@safe @nogc unittest +{ + import std.random; + + auto rnd = Random(unpredictableSeed); + auto n = rnd.front; + static assert(is(typeof(n) == uint)); +} + +@safe nothrow @nogc unittest +{ + import std.random; + + import std.algorithm.iteration : sum; + import std.range : take; + auto rnd = rndGen; + assert(rnd.take(3).sum > 0); +} + +@safe unittest +{ + import std.random; + + auto rnd = Random(unpredictableSeed); + + // Generate an integer in [0, 1023] + auto a = uniform(0, 1024, rnd); + assert(0 <= a && a < 1024); + + // Generate a float in [0, 1) + auto b = uniform(0.0f, 1.0f, rnd); + assert(0 <= b && b < 1); + + // Generate a float in [0, 1] + b = uniform!"[]"(0.0f, 1.0f, rnd); + assert(0 <= b && b <= 1); + + // Generate a float in (0, 1) + b = uniform!"()"(0.0f, 1.0f, rnd); + assert(0 < b && b < 1); +} + +@safe unittest +{ + import std.random; + + import std.array : array; + import std.range : generate, takeExactly; + + int[] arr = generate!(() => uniform(0, 100)).takeExactly(10).array; + assert(arr.length == 10); + assert(arr[0] >= 0 && arr[0] < 100); +} + +@safe unittest +{ + import std.random; + + import std.conv : to; + import std.meta : AliasSeq; + import std.range.primitives : isForwardRange; + import std.traits : isIntegral, isSomeChar; + + auto gen = Mt19937(123_456_789); + static assert(isForwardRange!(typeof(gen))); + + auto a = uniform(0, 1024, gen); + assert(0 <= a && a <= 1024); + auto b = uniform(0.0f, 1.0f, gen); + assert(0 <= b && b < 1, to!string(b)); + auto c = uniform(0.0, 1.0); + assert(0 <= c && c < 1); + + static foreach (T; AliasSeq!(char, wchar, dchar, byte, ubyte, short, ushort, + int, uint, long, ulong, float, double, real)) + {{ + T lo = 0, hi = 100; + + // Try tests with each of the possible bounds + { + T init = uniform(lo, hi); + size_t i = 50; + while (--i && uniform(lo, hi) == init) {} + assert(i > 0); + } + { + T init = uniform!"[)"(lo, hi); + size_t i = 50; + while (--i && uniform(lo, hi) == init) {} + assert(i > 0); + } + { + T init = uniform!"(]"(lo, hi); + size_t i = 50; + while (--i && uniform(lo, hi) == init) {} + assert(i > 0); + } + { + T init = uniform!"()"(lo, hi); + size_t i = 50; + while (--i && uniform(lo, hi) == init) {} + assert(i > 0); + } + { + T init = uniform!"[]"(lo, hi); + size_t i = 50; + while (--i && uniform(lo, hi) == init) {} + assert(i > 0); + } + + /* Test case with closed boundaries covering whole range + * of integral type + */ + static if (isIntegral!T || isSomeChar!T) + { + foreach (immutable _; 0 .. 100) + { + auto u = uniform!"[]"(T.min, T.max); + static assert(is(typeof(u) == T)); + assert(T.min <= u, "Lower bound violation for uniform!\"[]\" with " ~ T.stringof); + assert(u <= T.max, "Upper bound violation for uniform!\"[]\" with " ~ T.stringof); + } + } + }} + + auto reproRng = Xorshift(239842); + + static foreach (T; AliasSeq!(char, wchar, dchar, byte, ubyte, short, + ushort, int, uint, long, ulong)) + {{ + T lo = T.min + 10, hi = T.max - 10; + T init = uniform(lo, hi, reproRng); + size_t i = 50; + while (--i && uniform(lo, hi, reproRng) == init) {} + assert(i > 0); + }} + + { + bool sawLB = false, sawUB = false; + foreach (i; 0 .. 50) + { + auto x = uniform!"[]"('a', 'd', reproRng); + if (x == 'a') sawLB = true; + if (x == 'd') sawUB = true; + assert('a' <= x && x <= 'd'); + } + assert(sawLB && sawUB); + } + + { + bool sawLB = false, sawUB = false; + foreach (i; 0 .. 50) + { + auto x = uniform('a', 'd', reproRng); + if (x == 'a') sawLB = true; + if (x == 'c') sawUB = true; + assert('a' <= x && x < 'd'); + } + assert(sawLB && sawUB); + } + + { + bool sawLB = false, sawUB = false; + foreach (i; 0 .. 50) + { + immutable int lo = -2, hi = 2; + auto x = uniform!"()"(lo, hi, reproRng); + if (x == (lo+1)) sawLB = true; + if (x == (hi-1)) sawUB = true; + assert(lo < x && x < hi); + } + assert(sawLB && sawUB); + } + + { + bool sawLB = false, sawUB = false; + foreach (i; 0 .. 50) + { + immutable ubyte lo = 0, hi = 5; + auto x = uniform(lo, hi, reproRng); + if (x == lo) sawLB = true; + if (x == (hi-1)) sawUB = true; + assert(lo <= x && x < hi); + } + assert(sawLB && sawUB); + } + + { + foreach (i; 0 .. 30) + { + assert(i == uniform(i, i+1, reproRng)); + } + } +} + +@safe unittest +{ + import std.random; + + auto rnd = MinstdRand0(42); + + assert(rnd.uniform!ubyte == 102); + assert(rnd.uniform!ulong == 4838462006927449017); + + enum Fruit { apple, mango, pear } + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 + assert(rnd.uniform!Fruit == Fruit.mango); +} + +@safe @nogc unittest +{ + import std.random; + + import std.math.operations : feqrel; + + auto rnd = MinstdRand0(42); + + // Generate random numbers in the range in the range [0, 1) + auto u1 = uniform01(rnd); + assert(u1 >= 0 && u1 < 1); + + auto u2 = rnd.uniform01!float; + assert(u2 >= 0 && u2 < 1); + + // Confirm that the random values with the initial seed 42 are 0.000328707 and 0.524587 + assert(u1.feqrel(0.000328707) > 20); + assert(u2.feqrel(0.524587) > 20); +} + +@safe unittest +{ + import std.random; + + import std.algorithm.iteration : reduce; + import std.math.operations : isClose; + + auto a = uniformDistribution(5); + assert(a.length == 5); + assert(isClose(reduce!"a + b"(a), 1)); + + a = uniformDistribution(10, a); + assert(a.length == 10); + assert(isClose(reduce!"a + b"(a), 1)); +} + +@safe unittest +{ + import std.random; + + auto rnd = MinstdRand0(42); + + auto elem = [1, 2, 3, 4, 5].choice(rnd); + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 + assert(elem == 3); +} + +@safe unittest +{ + import std.random; + + auto rnd = MinstdRand0(42); + + auto arr = [1, 2, 3, 4, 5].randomShuffle(rnd); + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 + assert(arr == [3, 5, 2, 4, 1]); +} + +@safe unittest +{ + import std.random; + + auto rnd = MinstdRand0(42); + + auto arr = [1, 2, 3, 4, 5, 6]; + arr = arr.dup.partialShuffle(1, rnd); + + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 + assert(arr == [2, 1, 3, 4, 5, 6]); // 1<->2 + + arr = arr.dup.partialShuffle(2, rnd); + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 + assert(arr == [1, 4, 3, 2, 5, 6]); // 1<->2, 2<->4 + + arr = arr.dup.partialShuffle(3, rnd); + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 + assert(arr == [5, 4, 6, 2, 1, 3]); // 1<->5, 2<->4, 3<->6 +} + +@safe unittest +{ + import std.random; + + auto d6 = 1 + dice(1, 1, 1, 1, 1, 1); // fair dice roll + auto d6b = 1 + dice(2, 1, 1, 1, 1, 1); // double the chance to roll '1' + + auto x = dice(0.5, 0.5); // x is 0 or 1 in equal proportions + auto y = dice(50, 50); // y is 0 or 1 in equal proportions + auto z = dice(70, 20, 10); // z is 0 70% of the time, 1 20% of the time, + // and 2 10% of the time +} + +@safe unittest +{ + import std.random; + + auto rnd = MinstdRand0(42); + auto z = rnd.dice(70, 20, 10); + assert(z == 0); + z = rnd.dice(30, 20, 40, 10); + assert(z == 2); +} + +@safe unittest +{ + import std.random; + + auto rnd = Xorshift(123_456_789); + auto i = dice(rnd, 0.0, 100.0); + assert(i == 1); + i = dice(rnd, 100.0, 0.0); + assert(i == 0); + + i = dice(100U, 0U); + assert(i == 0); +} + +@safe unittest +{ + import std.random; + + import std.algorithm.comparison : equal; + import std.range : iota; + auto rnd = MinstdRand0(42); + + version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147 + assert(10.iota.randomCover(rnd).equal([7, 4, 2, 0, 1, 6, 8, 3, 9, 5])); +} + +@safe unittest +{ + import std.random; + + import std.algorithm.comparison : equal; + import std.range : iota; + auto rnd = MinstdRand0(42); + assert(10.iota.randomSample(3, rnd).equal([7, 8, 9])); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_range_interfaces.d b/libphobos/testsuite/libphobos.phobos/std_range_interfaces.d new file mode 100644 index 000000000000..8d91401930c2 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_range_interfaces.d @@ -0,0 +1,32 @@ +@safe unittest +{ + import std.range.interfaces; + + import std.algorithm.iteration : map; + import std.range : iota; + + void useRange(InputRange!int range) { + // Function body. + } + + // Create a range type. + auto squares = map!"a * a"(iota(10)); + + // Wrap it in an interface. + auto squaresWrapped = inputRangeObject(squares); + + // Use it. + useRange(squaresWrapped); +} + +@safe unittest +{ + import std.range.interfaces; + + import std.array; + auto app = appender!(uint[])(); + auto appWrapped = outputRangeObject!(uint, uint[])(app); + static assert(is(typeof(appWrapped) : OutputRange!(uint[]))); + static assert(is(typeof(appWrapped) : OutputRange!(uint))); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_range_package.d b/libphobos/testsuite/libphobos.phobos/std_range_package.d new file mode 100644 index 000000000000..03378ce3d668 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_range_package.d @@ -0,0 +1,1346 @@ +pure @safe nothrow @nogc unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + int[5] a = [ 1, 2, 3, 4, 5 ]; + int[5] b = [ 5, 4, 3, 2, 1 ]; + assert(equal(retro(a[]), b[])); + assert(retro(a[]).source is a[]); + assert(retro(retro(a[])) is a[]); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + int[] a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ]; + assert(equal(stride(a, 3), [ 1, 4, 7, 10 ][])); + assert(stride(stride(a, 2), 3) == stride(a, 6)); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + int[] arr1 = [ 1, 2, 3, 4 ]; + int[] arr2 = [ 5, 6 ]; + int[] arr3 = [ 7 ]; + auto s = chain(arr1, arr2, arr3); + assert(s.length == 7); + assert(s[5] == 6); + assert(equal(s, [1, 2, 3, 4, 5, 6, 7][])); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.algorithm.sorting : sort; + + int[] arr1 = [5, 2, 8]; + int[] arr2 = [3, 7, 9]; + int[] arr3 = [1, 4, 6]; + + // in-place sorting across all of the arrays + auto s = arr1.chain(arr2, arr3).sort; + + assert(s.equal([1, 2, 3, 4, 5, 6, 7, 8, 9])); + assert(arr1.equal([1, 2, 3])); + assert(arr2.equal([4, 5, 6])); + assert(arr3.equal([7, 8, 9])); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.utf : byChar, byCodeUnit; + + auto s1 = "string one"; + auto s2 = "string two"; + // s1 and s2 front is dchar because of auto-decoding + static assert(is(typeof(s1.front) == dchar) && is(typeof(s2.front) == dchar)); + + auto r1 = s1.chain(s2); + // chains of ranges of the same character type give that same type + static assert(is(typeof(r1.front) == dchar)); + + auto s3 = "string three".byCodeUnit; + static assert(is(typeof(s3.front) == immutable char)); + auto r2 = s1.chain(s3); + // chaining ranges of mixed character types gives `dchar` + static assert(is(typeof(r2.front) == dchar)); + + // use byChar on character ranges to correctly convert them to UTF-8 + auto r3 = s1.byChar.chain(s3); + static assert(is(typeof(r3.front) == immutable char)); +} + +@safe nothrow pure @nogc unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : filter, map; + + auto data1 = only(1, 2, 3, 4).filter!(a => a != 3); + auto data2 = only(5, 6, 7, 8).map!(a => a + 1); + + // choose() is primarily useful when you need to select one of two ranges + // with different types at runtime. + static assert(!is(typeof(data1) == typeof(data2))); + + auto chooseRange(bool pickFirst) + { + // The returned range is a common wrapper type that can be used for + // returning or storing either range without running into a type error. + return choose(pickFirst, data1, data2); + + // Simply returning the chosen range without using choose() does not + // work, because map() and filter() return different types. + //return pickFirst ? data1 : data2; // does not compile + } + + auto result = chooseRange(true); + assert(result.equal(only(1, 2, 4))); + + result = chooseRange(false); + assert(result.equal(only(6, 7, 8, 9))); +} + +@safe nothrow pure @nogc unittest +{ + import std.range; + + auto test() + { + import std.algorithm.comparison : equal; + + int[4] sarr1 = [1, 2, 3, 4]; + int[2] sarr2 = [5, 6]; + int[1] sarr3 = [7]; + auto arr1 = sarr1[]; + auto arr2 = sarr2[]; + auto arr3 = sarr3[]; + + { + auto s = chooseAmong(0, arr1, arr2, arr3); + auto t = s.save; + assert(s.length == 4); + assert(s[2] == 3); + s.popFront(); + assert(equal(t, only(1, 2, 3, 4))); + } + { + auto s = chooseAmong(1, arr1, arr2, arr3); + assert(s.length == 2); + s.front = 8; + assert(equal(s, only(8, 6))); + } + { + auto s = chooseAmong(1, arr1, arr2, arr3); + assert(s.length == 2); + s[1] = 9; + assert(equal(s, only(8, 9))); + } + { + auto s = chooseAmong(1, arr2, arr1, arr3)[1 .. 3]; + assert(s.length == 2); + assert(equal(s, only(2, 3))); + } + { + auto s = chooseAmong(0, arr1, arr2, arr3); + assert(s.length == 4); + assert(s.back == 4); + s.popBack(); + s.back = 5; + assert(equal(s, only(1, 2, 5))); + s.back = 3; + assert(equal(s, only(1, 2, 3))); + } + { + uint[5] foo = [1, 2, 3, 4, 5]; + uint[5] bar = [6, 7, 8, 9, 10]; + auto c = chooseAmong(1, foo[], bar[]); + assert(c[3] == 9); + c[3] = 42; + assert(c[3] == 42); + assert(c.moveFront() == 6); + assert(c.moveBack() == 10); + assert(c.moveAt(4) == 10); + } + { + import std.range : cycle; + auto s = chooseAmong(0, cycle(arr2), cycle(arr3)); + assert(isInfinite!(typeof(s))); + assert(!s.empty); + assert(s[100] == 8); + assert(s[101] == 9); + assert(s[0 .. 3].equal(only(8, 9, 8))); + } + return 0; + } + // works at runtime + auto a = test(); + // and at compile time + static b = test(); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + int[] a = [ 1, 2, 3 ]; + int[] b = [ 10, 20, 30, 40 ]; + auto r = roundRobin(a, b); + assert(equal(r, [ 1, 10, 2, 20, 3, 30, 40 ])); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + auto interleave(R, E)(R range, E element) + if ((isInputRange!R && hasLength!R) || isForwardRange!R) + { + static if (hasLength!R) + immutable len = range.length; + else + immutable len = range.save.walkLength; + + return roundRobin( + range, + element.repeat(len - 1) + ); + } + + assert(interleave([1, 2, 3], 0).equal([1, 0, 2, 0, 3])); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + int[] a = [ 1, 2, 3, 4, 5 ]; + assert(equal(radial(a), [ 3, 4, 2, 5, 1 ])); + a = [ 1, 2, 3, 4 ]; + assert(equal(radial(a), [ 2, 3, 1, 4 ])); + + // If the left end is reached first, the remaining elements on the right + // are concatenated in order: + a = [ 0, 1, 2, 3, 4, 5 ]; + assert(equal(radial(a, 1), [ 1, 2, 0, 3, 4, 5 ])); + + // If the right end is reached first, the remaining elements on the left + // are concatenated in reverse order: + assert(equal(radial(a, 4), [ 4, 5, 3, 2, 1, 0 ])); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; + auto s = take(arr1, 5); + assert(s.length == 5); + assert(s[4] == 5); + assert(equal(s, [ 1, 2, 3, 4, 5 ][])); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + int[] arr2 = [ 1, 2, 3 ]; + auto t = take(arr2, 5); + assert(t.length == 3); + assert(equal(t, [ 1, 2, 3 ])); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + auto a = [ 1, 2, 3, 4, 5 ]; + + auto b = takeExactly(a, 3); + assert(equal(b, [1, 2, 3])); + static assert(is(typeof(b.length) == size_t)); + assert(b.length == 3); + assert(b.front == 1); + assert(b.back == 3); +} + +pure @safe nothrow unittest +{ + import std.range; + + auto s = takeOne([42, 43, 44]); + static assert(isRandomAccessRange!(typeof(s))); + assert(s.length == 1); + assert(!s.empty); + assert(s.front == 42); + s.front = 43; + assert(s.front == 43); + assert(s.back == 43); + assert(s[0] == 43); + s.popFront(); + assert(s.length == 0); + assert(s.empty); +} + +pure @safe nothrow @nogc unittest +{ + import std.range; + + auto range = takeNone!(int[])(); + assert(range.length == 0); + assert(range.empty); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.iteration : filter; + assert(takeNone([42, 27, 19]).empty); + assert(takeNone("dlang.org").empty); + assert(takeNone(filter!"true"([42, 27, 19])).empty); +} + +pure @safe nothrow unittest +{ + import std.range; + + // tail -c n + assert([1, 2, 3].tail(1) == [3]); + assert([1, 2, 3].tail(2) == [2, 3]); + assert([1, 2, 3].tail(3) == [1, 2, 3]); + assert([1, 2, 3].tail(4) == [1, 2, 3]); + assert([1, 2, 3].tail(0).length == 0); + + // tail --lines=n + import std.algorithm.comparison : equal; + import std.algorithm.iteration : joiner; + import std.exception : assumeWontThrow; + import std.string : lineSplitter; + assert("one\ntwo\nthree" + .lineSplitter + .tail(2) + .joiner("\n") + .equal("two\nthree") + .assumeWontThrow); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + assert([0, 2, 1, 5, 0, 3].drop(3) == [5, 0, 3]); + assert("hello world".drop(6) == "world"); + assert("hello world".drop(50).empty); + assert("hello world".take(6).drop(3).equal("lo ")); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + assert([0, 2, 1, 5, 0, 3].dropBack(3) == [0, 2, 1]); + assert("hello world".dropBack(6) == "hello"); + assert("hello world".dropBack(50).empty); + assert("hello world".drop(4).dropBack(4).equal("o w")); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : filterBidirectional; + + auto a = [1, 2, 3]; + assert(a.dropExactly(2) == [3]); + assert(a.dropBackExactly(2) == [1]); + + string s = "日本語"; + assert(s.dropExactly(2) == "語"); + assert(s.dropBackExactly(2) == "æ—¥"); + + auto bd = filterBidirectional!"true"([1, 2, 3]); + assert(bd.dropExactly(2).equal([3])); + assert(bd.dropBackExactly(2).equal([1])); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : filterBidirectional; + import std.container.dlist : DList; + + auto dl = DList!int(9, 1, 2, 3, 9); + assert(dl[].dropOne().dropBackOne().equal([1, 2, 3])); + + auto a = [1, 2, 3]; + assert(a.dropOne() == [2, 3]); + assert(a.dropBackOne() == [1, 2]); + + string s = "日本語"; + import std.exception : assumeWontThrow; + assert(assumeWontThrow(s.dropOne() == "本語")); + assert(assumeWontThrow(s.dropBackOne() == "日本")); + + auto bd = filterBidirectional!"true"([1, 2, 3]); + assert(bd.dropOne().equal([2, 3])); + assert(bd.dropBackOne().equal([1, 2])); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + assert(5.repeat().take(4).equal([5, 5, 5, 5])); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + assert(5.repeat(4).equal([5, 5, 5, 5])); +} + +@safe pure nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : map; + + int i = 1; + auto powersOfTwo = generate!(() => i *= 2)().take(10); + assert(equal(powersOfTwo, iota(1, 11).map!"2^^a"())); +} + +@safe pure nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + //Returns a run-time delegate + auto infiniteIota(T)(T low, T high) + { + T i = high; + return (){if (i == high) i = low; return i++;}; + } + //adapted as a range. + assert(equal(generate(infiniteIota(1, 4)).take(10), [1, 2, 3, 1, 2, 3, 1, 2, 3, 1])); +} + +@safe unittest +{ + import std.range; + + import std.format : format; + import std.random : uniform; + + auto r = generate!(() => uniform(0, 6)).take(10); + format("%(%s %)", r); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.range : cycle, take; + + // Here we create an infinitive cyclic sequence from [1, 2] + // (i.e. get here [1, 2, 1, 2, 1, 2 and so on]) then + // take 5 elements of this sequence (so we have [1, 2, 1, 2, 1]) + // and compare them with the expected values for equality. + assert(cycle([1, 2]).take(5).equal([ 1, 2, 1, 2, 1 ])); +} + +@nogc nothrow pure @safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : map; + + // pairwise sum + auto arr = only(0, 1, 2); + auto part1 = zip(arr, arr.dropOne).map!"a[0] + a[1]"; + assert(part1.equal(only(1, 3))); +} + +nothrow pure @safe unittest +{ + import std.range; + + import std.conv : to; + + int[] a = [ 1, 2, 3 ]; + string[] b = [ "a", "b", "c" ]; + string[] result; + + foreach (tup; zip(a, b)) + { + result ~= tup[0].to!string ~ tup[1]; + } + + assert(result == [ "1a", "2b", "3c" ]); + + size_t idx = 0; + // unpacking tuple elements with foreach + foreach (e1, e2; zip(a, b)) + { + assert(e1 == a[idx]); + assert(e2 == b[idx]); + ++idx; + } +} + +nothrow pure @safe unittest +{ + import std.range; + + import std.algorithm.sorting : sort; + + int[] a = [ 1, 2, 3 ]; + string[] b = [ "a", "c", "b" ]; + zip(a, b).sort!((t1, t2) => t1[0] > t2[0]); + + assert(a == [ 3, 2, 1 ]); + // b is sorted according to a's sorting + assert(b == [ "b", "c", "a" ]); +} + +pure @safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.exception : assertThrown; + import std.range.primitives; + import std.typecons : tuple; + + auto a = [1, 2, 3]; + auto b = [4, 5, 6, 7]; + + auto shortest = zip(StoppingPolicy.shortest, a, b); + assert(shortest.equal([ + tuple(1, 4), + tuple(2, 5), + tuple(3, 6) + ])); + + auto longest = zip(StoppingPolicy.longest, a, b); + assert(longest.equal([ + tuple(1, 4), + tuple(2, 5), + tuple(3, 6), + tuple(0, 7) + ])); + + auto same = zip(StoppingPolicy.requireSameLength, a, b); + same.popFrontN(3); + assertThrown!Exception(same.popFront); +} + +pure @safe unittest +{ + import std.range; + + int[6] arr1 = [1,2,3,4,5,100]; + int[5] arr2 = [6,7,8,9,10]; + + foreach (ref a, b; lockstep(arr1[], arr2[])) + { + a += b; + } + + assert(arr1 == [7,9,11,13,15,100]); +} + +pure @safe unittest +{ + import std.range; + + int[3] arr1 = [1,2,3]; + int[3] arr2 = [4,5,6]; + + foreach (index, a, b; lockstep(arr1[], arr2[])) + { + assert(arr1[index] == a); + assert(arr2[index] == b); + } +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + // The Fibonacci numbers, using function in string form: + // a[0] = 1, a[1] = 1, and compute a[n+1] = a[n-1] + a[n] + auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1); + assert(fib.take(10).equal([1, 1, 2, 3, 5, 8, 13, 21, 34, 55])); + + // The factorials, using function in lambda form: + auto fac = recurrence!((a,n) => a[n-1] * n)(1); + assert(take(fac, 10).equal([ + 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 + ])); + + // The triangular numbers, using function in explicit form: + static size_t genTriangular(R)(R state, size_t n) + { + return state[n-1] + n; + } + auto tri = recurrence!genTriangular(0); + assert(take(tri, 10).equal([0, 1, 3, 6, 10, 15, 21, 28, 36, 45])); +} + +pure @safe nothrow @nogc unittest +{ + import std.range; + + auto odds = sequence!("a[0] + n * a[1]")(1, 2); + assert(odds.front == 1); + odds.popFront(); + assert(odds.front == 3); + odds.popFront(); + assert(odds.front == 5); +} + +pure @safe nothrow @nogc unittest +{ + import std.range; + + auto tri = sequence!((a,n) => n*(n+1)/2)(); + + // Note random access + assert(tri[0] == 0); + assert(tri[3] == 6); + assert(tri[1] == 1); + assert(tri[4] == 10); + assert(tri[2] == 3); +} + +@safe nothrow @nogc unittest +{ + import std.range; + + import std.math.exponential : pow; + import std.math.rounding : round; + import std.math.algebraic : sqrt; + static ulong computeFib(S)(S state, size_t n) + { + // Binet's formula + return cast(ulong)(round((pow(state[0], n+1) - pow(state[1], n+1)) / + state[2])); + } + auto fib = sequence!computeFib( + (1.0 + sqrt(5.0)) / 2.0, // Golden Ratio + (1.0 - sqrt(5.0)) / 2.0, // Conjugate of Golden Ratio + sqrt(5.0)); + + // Note random access with [] operator + assert(fib[1] == 1); + assert(fib[4] == 5); + assert(fib[3] == 3); + assert(fib[2] == 2); + assert(fib[9] == 55); +} + +pure @safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.math.operations : isClose; + + auto r = iota(0, 10, 1); + assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); + assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); + assert(3 in r); + assert(r.contains(3)); //Same as above + assert(!(10 in r)); + assert(!(-8 in r)); + r = iota(0, 11, 3); + assert(equal(r, [0, 3, 6, 9])); + assert(r[2] == 6); + assert(!(2 in r)); + auto rf = iota(0.0, 0.5, 0.1); + assert(isClose(rf, [0.0, 0.1, 0.2, 0.3, 0.4])); +} + +@safe pure unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.exception : assertThrown; + + auto arr = [[1, 2], [3, 4, 5]]; + + auto r1 = arr.frontTransversal!(TransverseOptions.assumeJagged); + assert(r1.equal([1, 3])); + + // throws on construction + assertThrown!Exception(arr.frontTransversal!(TransverseOptions.enforceNotJagged)); + + auto r2 = arr.frontTransversal!(TransverseOptions.assumeNotJagged); + assert(r2.equal([1, 3])); + + // either assuming or checking for equal lengths makes + // the result a random access range + assert(r2[0] == 1); + static assert(!__traits(compiles, r1[0])); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + int[][] x = new int[][2]; + x[0] = [1, 2]; + x[1] = [3, 4]; + auto ror = frontTransversal(x); + assert(equal(ror, [ 1, 3 ][])); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + int[][] x = new int[][2]; + x[0] = [1, 2]; + x[1] = [3, 4]; + auto ror = transversal(x, 1); + assert(equal(ror, [ 2, 4 ])); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : map; + int[][] y = [[1, 2, 3], [4, 5, 6]]; + auto z = y.front.walkLength.iota.map!(i => transversal(y, i)); + assert(equal!equal(z, [[1, 4], [2, 5], [3, 6]])); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + int[][] ror = [ + [1, 2, 3], + [4, 5, 6] + ]; + auto xp = transposed(ror); + assert(equal!"a.equal(b)"(xp, [ + [1, 4], + [2, 5], + [3, 6] + ])); +} + +@safe unittest +{ + import std.range; + + int[][] x = new int[][2]; + x[0] = [1, 2]; + x[1] = [3, 4]; + auto tr = transposed(x); + int[][] witness = [ [ 1, 3 ], [ 2, 4 ] ]; + uint i; + + foreach (e; tr) + { + assert(array(e) == witness[i++]); + } +} + +@safe unittest +{ + import std.range; + + auto ind = indexed([1, 2, 3, 4, 5], [1, 3, 4]); + assert(ind.physicalIndex(0) == 1); + +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + auto source = [1, 2, 3, 4, 5]; + auto indices = [4, 3, 1, 2, 0, 4]; + auto ind = indexed(source, indices); + assert(equal(ind, [5, 4, 2, 3, 1, 5])); + assert(equal(retro(ind), [5, 1, 3, 2, 4, 5])); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + auto chunks = chunks(source, 4); + assert(chunks[0] == [1, 2, 3, 4]); + assert(chunks[1] == [5, 6, 7, 8]); + assert(chunks[2] == [9, 10]); + assert(chunks.back == chunks[2]); + assert(chunks.front == chunks[0]); + assert(chunks.length == 3); + assert(equal(retro(array(chunks)), array(retro(chunks)))); +} + +@system unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + int i; + + // The generator doesn't save state, so it cannot be a forward range. + auto inputRange = generate!(() => ++i).take(10); + + // We can still process it in chunks, but it will be single-pass only. + auto chunked = inputRange.chunks(2); + + assert(chunked.front.equal([1, 2])); + assert(chunked.front.empty); // Iterating the chunk has consumed it + chunked.popFront; + assert(chunked.front.equal([3, 4])); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + auto source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + auto chunks = evenChunks(source, 3); + assert(chunks[0] == [1, 2, 3, 4]); + assert(chunks[1] == [5, 6, 7]); + assert(chunks[2] == [8, 9, 10]); +} + +@safe pure nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + assert([0, 1, 2, 3].slide(2).equal!equal( + [[0, 1], [1, 2], [2, 3]] + )); + + assert(5.iota.slide(3).equal!equal( + [[0, 1, 2], [1, 2, 3], [2, 3, 4]] + )); +} + +@safe pure nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + assert(6.iota.slide(1, 2).equal!equal( + [[0], [2], [4]] + )); + + assert(6.iota.slide(2, 4).equal!equal( + [[0, 1], [4, 5]] + )); + + assert(iota(7).slide(2, 2).equal!equal( + [[0, 1], [2, 3], [4, 5], [6]] + )); + + assert(iota(12).slide(2, 4).equal!equal( + [[0, 1], [4, 5], [8, 9]] + )); +} + +@safe pure nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + assert(3.iota.slide!(No.withPartial)(4).empty); + assert(3.iota.slide!(Yes.withPartial)(4).equal!equal( + [[0, 1, 2]] + )); +} + +@safe pure nothrow unittest +{ + import std.range; + + import std.algorithm.iteration : each; + + int[dstring] d; + "AGAGA"d.slide!(Yes.withPartial)(2).each!(a => d[a]++); + assert(d == ["AG"d: 2, "GA"d: 2]); +} + +@safe pure nothrow unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + assert(5.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4]])); + assert(6.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5]])); + assert(7.iota.slide!(Yes.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]])); + + assert(5.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]])); + assert(6.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2]])); + assert(7.iota.slide!(No.withPartial)(3, 4).equal!equal([[0, 1, 2], [4, 5, 6]])); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : filter, joiner, map; + import std.algorithm.searching : findSplitBefore; + import std.uni : isUpper; + + assert(equal(only('♡'), "♡")); + assert([1, 2, 3, 4].findSplitBefore(only(3))[0] == [1, 2]); + + assert(only("one", "two", "three").joiner(" ").equal("one two three")); + + string title = "The D Programming Language"; + assert(title + .filter!isUpper // take the upper case letters + .map!only // make each letter its own range + .joiner(".") // join the ranges together lazily + .equal("T.D.P.L")); +} + +pure @safe nothrow unittest +{ + import std.range; + + import std.array : assocArray; + import std.range : enumerate; + + bool[int] aa = true.repeat(3).enumerate(-1).assocArray(); + assert(aa[-1]); + assert(aa[0]); + assert(aa[1]); +} + +@safe unittest +{ + import std.range; + + void func1(int a, int b); + void func2(int a, float b); + + static assert(isTwoWayCompatible!(func1, int, int)); + static assert(isTwoWayCompatible!(func1, short, int)); + static assert(!isTwoWayCompatible!(func2, int, float)); + + void func3(ref int a, ref int b); + static assert( isTwoWayCompatible!(func3, int, int)); + static assert(!isTwoWayCompatible!(func3, short, int)); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + auto a = assumeSorted([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + auto p1 = a.upperBound!(SearchPolicy.binarySearch)(3); + assert(p1.equal([4, 5, 6, 7, 8, 9])); + + auto p2 = a.lowerBound!(SearchPolicy.gallop)(4); + assert(p2.equal([0, 1, 2, 3])); +} + +@safe pure unittest +{ + import std.range; + + // create a SortedRange, that's checked strictly + SortedRange!(int[],"a < b", SortedRangeOptions.checkStrictly)([ 1, 3, 5, 7, 9 ]); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.sorting : sort; + int[3] data = [ 1, 2, 3 ]; + auto a = assumeSorted(data[]); + assert(a == sort!"a < b"(data[])); + int[] p = a.release(); + assert(p == [ 1, 2, 3 ]); + +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + auto a = assumeSorted([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]); + auto p = a.lowerBound(4); + assert(equal(p, [ 0, 1, 2, 3 ])); + +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + auto a = assumeSorted([ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]); + auto p = a.upperBound(3); + assert(equal(p, [4, 4, 5, 6])); + +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; + auto r = a.assumeSorted.equalRange(3); + assert(equal(r, [ 3, 3, 3 ])); + +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + auto a = [ 1, 2, 3, 3, 3, 4, 4, 5, 6 ]; + auto r = assumeSorted(a).trisect(3); + assert(equal(r[0], [ 1, 2 ])); + assert(equal(r[1], [ 3, 3, 3 ])); + assert(equal(r[2], [ 4, 4, 5, 6 ])); + +} + +@safe unittest +{ + import std.range; + + import std.algorithm.sorting : sort; + auto a = [ 1, 2, 3, 42, 52, 64 ]; + auto r = assumeSorted(a); + assert(r.contains(3)); + assert(!(32 in r)); + auto r1 = sort!"a > b"(a); + assert(3 in r1); + assert(!r1.contains(32)); + assert(r1.release() == [ 64, 52, 42, 3, 2, 1 ]); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.mutation : swap; + auto a = [ 1, 2, 3, 42, 52, 64 ]; + auto r = assumeSorted(a); + assert(r.contains(42)); + swap(a[3], a[5]); // illegal to break sortedness of original range + assert(!r.contains(42)); // passes although it shouldn't +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + static struct S { int i; } + static bool byI(A, B)(A a, B b) + { + static if (is(A == S)) + return a.i < b; + else + return a < b.i; + } + auto r = assumeSorted!byI([S(1), S(2), S(3)]); + auto lessThanTwo = r.lowerBound(2); + assert(equal(lessThanTwo, [S(1)])); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + auto p = assumeSorted(a); + + assert(equal(p.lowerBound(4), [0, 1, 2, 3])); + assert(equal(p.lowerBound(5), [0, 1, 2, 3, 4])); + assert(equal(p.lowerBound(6), [0, 1, 2, 3, 4, 5])); + assert(equal(p.lowerBound(6.9), [0, 1, 2, 3, 4, 5, 6])); +} + +@system unittest +{ + import std.range; + + import std.algorithm.searching : find; + ubyte[] buffer = [1, 9, 45, 12, 22]; + auto found1 = find(buffer, 45); + assert(found1 == [45, 12, 22]); + assert(buffer == [1, 9, 45, 12, 22]); + + auto wrapped1 = refRange(&buffer); + auto found2 = find(wrapped1, 45); + assert(*found2.ptr == [45, 12, 22]); + assert(buffer == [45, 12, 22]); + + auto found3 = find(wrapped1.save, 22); + assert(*found3.ptr == [22]); + assert(buffer == [45, 12, 22]); + + string str = "hello world"; + auto wrappedStr = refRange(&str); + assert(str.front == 'h'); + str.popFrontN(5); + assert(str == " world"); + assert(wrappedStr.front == ' '); + assert(*wrappedStr.ptr == " world"); +} + +@system unittest +{ + import std.range; + + ubyte[] buffer1 = [1, 2, 3, 4, 5]; + ubyte[] buffer2 = [6, 7, 8, 9, 10]; + auto wrapped1 = refRange(&buffer1); + auto wrapped2 = refRange(&buffer2); + assert(wrapped1.ptr is &buffer1); + assert(wrapped2.ptr is &buffer2); + assert(wrapped1.ptr !is wrapped2.ptr); + assert(buffer1 != buffer2); + + wrapped1 = wrapped2; + + //Everything points to the same stuff as before. + assert(wrapped1.ptr is &buffer1); + assert(wrapped2.ptr is &buffer2); + assert(wrapped1.ptr !is wrapped2.ptr); + + //But buffer1 has changed due to the assignment. + assert(buffer1 == [6, 7, 8, 9, 10]); + assert(buffer2 == [6, 7, 8, 9, 10]); + + buffer2 = [11, 12, 13, 14, 15]; + + //Everything points to the same stuff as before. + assert(wrapped1.ptr is &buffer1); + assert(wrapped2.ptr is &buffer2); + assert(wrapped1.ptr !is wrapped2.ptr); + + //But buffer2 has changed due to the assignment. + assert(buffer1 == [6, 7, 8, 9, 10]); + assert(buffer2 == [11, 12, 13, 14, 15]); + + wrapped2 = null; + + //The pointer changed for wrapped2 but not wrapped1. + assert(wrapped1.ptr is &buffer1); + assert(wrapped2.ptr is null); + assert(wrapped1.ptr !is wrapped2.ptr); + + //buffer2 is not affected by the assignment. + assert(buffer1 == [6, 7, 8, 9, 10]); + assert(buffer2 == [11, 12, 13, 14, 15]); +} + +@safe pure unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.format : format; + + // 00000011 00001001 + ubyte[] arr = [3, 9]; + auto r = arr.bitwise; + + // iterate through it as with any other range + assert(format("%(%d%)", r) == "1100000010010000"); + assert(format("%(%d%)", r.retro).equal("1100000010010000".retro)); + + auto r2 = r[5 .. $]; + // set a bit + r[2] = 1; + assert(arr[0] == 7); + assert(r[5] == r2[0]); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.random : rndGen; + + auto rb = rndGen.bitwise; + static assert(isInfinite!(typeof(rb))); + + auto rb2 = rndGen.bitwise; + // Don't forget that structs are passed by value + assert(rb.take(10).equal(rb2.take(10))); +} + +@safe nothrow unittest +{ + import std.range; + + import std.algorithm.iteration : map; + import std.algorithm.mutation : copy; + [4, 5, 6].map!(x => x * 2).copy(nullSink); // data is discarded +} + +@safe unittest +{ + import std.range; + + import std.csv : csvNextToken; + + string line = "a,b,c"; + + // ignore the first column + line.csvNextToken(nullSink, ',', '"'); + line.popFront; + + // look at the second column + Appender!string app; + line.csvNextToken(app, ',', '"'); + assert(app.data == "b"); +} + +@safe unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : filter, map; + + // Sum values while copying + int[] values = [1, 4, 9, 16, 25]; + int sum = 0; + auto newValues = values.tee!(a => sum += a).array; + assert(equal(newValues, values)); + assert(sum == 1 + 4 + 9 + 16 + 25); + + // Count values that pass the first filter + int count = 0; + auto newValues4 = values.filter!(a => a < 10) + .tee!(a => count++) + .map!(a => a + 1) + .filter!(a => a < 10); + + //Fine, equal also evaluates any lazy ranges passed to it. + //count is not 3 until equal evaluates newValues4 + assert(equal(newValues4, [2, 5])); + assert(count == 3); +} + +@safe pure unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + assert([1, 2, 3, 4].padLeft(0, 6).equal([0, 0, 1, 2, 3, 4])); + assert([1, 2, 3, 4].padLeft(0, 3).equal([1, 2, 3, 4])); + + assert("abc".padLeft('_', 6).equal("___abc")); +} + +@safe pure unittest +{ + import std.range; + + import std.algorithm.comparison : equal; + + assert([1, 2, 3, 4].padRight(0, 6).equal([1, 2, 3, 4, 0, 0])); + assert([1, 2, 3, 4].padRight(0, 4).equal([1, 2, 3, 4])); + + assert("abc".padRight('_', 6).equal("abc___")); +} + +@safe unittest +{ + import std.range; + + import std.path : chainPath; + import std.range : chain; + + void someLibraryMethod(R)(R argument) + if (isSomeFiniteCharInputRange!R) + { + // implementation detail, would iterate over each character of argument + } + + someLibraryMethod("simple strings work"); + someLibraryMethod(chain("chained", " ", "strings", " ", "work")); + someLibraryMethod(chainPath("chained", "paths", "work")); + // you can also use custom structs implementing a char range +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_range_primitives.d b/libphobos/testsuite/libphobos.phobos/std_range_primitives.d new file mode 100644 index 000000000000..eb4bc267c8b4 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_range_primitives.d @@ -0,0 +1,591 @@ +@safe unittest +{ + import std.range.primitives; + + struct A {} + struct B + { + void popFront(); + @property bool empty(); + @property int front(); + } + static assert(!isInputRange!A); + static assert( isInputRange!B); + static assert( isInputRange!(int[])); + static assert( isInputRange!(char[])); + static assert(!isInputRange!(char[4])); + static assert( isInputRange!(inout(int)[])); + static assert(!isInputRange!(int[], string)); + static assert( isInputRange!(int[], int)); + static assert( isInputRange!(int[], const int)); + static assert(!isInputRange!(int[], immutable int)); + + static assert(!isInputRange!(const(int)[], int)); + static assert( isInputRange!(const(int)[], const int)); + static assert(!isInputRange!(const(int)[], immutable int)); + + static assert(!isInputRange!(immutable(int)[], int)); + static assert( isInputRange!(immutable(int)[], const int)); + static assert( isInputRange!(immutable(int)[], immutable int)); + + static struct NotDefaultConstructible + { + @disable this(); + void popFront(); + @property bool empty(); + @property int front(); + } + static assert( isInputRange!NotDefaultConstructible); + + static struct NotDefaultConstructibleOrCopyable + { + @disable this(); + @disable this(this); + void popFront(); + @property bool empty(); + @property int front(); + } + static assert(isInputRange!NotDefaultConstructibleOrCopyable); + + static struct Frontless + { + void popFront(); + @property bool empty(); + } + static assert(!isInputRange!Frontless); + + static struct VoidFront + { + void popFront(); + @property bool empty(); + void front(); + } + static assert(!isInputRange!VoidFront); +} + +@safe pure unittest +{ + import std.range.primitives; + + import std.traits : isSomeChar; + + static struct A + { + string data; + + void put(C)(C c) + if (isSomeChar!C) + { + data ~= c; + } + } + static assert(isOutputRange!(A, char)); + + auto a = A(); + put(a, "Hello"); + assert(a.data == "Hello"); +} + +@safe pure nothrow unittest +{ + import std.range.primitives; + + int[] a = [1, 2, 3], b = [10, 20]; + auto c = a; + put(a, b); + assert(c == [10, 20, 3]); + // at this point, a was advanced twice, so it only contains + // its last element while c represents the whole array + assert(a == [3]); +} + +@safe pure unittest +{ + import std.range.primitives; + + // the elements must be mutable, so using string or const(char)[] + // won't compile + char[] s1 = new char[13]; + auto r1 = s1; + put(r1, "Hello, World!"w); + assert(s1 == "Hello, World!"); +} + +@safe unittest +{ + import std.range.primitives; + + void myprint(scope const(char)[] s) { } + static assert(isOutputRange!(typeof(&myprint), char)); + + static assert( isOutputRange!(char[], char)); + static assert( isOutputRange!(dchar[], wchar)); + static assert( isOutputRange!(dchar[], dchar)); +} + +@safe unittest +{ + import std.range.primitives; + + static assert(!isForwardRange!(int)); + static assert( isForwardRange!(int[])); + static assert( isForwardRange!(inout(int)[])); + + static assert( isForwardRange!(int[], const int)); + static assert(!isForwardRange!(int[], immutable int)); + + static assert(!isForwardRange!(const(int)[], int)); + static assert( isForwardRange!(const(int)[], const int)); + static assert(!isForwardRange!(const(int)[], immutable int)); + + static assert(!isForwardRange!(immutable(int)[], int)); + static assert( isForwardRange!(immutable(int)[], const int)); + static assert( isForwardRange!(immutable(int)[], immutable int)); +} + +@safe unittest +{ + import std.range.primitives; + + alias R = int[]; + R r = [0,1]; + static assert(isForwardRange!R); // is forward range + r.popBack(); // can invoke popBack + auto t = r.back; // can get the back of the range + auto w = r.front; + static assert(is(typeof(t) == typeof(w))); // same type for front and back + + // Checking the element type + static assert( isBidirectionalRange!(int[], const int)); + static assert(!isBidirectionalRange!(int[], immutable int)); + + static assert(!isBidirectionalRange!(const(int)[], int)); + static assert( isBidirectionalRange!(const(int)[], const int)); + static assert(!isBidirectionalRange!(const(int)[], immutable int)); + + static assert(!isBidirectionalRange!(immutable(int)[], int)); + static assert( isBidirectionalRange!(immutable(int)[], const int)); + static assert( isBidirectionalRange!(immutable(int)[], immutable int)); +} + +@safe unittest +{ + import std.range.primitives; + + import std.traits : isAggregateType, isAutodecodableString; + + alias R = int[]; + + // range is finite and bidirectional or infinite and forward. + static assert(isBidirectionalRange!R || + isForwardRange!R && isInfinite!R); + + R r = [0,1]; + auto e = r[1]; // can index + auto f = r.front; + static assert(is(typeof(e) == typeof(f))); // same type for indexed and front + static assert(!(isAutodecodableString!R && !isAggregateType!R)); // narrow strings cannot be indexed as ranges + static assert(hasLength!R || isInfinite!R); // must have length or be infinite + + // $ must work as it does with arrays if opIndex works with $ + static if (is(typeof(r[$]))) + { + static assert(is(typeof(f) == typeof(r[$]))); + + // $ - 1 doesn't make sense with infinite ranges but needs to work + // with finite ones. + static if (!isInfinite!R) + static assert(is(typeof(f) == typeof(r[$ - 1]))); + } + + // Checking the element type + static assert( isRandomAccessRange!(int[], const int)); + static assert(!isRandomAccessRange!(int[], immutable int)); + + static assert(!isRandomAccessRange!(const(int)[], int)); + static assert( isRandomAccessRange!(const(int)[], const int)); + static assert(!isRandomAccessRange!(const(int)[], immutable int)); + + static assert(!isRandomAccessRange!(immutable(int)[], int)); + static assert( isRandomAccessRange!(immutable(int)[], const int)); + static assert( isRandomAccessRange!(immutable(int)[], immutable int)); +} + +@safe unittest +{ + import std.range.primitives; + + import std.algorithm.iteration : map; + import std.range : iota, repeat; + + static struct HasPostblit + { + this(this) {} + } + + auto nonMobile = map!"a"(repeat(HasPostblit.init)); + static assert(!hasMobileElements!(typeof(nonMobile))); + static assert( hasMobileElements!(int[])); + static assert( hasMobileElements!(inout(int)[])); + static assert( hasMobileElements!(typeof(iota(1000)))); + + static assert( hasMobileElements!( string)); + static assert( hasMobileElements!(dstring)); + static assert( hasMobileElements!( char[])); + static assert( hasMobileElements!(dchar[])); +} + +@safe unittest +{ + import std.range.primitives; + + import std.range : iota; + + // Standard arrays: returns the type of the elements of the array + static assert(is(ElementType!(int[]) == int)); + + // Accessing .front retrieves the decoded dchar + static assert(is(ElementType!(char[]) == dchar)); // rvalue + static assert(is(ElementType!(dchar[]) == dchar)); // lvalue + + // Ditto + static assert(is(ElementType!(string) == dchar)); + static assert(is(ElementType!(dstring) == immutable(dchar))); + + // For ranges it gets the type of .front. + auto range = iota(0, 10); + static assert(is(ElementType!(typeof(range)) == int)); +} + +@safe unittest +{ + import std.range.primitives; + + import std.range : iota; + // internally the range stores the encoded type + static assert(is(ElementEncodingType!(char[]) == char)); + + static assert(is(ElementEncodingType!(wstring) == immutable(wchar))); + + static assert(is(ElementEncodingType!(byte[]) == byte)); + + auto range = iota(0, 10); + static assert(is(ElementEncodingType!(typeof(range)) == int)); +} + +@safe unittest +{ + import std.range.primitives; + + static assert(!hasSwappableElements!(const int[])); + static assert(!hasSwappableElements!(const(int)[])); + static assert(!hasSwappableElements!(inout(int)[])); + static assert( hasSwappableElements!(int[])); + + static assert(!hasSwappableElements!( string)); + static assert(!hasSwappableElements!(dstring)); + static assert(!hasSwappableElements!( char[])); + static assert( hasSwappableElements!(dchar[])); +} + +@safe unittest +{ + import std.range.primitives; + + static assert(!hasAssignableElements!(const int[])); + static assert(!hasAssignableElements!(const(int)[])); + static assert( hasAssignableElements!(int[])); + static assert(!hasAssignableElements!(inout(int)[])); + + static assert(!hasAssignableElements!( string)); + static assert(!hasAssignableElements!(dstring)); + static assert(!hasAssignableElements!( char[])); + static assert( hasAssignableElements!(dchar[])); +} + +@safe unittest +{ + import std.range.primitives; + + import std.range : iota, chain; + + static assert( hasLvalueElements!(int[])); + static assert( hasLvalueElements!(const(int)[])); + static assert( hasLvalueElements!(inout(int)[])); + static assert( hasLvalueElements!(immutable(int)[])); + static assert(!hasLvalueElements!(typeof(iota(3)))); + + static assert(!hasLvalueElements!( string)); + static assert( hasLvalueElements!(dstring)); + static assert(!hasLvalueElements!( char[])); + static assert( hasLvalueElements!(dchar[])); + + auto c = chain([1, 2, 3], [4, 5, 6]); + static assert( hasLvalueElements!(typeof(c))); +} + +@safe unittest +{ + import std.range.primitives; + + static assert(!hasLength!(char[])); + static assert( hasLength!(int[])); + static assert( hasLength!(inout(int)[])); + + struct A { size_t length() { return 0; } } + struct B { @property size_t length() { return 0; } } + static assert( hasLength!(A)); + static assert( hasLength!(B)); +} + +@safe unittest +{ + import std.range.primitives; + + import std.range : Repeat; + static assert(!isInfinite!(int[])); + static assert( isInfinite!(Repeat!(int))); +} + +@safe unittest +{ + import std.range.primitives; + + import std.range : takeExactly; + static assert( hasSlicing!(int[])); + static assert( hasSlicing!(const(int)[])); + static assert(!hasSlicing!(const int[])); + static assert( hasSlicing!(inout(int)[])); + static assert(!hasSlicing!(inout int [])); + static assert( hasSlicing!(immutable(int)[])); + static assert(!hasSlicing!(immutable int[])); + static assert(!hasSlicing!string); + static assert( hasSlicing!dstring); + + enum rangeFuncs = "@property int front();" ~ + "void popFront();" ~ + "@property bool empty();" ~ + "@property auto save() { return this; }" ~ + "@property size_t length();"; + + struct A { mixin(rangeFuncs); int opSlice(size_t, size_t); } + struct B { mixin(rangeFuncs); B opSlice(size_t, size_t); } + struct C { mixin(rangeFuncs); @disable this(); C opSlice(size_t, size_t); } + struct D { mixin(rangeFuncs); int[] opSlice(size_t, size_t); } + static assert(!hasSlicing!(A)); + static assert( hasSlicing!(B)); + static assert( hasSlicing!(C)); + static assert(!hasSlicing!(D)); + + struct InfOnes + { + enum empty = false; + void popFront() {} + @property int front() { return 1; } + @property InfOnes save() { return this; } + auto opSlice(size_t i, size_t j) { return takeExactly(this, j - i); } + auto opSlice(size_t i, Dollar d) { return this; } + + struct Dollar {} + Dollar opDollar() const { return Dollar.init; } + } + + static assert(hasSlicing!InfOnes); +} + +@safe unittest +{ + import std.range.primitives; + + import std.range : iota; + + assert(10.iota.walkLength == 10); + // iota has a length function, and therefore the + // doesn't have to be walked, and the upTo + // parameter is ignored + assert(10.iota.walkLength(5) == 10); +} + +@safe unittest +{ + import std.range.primitives; + + int[] a = [ 1, 2, 3, 4, 5 ]; + a.popFrontN(2); + assert(a == [ 3, 4, 5 ]); + a.popFrontN(7); + assert(a == [ ]); +} + +@safe unittest +{ + import std.range.primitives; + + import std.algorithm.comparison : equal; + import std.range : iota; + auto LL = iota(1L, 7L); + auto r = popFrontN(LL, 2); + assert(equal(LL, [3L, 4L, 5L, 6L])); + assert(r == 2); +} + +@safe unittest +{ + import std.range.primitives; + + int[] a = [ 1, 2, 3, 4, 5 ]; + a.popBackN(2); + assert(a == [ 1, 2, 3 ]); + a.popBackN(7); + assert(a == [ ]); +} + +@safe unittest +{ + import std.range.primitives; + + import std.algorithm.comparison : equal; + import std.range : iota; + auto LL = iota(1L, 7L); + auto r = popBackN(LL, 2); + assert(equal(LL, [1L, 2L, 3L, 4L])); + assert(r == 2); +} + +@safe unittest +{ + import std.range.primitives; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : filterBidirectional; + + auto a = [1, 2, 3]; + a.popFrontExactly(1); + assert(a == [2, 3]); + a.popBackExactly(1); + assert(a == [2]); + + string s = "日本語"; + s.popFrontExactly(1); + assert(s == "本語"); + s.popBackExactly(1); + assert(s == "本"); + + auto bd = filterBidirectional!"true"([1, 2, 3]); + bd.popFrontExactly(1); + assert(bd.equal([2, 3])); + bd.popBackExactly(1); + assert(bd.equal([2])); +} + +@safe unittest +{ + import std.range.primitives; + + auto a = [ 1, 2, 3 ]; + assert(moveFront(a) == 1); + assert(a.length == 3); + + // define a perfunctory input range + struct InputRange + { + enum bool empty = false; + enum int front = 7; + void popFront() {} + int moveFront() { return 43; } + } + InputRange r; + // calls r.moveFront + assert(moveFront(r) == 43); +} + +@safe unittest +{ + import std.range.primitives; + + struct TestRange + { + int payload = 5; + @property bool empty() { return false; } + @property TestRange save() { return this; } + @property ref int front() return { return payload; } + @property ref int back() return { return payload; } + void popFront() { } + void popBack() { } + } + static assert(isBidirectionalRange!TestRange); + TestRange r; + auto x = moveBack(r); + assert(x == 5); +} + +@safe unittest +{ + import std.range.primitives; + + auto a = [1,2,3,4]; + foreach (idx, it; a) + { + assert(it == moveAt(a, idx)); + } +} + +@safe pure nothrow unittest +{ + import std.range.primitives; + + auto a = [ 1, 2, 3 ]; + assert(!a.empty); + assert(a[3 .. $].empty); + + int[string] b; + assert(b.empty); + b["zero"] = 0; + assert(!b.empty); +} + +@safe pure nothrow unittest +{ + import std.range.primitives; + + auto a = [ 1, 2, 3 ]; + auto b = a.save; + assert(b is a); +} + +@safe pure nothrow unittest +{ + import std.range.primitives; + + auto a = [ 1, 2, 3 ]; + a.popFront(); + assert(a == [ 2, 3 ]); +} + +@safe pure nothrow unittest +{ + import std.range.primitives; + + auto a = [ 1, 2, 3 ]; + a.popBack(); + assert(a == [ 1, 2 ]); +} + +@safe pure nothrow unittest +{ + import std.range.primitives; + + int[] a = [ 1, 2, 3 ]; + assert(a.front == 1); +} + +@safe pure nothrow unittest +{ + import std.range.primitives; + + int[] a = [ 1, 2, 3 ]; + assert(a.back == 3); + a.back += 4; + assert(a.back == 7); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_regex_package.d b/libphobos/testsuite/libphobos.phobos/std_regex_package.d new file mode 100644 index 000000000000..448c9db1aea9 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_regex_package.d @@ -0,0 +1,175 @@ +@system unittest +{ + import std.regex; + + void test(S)() + { + // multi-pattern regex example + S[] arr = [`([a-z]+):(\d+)`, `(\d+),\d+`]; + auto multi = regex(arr); // multi regex + S str = "abc:43 12,34"; + auto m = str.matchAll(multi); + assert(m.front.whichPattern == 1); + assert(m.front[1] == "abc"); + assert(m.front[2] == "43"); + m.popFront(); + assert(m.front.whichPattern == 2); + assert(m.front[1] == "12"); + } + + import std.meta : AliasSeq; + static foreach (C; AliasSeq!(string, wstring, dstring)) + // Test with const array of patterns - see https://issues.dlang.org/show_bug.cgi?id=20301 + static foreach (S; AliasSeq!(C, const C, immutable C)) + test!S(); +} + +@system unittest +{ + import std.regex; + + import std.regex; + assert(matchFirst("abc", "[0-9]+", "[a-z]+").whichPattern == 2); + +} + +@system unittest +{ + import std.regex; + + import std.range.primitives : popFrontN; + + auto c = matchFirst("@abc#", regex(`(\w)(\w)(\w)`)); + assert(c.pre == "@"); // Part of input preceding match + assert(c.post == "#"); // Immediately after match + assert(c.hit == c[0] && c.hit == "abc"); // The whole match + assert(c[2] == "b"); + assert(c.front == "abc"); + c.popFront(); + assert(c.front == "a"); + assert(c.back == "c"); + c.popBack(); + assert(c.back == "b"); + popFrontN(c, 2); + assert(c.empty); + + assert(!matchFirst("nothing", "something")); + + // Captures that are not matched will be null. + c = matchFirst("ac", regex(`a(b)?c`)); + assert(c); + assert(!c[1]); +} + +@system unittest +{ + import std.regex; + + assert(replaceFirst("noon", regex("n"), "[$&]") == "[n]oon"); +} + +@system unittest +{ + import std.regex; + + import std.conv : to; + string list = "#21 out of 46"; + string newList = replaceFirst!(cap => to!string(to!int(cap.hit)+1)) + (list, regex(`[0-9]+`)); + assert(newList == "#22 out of 46"); +} + +@system unittest +{ + import std.regex; + + import std.array; + string m1 = "first message\n"; + string m2 = "second message\n"; + auto result = appender!string(); + replaceFirstInto(result, m1, regex(`([a-z]+) message`), "$1"); + //equivalent of the above with user-defined callback + replaceFirstInto!(cap=>cap[1])(result, m2, regex(`([a-z]+) message`)); + assert(result.data == "first\nsecond\n"); +} + +@system unittest +{ + import std.regex; + + // insert comma as thousands delimiter + auto re = regex(r"(?<=\d)(?=(\d\d\d)+\b)","g"); + assert(replaceAll("12000 + 42100 = 54100", re, ",") == "12,000 + 42,100 = 54,100"); +} + +@system unittest +{ + import std.regex; + + string baz(Captures!(string) m) + { + import std.string : toUpper; + return toUpper(m.hit); + } + // Capitalize the letters 'a' and 'r': + auto s = replaceAll!(baz)("Strap a rocket engine on a chicken.", + regex("[ar]")); + assert(s == "StRAp A Rocket engine on A chicken."); +} + +@system unittest +{ + import std.regex; + + // insert comma as thousands delimiter in fifty randomly produced big numbers + import std.array, std.conv, std.random, std.range; + static re = regex(`(?<=\d)(?=(\d\d\d)+\b)`, "g"); + auto sink = appender!(char [])(); + enum ulong min = 10UL ^^ 10, max = 10UL ^^ 19; + foreach (i; 0 .. 50) + { + sink.clear(); + replaceAllInto(sink, text(uniform(min, max)), re, ","); + foreach (pos; iota(sink.data.length - 4, 0, -4)) + assert(sink.data[pos] == ','); + } +} + +@system unittest +{ + import std.regex; + + import std.algorithm.comparison : equal; + auto s1 = ", abc, de, fg, hi, "; + assert(equal(splitter(s1, regex(", *")), + ["", "abc", "de", "fg", "hi", ""])); +} + +@system unittest +{ + import std.regex; + + import std.algorithm.comparison : equal; + import std.typecons : Yes; + + auto pattern = regex(`([\.,])`); + + assert("2003.04.05" + .splitter!(Yes.keepSeparators)(pattern) + .equal(["2003", ".", "04", ".", "05"])); + + assert(",1,2,3" + .splitter!(Yes.keepSeparators)(pattern) + .equal([",", "1", ",", "2", ",", "3"])); +} + +@system unittest +{ + import std.regex; + + import std.algorithm.comparison; + import std.regex; + string s = `This is {unfriendly} to *regex*`; + assert(s.escaper.equal(`This is \{unfriendly\} to \*regex\*`)); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_signals.d b/libphobos/testsuite/libphobos.phobos/std_signals.d new file mode 100644 index 000000000000..255dbde7d754 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_signals.d @@ -0,0 +1,85 @@ +@system unittest +{ + import std.signals; + + import std.signals; + + int observedMessageCounter = 0; + + class Observer + { // our slot + void watch(string msg, int value) + { + switch (observedMessageCounter++) + { + case 0: + assert(msg == "setting new value"); + assert(value == 4); + break; + case 1: + assert(msg == "setting new value"); + assert(value == 6); + break; + default: + assert(0, "Unknown observation"); + } + } + } + + class Observer2 + { // our slot + void watch(string msg, int value) + { + } + } + + class Foo + { + int value() { return _value; } + + int value(int v) + { + if (v != _value) + { _value = v; + // call all the connected slots with the two parameters + emit("setting new value", v); + } + return v; + } + + // Mix in all the code we need to make Foo into a signal + mixin Signal!(string, int); + + private : + int _value; + } + + Foo a = new Foo; + Observer o = new Observer; + auto o2 = new Observer2; + auto o3 = new Observer2; + auto o4 = new Observer2; + auto o5 = new Observer2; + + a.value = 3; // should not call o.watch() + a.connect(&o.watch); // o.watch is the slot + a.connect(&o2.watch); + a.connect(&o3.watch); + a.connect(&o4.watch); + a.connect(&o5.watch); + a.value = 4; // should call o.watch() + a.disconnect(&o.watch); // o.watch is no longer a slot + a.disconnect(&o3.watch); + a.disconnect(&o5.watch); + a.disconnect(&o4.watch); + a.disconnect(&o2.watch); + a.value = 5; // so should not call o.watch() + a.connect(&o2.watch); + a.connect(&o.watch); // connect again + a.value = 6; // should call o.watch() + destroy(o); // destroying o should automatically disconnect it + a.value = 7; // should not call o.watch() + + assert(observedMessageCounter == 2); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_socket.d b/libphobos/testsuite/libphobos.phobos/std_socket.d new file mode 100644 index 000000000000..5a63193dc7cc --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_socket.d @@ -0,0 +1,66 @@ +@safe unittest +{ + import std.socket; + + InternetHost ih = new InternetHost; + + ih.getHostByAddr(0x7F_00_00_01); + assert(ih.addrList[0] == 0x7F_00_00_01); + ih.getHostByAddr("127.0.0.1"); + assert(ih.addrList[0] == 0x7F_00_00_01); + + if (!ih.getHostByName("www.digitalmars.com")) + return; // don't fail if not connected to internet + + assert(ih.addrList.length); + InternetAddress ia = new InternetAddress(ih.addrList[0], InternetAddress.PORT_ANY); + assert(ih.name == "www.digitalmars.com" || ih.name == "digitalmars.com", + ih.name); + + /* The following assert randomly fails in the test suite. + * https://issues.dlang.org/show_bug.cgi?id=22791 + * So just ignore it when it fails. + */ + //assert(ih.getHostByAddr(ih.addrList[0])); + if (ih.getHostByAddr(ih.addrList[0])) + { + string getHostNameFromInt = ih.name.dup; + + // This randomly fails in the compiler test suite + //assert(ih.getHostByAddr(ia.toAddrString())); + + if (ih.getHostByAddr(ia.toAddrString())) + { + string getHostNameFromStr = ih.name.dup; + assert(getHostNameFromInt == getHostNameFromStr); + } + } +} + +@system unittest +{ + import std.socket; + + auto addr1 = new InternetAddress("127.0.0.1", 80); + auto addr2 = new InternetAddress("127.0.0.2", 80); + + assert(addr1 == addr1); + assert(addr1 != addr2); + +} + +@safe unittest +{ + import std.socket; + + immutable ubyte[4] data = [1, 2, 3, 4]; + auto pair = socketPair(); + scope(exit) foreach (s; pair) s.close(); + + pair[0].send(data[]); + + auto buf = new ubyte[data.length]; + pair[1].receive(buf); + assert(buf == data); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_stdio.d b/libphobos/testsuite/libphobos.phobos/std_stdio.d new file mode 100644 index 000000000000..43b3cf6aa50d --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_stdio.d @@ -0,0 +1,185 @@ +@system unittest +{ + import std.stdio; + + static import std.file; + + auto testFile = std.file.deleteme(); + std.file.write(testFile, "\r\n\n\r\n"); + scope(exit) std.file.remove(testFile); + + auto f = File(testFile, "r"); + auto buf = f.rawRead(new char[5]); + f.close(); + assert(buf == "\r\n\n\r\n"); + +} + +@system unittest +{ + import std.stdio; + + static import std.file; + + auto testFile = std.file.deleteme(); + auto f = File(testFile, "w"); + scope(exit) std.file.remove(testFile); + + f.rawWrite("\r\n\n\r\n"); + f.close(); + assert(std.file.read(testFile) == "\r\n\n\r\n"); + +} + +@system unittest +{ + import std.stdio; + + import std.conv : text; + static import std.file; + + auto testFile = std.file.deleteme(); + std.file.write(testFile, "abcdefghijklmnopqrstuvwqxyz"); + scope(exit) { std.file.remove(testFile); } + + auto f = File(testFile); + auto a = new ubyte[4]; + f.rawRead(a); + assert(f.tell == 4, text(f.tell)); + +} + +@system unittest +{ + import std.stdio; + + static import std.file; + + auto deleteme = std.file.deleteme(); + std.file.write(deleteme, "hello\nworld\ntrue\nfalse\n"); + scope(exit) std.file.remove(deleteme); + string s; + auto f = File(deleteme); + f.readf!"%s\n"(s); + assert(s == "hello", "["~s~"]"); + f.readf("%s\n", s); + assert(s == "world", "["~s~"]"); + + bool b1, b2; + f.readf("%s\n%s\n", b1, b2); + assert(b1 == true && b2 == false); + +} + +@system unittest +{ + import std.stdio; + + static import std.file; + import std.typecons : tuple; + + // prepare test file + auto testFile = std.file.deleteme(); + scope(failure) printf("Failed test at line %d\n", __LINE__); + std.file.write(testFile, "1 2\n4 1\n5 100"); + scope(exit) std.file.remove(testFile); + + File f = File(testFile); + scope(exit) f.close(); + + auto expected = [tuple(1, 2), tuple(4, 1), tuple(5, 100)]; + uint i; + foreach (e; f.byRecord!(int, int)("%s %s")) + { + assert(e == expected[i++]); + } + +} + +@safe unittest +{ + import std.stdio; + + static assert(isFileHandle!(FILE*)); + static assert(isFileHandle!(File)); +} + +@safe unittest +{ + import std.stdio; + + // Read stdin, sort lines, write to stdout + import std.algorithm.mutation : copy; + import std.algorithm.sorting : sort; + import std.array : array; + import std.typecons : Yes; + + void main() + { + stdin // read from stdin + .byLineCopy(Yes.keepTerminator) // copying each line + .array() // convert to array of lines + .sort() // sort the lines + .copy( // copy output of .sort to an OutputRange + stdout.lockingTextWriter()); // the OutputRange + } +} + +@safe unittest +{ + import std.stdio; + + void main() + { + stdout.writeln("Write a message to stdout."); + } +} + +@safe unittest +{ + import std.stdio; + + void main() + { + import std.algorithm.iteration : filter, map, sum; + import std.format : format; + import std.range : iota, tee; + + int len; + const r = 6.iota + .filter!(a => a % 2) // 1 3 5 + .map!(a => a * 2) // 2 6 10 + .tee!(_ => stdout.writefln("len: %d", len++)) + .sum; + + assert(r == 18); + } +} + +@safe unittest +{ + import std.stdio; + + void main() + { + import std.algorithm.mutation : copy; + import std.algorithm.iteration : map; + import std.format : format; + import std.range : iota; + + 10.iota + .map!(e => "N: %d".format(e)) + .copy(stdout.lockingTextWriter()); // the OutputRange + } +} + +@safe unittest +{ + import std.stdio; + + void main() + { + stderr.writeln("Write a message to stderr."); + } +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_string.d b/libphobos/testsuite/libphobos.phobos/std_string.d new file mode 100644 index 000000000000..256b5a77287b --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_string.d @@ -0,0 +1,892 @@ +@safe pure unittest +{ + import std.string; + + import std.exception : assertThrown; + auto bad = " a\n\tb\n c"; + assertThrown!StringException(bad.outdent); +} + +@system pure unittest +{ + import std.string; + + assert(fromStringz("foo\0"c.ptr) == "foo"c); + assert(fromStringz("foo\0"w.ptr) == "foo"w); + assert(fromStringz("foo\0"d.ptr) == "foo"d); + + assert(fromStringz("ç¦\0"c.ptr) == "ç¦"c); + assert(fromStringz("ç¦\0"w.ptr) == "ç¦"w); + assert(fromStringz("ç¦\0"d.ptr) == "ç¦"d); +} + +@nogc @safe pure nothrow unittest +{ + import std.string; + + struct C + { + char[32] name; + } + assert(C("foo\0"c).name.fromStringz() == "foo"c); + + struct W + { + wchar[32] name; + } + assert(W("foo\0"w).name.fromStringz() == "foo"w); + + struct D + { + dchar[32] name; + } + assert(D("foo\0"d).name.fromStringz() == "foo"d); +} + +pure nothrow @system unittest +{ + import std.string; + + import core.stdc.string : strlen; + import std.conv : to; + + auto p = toStringz("foo"); + assert(strlen(p) == 3); + const(char)[] foo = "abbzxyzzy"; + p = toStringz(foo[3 .. 5]); + assert(strlen(p) == 2); + + string test = ""; + p = toStringz(test); + assert(*p == 0); + + test = "\0"; + p = toStringz(test); + assert(*p == 0); + + test = "foo\0"; + p = toStringz(test); + assert(p[0] == 'f' && p[1] == 'o' && p[2] == 'o' && p[3] == 0); + + const string test2 = ""; + p = toStringz(test2); + assert(*p == 0); + + assert(toStringz([]) is toStringz("")); +} + +@safe pure unittest +{ + import std.string; + + import std.typecons : No; + + string s = "Hello World"; + assert(indexOf(s, 'W') == 6); + assert(indexOf(s, 'Z') == -1); + assert(indexOf(s, 'w', No.caseSensitive) == 6); +} + +@safe pure unittest +{ + import std.string; + + import std.typecons : No; + + string s = "Hello World"; + assert(indexOf(s, 'W', 4) == 6); + assert(indexOf(s, 'Z', 100) == -1); + assert(indexOf(s, 'w', 3, No.caseSensitive) == 6); +} + +@safe pure unittest +{ + import std.string; + + import std.typecons : No; + + string s = "Hello World"; + assert(indexOf(s, "Wo", 4) == 6); + assert(indexOf(s, "Zo", 100) == -1); + assert(indexOf(s, "wo", 3, No.caseSensitive) == 6); +} + +@safe pure unittest +{ + import std.string; + + import std.typecons : No; + + string s = "Hello World"; + assert(indexOf(s, "Wo") == 6); + assert(indexOf(s, "Zo") == -1); + assert(indexOf(s, "wO", No.caseSensitive) == 6); +} + +@safe pure unittest +{ + import std.string; + + import std.typecons : No; + + string s = "Hello World"; + assert(lastIndexOf(s, 'l') == 9); + assert(lastIndexOf(s, 'Z') == -1); + assert(lastIndexOf(s, 'L', No.caseSensitive) == 9); +} + +@safe pure unittest +{ + import std.string; + + import std.typecons : No; + + string s = "Hello World"; + assert(lastIndexOf(s, 'l', 4) == 3); + assert(lastIndexOf(s, 'Z', 1337) == -1); + assert(lastIndexOf(s, 'L', 7, No.caseSensitive) == 3); +} + +@safe pure unittest +{ + import std.string; + + import std.typecons : No; + + string s = "Hello World"; + assert(lastIndexOf(s, "ll") == 2); + assert(lastIndexOf(s, "Zo") == -1); + assert(lastIndexOf(s, "lL", No.caseSensitive) == 2); +} + +@safe pure unittest +{ + import std.string; + + import std.typecons : No; + + string s = "Hello World"; + assert(lastIndexOf(s, "ll", 4) == 2); + assert(lastIndexOf(s, "Zo", 128) == -1); + assert(lastIndexOf(s, "lL", 3, No.caseSensitive) == -1); +} + +@safe pure unittest +{ + import std.string; + + import std.conv : to; + + ptrdiff_t i = "helloWorld".indexOfAny("Wr"); + assert(i == 5); + i = "öällo world".indexOfAny("lo "); + assert(i == 4, to!string(i)); +} + +@safe pure unittest +{ + import std.string; + + import std.conv : to; + + ptrdiff_t i = "helloWorld".indexOfAny("Wr", 4); + assert(i == 5); + + i = "Foo öällo world".indexOfAny("lh", 3); + assert(i == 8, to!string(i)); +} + +@safe pure unittest +{ + import std.string; + + ptrdiff_t i = "helloWorld".lastIndexOfAny("Wlo"); + assert(i == 8); + + i = "Foo öäöllo world".lastIndexOfAny("öF"); + assert(i == 8); +} + +@safe pure unittest +{ + import std.string; + + import std.conv : to; + + ptrdiff_t i = "helloWorld".lastIndexOfAny("Wlo", 4); + assert(i == 3); + + i = "Foo öäöllo world".lastIndexOfAny("öF", 3); + assert(i == 0); +} + +@safe pure unittest +{ + import std.string; + + assert(indexOfNeither("abba", "a", 2) == 2); + assert(indexOfNeither("def", "de", 1) == 2); + assert(indexOfNeither("dfefffg", "dfe", 4) == 6); +} + +@safe pure unittest +{ + import std.string; + + assert(indexOfNeither("def", "a") == 0); + assert(indexOfNeither("def", "de") == 2); + assert(indexOfNeither("dfefffg", "dfe") == 6); +} + +@safe pure unittest +{ + import std.string; + + assert(lastIndexOfNeither("abba", "a") == 2); + assert(lastIndexOfNeither("def", "f") == 1); +} + +@safe pure unittest +{ + import std.string; + + assert(lastIndexOfNeither("def", "rsa", 3) == -1); + assert(lastIndexOfNeither("abba", "a", 2) == 1); +} + +@safe pure unittest +{ + import std.string; + + string s = "hello"; + static assert(is(typeof(representation(s)) == immutable(ubyte)[])); + assert(representation(s) is cast(immutable(ubyte)[]) s); + assert(representation(s) == [0x68, 0x65, 0x6c, 0x6c, 0x6f]); +} + +pure @safe unittest +{ + import std.string; + + assert(capitalize("hello") == "Hello"); + assert(capitalize("World") == "World"); +} + +@safe pure nothrow unittest +{ + import std.string; + + string s = "Hello\nmy\rname\nis"; + assert(splitLines(s) == ["Hello", "my", "name", "is"]); +} + +@safe pure unittest +{ + import std.string; + + import std.array : array; + + string s = "Hello\nmy\rname\nis"; + + /* notice the call to 'array' to turn the lazy range created by + lineSplitter comparable to the string[] created by splitLines. + */ + assert(lineSplitter(s).array == splitLines(s)); +} + +@nogc @safe pure unittest +{ + import std.string; + + auto s = "\rpeter\n\rpaul\r\njerry\u2028ice\u2029cream\n\nsunday\nmon\u2030day\n"; + auto lines = s.lineSplitter(); + static immutable witness = ["", "peter", "", "paul", "jerry", "ice", "cream", "", "sunday", "mon\u2030day"]; + uint i; + foreach (line; lines) + { + assert(line == witness[i++]); + } + assert(i == witness.length); +} + +nothrow @safe pure unittest +{ + import std.string; + + import std.uni : lineSep, paraSep; + assert(stripLeft(" hello world ") == + "hello world "); + assert(stripLeft("\n\t\v\rhello world\n\t\v\r") == + "hello world\n\t\v\r"); + assert(stripLeft(" \u2028hello world") == + "hello world"); + assert(stripLeft("hello world") == + "hello world"); + assert(stripLeft([lineSep] ~ "hello world" ~ lineSep) == + "hello world" ~ [lineSep]); + assert(stripLeft([paraSep] ~ "hello world" ~ paraSep) == + "hello world" ~ [paraSep]); + + import std.array : array; + import std.utf : byChar; + assert(stripLeft(" hello world "w.byChar).array == + "hello world "); + assert(stripLeft(" \u2022hello world ".byChar).array == + "\u2022hello world "); +} + +@safe pure unittest +{ + import std.string; + + assert(stripLeft(" hello world ", " ") == + "hello world "); + assert(stripLeft("xxxxxhello world ", "x") == + "hello world "); + assert(stripLeft("xxxyy hello world ", "xy ") == + "hello world "); +} + +@safe pure unittest +{ + import std.string; + + import std.array : array; + import std.utf : byChar, byWchar, byDchar; + + assert(stripLeft(" xxxyy hello world "w.byChar, "xy ").array == + "hello world "); + + assert(stripLeft("\u2028\u2020hello world\u2028"w.byWchar, + "\u2028").array == "\u2020hello world\u2028"); + assert(stripLeft("\U00010001hello world"w.byWchar, " ").array == + "\U00010001hello world"w); + assert(stripLeft("\U00010001 xyhello world"d.byDchar, + "\U00010001 xy").array == "hello world"d); + + assert(stripLeft("\u2020hello"w, "\u2020"w) == "hello"w); + assert(stripLeft("\U00010001hello"d, "\U00010001"d) == "hello"d); + assert(stripLeft(" hello ", "") == " hello "); +} + +nothrow @safe pure unittest +{ + import std.string; + + import std.uni : lineSep, paraSep; + assert(stripRight(" hello world ") == + " hello world"); + assert(stripRight("\n\t\v\rhello world\n\t\v\r") == + "\n\t\v\rhello world"); + assert(stripRight("hello world") == + "hello world"); + assert(stripRight([lineSep] ~ "hello world" ~ lineSep) == + [lineSep] ~ "hello world"); + assert(stripRight([paraSep] ~ "hello world" ~ paraSep) == + [paraSep] ~ "hello world"); +} + +@safe pure unittest +{ + import std.string; + + assert(stripRight(" hello world ", "x") == + " hello world "); + assert(stripRight(" hello world ", " ") == + " hello world"); + assert(stripRight(" hello worldxy ", "xy ") == + " hello world"); +} + +@safe pure unittest +{ + import std.string; + + import std.uni : lineSep, paraSep; + assert(strip(" hello world ") == + "hello world"); + assert(strip("\n\t\v\rhello world\n\t\v\r") == + "hello world"); + assert(strip("hello world") == + "hello world"); + assert(strip([lineSep] ~ "hello world" ~ [lineSep]) == + "hello world"); + assert(strip([paraSep] ~ "hello world" ~ [paraSep]) == + "hello world"); +} + +@safe pure unittest +{ + import std.string; + + assert(strip(" hello world ", "x") == + " hello world "); + assert(strip(" hello world ", " ") == + "hello world"); + assert(strip(" xyxyhello worldxyxy ", "xy ") == + "hello world"); + assert(strip("\u2020hello\u2020"w, "\u2020"w) == "hello"w); + assert(strip("\U00010001hello\U00010001"d, "\U00010001"d) == "hello"d); + assert(strip(" hello ", "") == " hello "); +} + +@safe pure unittest +{ + import std.string; + + assert(strip("xxhelloyy", "x", "y") == "hello"); + assert(strip(" xyxyhello worldxyxyzz ", "xy ", "xyz ") == + "hello world"); + assert(strip("\u2020hello\u2028"w, "\u2020"w, "\u2028"w) == "hello"w); + assert(strip("\U00010001hello\U00010002"d, "\U00010001"d, "\U00010002"d) == + "hello"d); + assert(strip(" hello ", "", "") == " hello "); +} + +@safe pure unittest +{ + import std.string; + + import std.uni : lineSep, paraSep, nelSep; + import std.utf : decode; + assert(chomp(" hello world \n\r") == " hello world \n"); + assert(chomp(" hello world \r\n") == " hello world "); + assert(chomp(" hello world \f") == " hello world "); + assert(chomp(" hello world \v") == " hello world "); + assert(chomp(" hello world \n\n") == " hello world \n"); + assert(chomp(" hello world \n\n ") == " hello world \n\n "); + assert(chomp(" hello world \n\n" ~ [lineSep]) == " hello world \n\n"); + assert(chomp(" hello world \n\n" ~ [paraSep]) == " hello world \n\n"); + assert(chomp(" hello world \n\n" ~ [ nelSep]) == " hello world \n\n"); + assert(chomp(" hello world ") == " hello world "); + assert(chomp(" hello world") == " hello world"); + assert(chomp("") == ""); + + assert(chomp(" hello world", "orld") == " hello w"); + assert(chomp(" hello world", " he") == " hello world"); + assert(chomp("", "hello") == ""); + + // Don't decode pointlessly + assert(chomp("hello\xFE", "\r") == "hello\xFE"); +} + +@safe pure unittest +{ + import std.string; + + assert(chompPrefix("hello world", "he") == "llo world"); + assert(chompPrefix("hello world", "hello w") == "orld"); + assert(chompPrefix("hello world", " world") == "hello world"); + assert(chompPrefix("", "hello") == ""); +} + +@safe pure unittest +{ + import std.string; + + assert(chop("hello world") == "hello worl"); + assert(chop("hello world\n") == "hello world"); + assert(chop("hello world\r") == "hello world"); + assert(chop("hello world\n\r") == "hello world\n"); + assert(chop("hello world\r\n") == "hello world"); + assert(chop("Walter Bright") == "Walter Brigh"); + assert(chop("") == ""); +} + +@safe pure unittest +{ + import std.string; + + assert(leftJustify("hello", 7, 'X') == "helloXX"); + assert(leftJustify("hello", 2, 'X') == "hello"); + assert(leftJustify("hello", 9, 'X') == "helloXXXX"); +} + +@safe pure @nogc nothrow unittest +{ + import std.string; + + import std.algorithm.comparison : equal; + import std.utf : byChar; + assert(leftJustifier("hello", 2).equal("hello".byChar)); + assert(leftJustifier("hello", 7).equal("hello ".byChar)); + assert(leftJustifier("hello", 7, 'x').equal("helloxx".byChar)); +} + +@safe pure unittest +{ + import std.string; + + assert(rightJustify("hello", 7, 'X') == "XXhello"); + assert(rightJustify("hello", 2, 'X') == "hello"); + assert(rightJustify("hello", 9, 'X') == "XXXXhello"); +} + +@safe pure @nogc nothrow unittest +{ + import std.string; + + import std.algorithm.comparison : equal; + import std.utf : byChar; + assert(rightJustifier("hello", 2).equal("hello".byChar)); + assert(rightJustifier("hello", 7).equal(" hello".byChar)); + assert(rightJustifier("hello", 7, 'x').equal("xxhello".byChar)); +} + +@safe pure unittest +{ + import std.string; + + assert(center("hello", 7, 'X') == "XhelloX"); + assert(center("hello", 2, 'X') == "hello"); + assert(center("hello", 9, 'X') == "XXhelloXX"); +} + +@safe pure @nogc nothrow unittest +{ + import std.string; + + import std.algorithm.comparison : equal; + import std.utf : byChar; + assert(centerJustifier("hello", 2).equal("hello".byChar)); + assert(centerJustifier("hello", 8).equal(" hello ".byChar)); + assert(centerJustifier("hello", 7, 'x').equal("xhellox".byChar)); +} + +@safe pure unittest +{ + import std.string; + + assert(detab(" \n\tx", 9) == " \n x"); +} + +@safe pure unittest +{ + import std.string; + + import std.array : array; + + assert(detabber(" \n\tx", 9).array == " \n x"); +} + +@safe pure unittest +{ + import std.string; + + import std.array : array; + import std.utf : byChar, byWchar; + + assert(detabber(" \u2029\t".byChar, 9).array == " \u2029 "); + auto r = "hel\tx".byWchar.detabber(); + assert(r.front == 'h'); + auto s = r.save; + r.popFront(); + r.popFront(); + assert(r.front == 'l'); + assert(s.front == 'h'); +} + +@safe pure unittest +{ + import std.string; + + assert(entab(" x \n") == "\tx\n"); +} + +@safe pure unittest +{ + import std.string; + + import std.array : array; + assert(entabber(" x \n").array == "\tx\n"); +} + +@safe pure unittest +{ + import std.string; + + dchar[dchar] transTable1 = ['e' : '5', 'o' : '7', '5': 'q']; + assert(translate("hello world", transTable1) == "h5ll7 w7rld"); + + assert(translate("hello world", transTable1, "low") == "h5 rd"); + + string[dchar] transTable2 = ['e' : "5", 'o' : "orange"]; + assert(translate("hello world", transTable2) == "h5llorange worangerld"); +} + +@safe pure unittest +{ + import std.string; + + import std.array : appender; + dchar[dchar] transTable1 = ['e' : '5', 'o' : '7', '5': 'q']; + auto buffer = appender!(dchar[])(); + translate("hello world", transTable1, null, buffer); + assert(buffer.data == "h5ll7 w7rld"); + + buffer.clear(); + translate("hello world", transTable1, "low", buffer); + assert(buffer.data == "h5 rd"); + + buffer.clear(); + string[dchar] transTable2 = ['e' : "5", 'o' : "orange"]; + translate("hello world", transTable2, null, buffer); + assert(buffer.data == "h5llorange worangerld"); +} + +@safe pure nothrow unittest +{ + import std.string; + + auto transTable1 = makeTrans("eo5", "57q"); + assert(translate("hello world", transTable1) == "h5ll7 w7rld"); + + assert(translate("hello world", transTable1, "low") == "h5 rd"); +} + +@safe pure nothrow unittest +{ + import std.string; + + auto transTable1 = makeTrans("eo5", "57q"); + assert(translate("hello world", transTable1) == "h5ll7 w7rld"); + + assert(translate("hello world", transTable1, "low") == "h5 rd"); +} + +@safe pure unittest +{ + import std.string; + + assert(translate("hello world", makeTransTable("hl", "q5")) == "qe55o wor5d"); + assert(translate("hello world", makeTransTable("12345", "67890")) == "hello world"); +} + +@safe pure unittest +{ + import std.string; + + import std.array : appender; + auto buffer = appender!(char[])(); + auto transTable1 = makeTransTable("eo5", "57q"); + translate("hello world", transTable1, null, buffer); + assert(buffer.data == "h5ll7 w7rld"); + + buffer.clear(); + translate("hello world", transTable1, "low", buffer); + assert(buffer.data == "h5 rd"); +} + +@safe pure unittest +{ + import std.string; + + assert(succ("1") == "2"); + assert(succ("9") == "10"); + assert(succ("999") == "1000"); + assert(succ("zz99") == "aaa00"); +} + +@safe pure unittest +{ + import std.string; + + assert(tr("abcdef", "cd", "CD") == "abCDef"); + assert(tr("1st March, 2018", "March", "MAR", "s") == "1st MAR, 2018"); + assert(tr("abcdef", "ef", "", "d") == "abcd"); + assert(tr("14-Jul-87", "a-zA-Z", " ", "cs") == " Jul "); +} + +@safe @nogc pure nothrow unittest +{ + import std.string; + + assert(isNumeric("123")); + assert(isNumeric("123UL")); + assert(isNumeric("123L")); + assert(isNumeric("+123U")); + assert(isNumeric("-123L")); +} + +@safe @nogc pure nothrow unittest +{ + import std.string; + + assert(isNumeric("+123")); + assert(isNumeric("-123.01")); + assert(isNumeric("123.3e-10f")); + assert(isNumeric("123.3e-10fi")); + assert(isNumeric("123.3e-10L")); + + assert(isNumeric("nan")); + assert(isNumeric("nani")); + assert(isNumeric("-inf")); +} + +@safe @nogc pure nothrow unittest +{ + import std.string; + + assert(isNumeric("-123e-1+456.9e-10Li")); + assert(isNumeric("+123e+10+456i")); + assert(isNumeric("123+456")); +} + +@safe pure unittest +{ + import std.string; + + enum a = isNumeric("123.00E-5+1234.45E-12Li"); + enum b = isNumeric("12345xxxx890"); + + static assert( a); + static assert(!b); +} + +@safe unittest +{ + import std.string; + + assert(soundexer("Gauss") == "G200"); + assert(soundexer("Ghosh") == "G200"); + + assert(soundexer("Robert") == "R163"); + assert(soundexer("Rupert") == "R163"); + + assert(soundexer("0123^&^^**&^") == ['\0', '\0', '\0', '\0']); +} + +@safe unittest +{ + import std.string; + + assert(soundex("Gauss") == "G200"); + assert(soundex("Ghosh") == "G200"); + + assert(soundex("Robert") == "R163"); + assert(soundex("Rupert") == "R163"); + + assert(soundex("0123^&^^**&^") == null); +} + +@safe unittest +{ + import std.string; + + import std.string; + + static string[] list = [ "food", "foxy" ]; + auto abbrevs = abbrev(list); + assert(abbrevs == ["fox": "foxy", "food": "food", + "foxy": "foxy", "foo": "food"]); +} + +@safe pure unittest +{ + import std.string; + + import std.utf : byChar, byWchar, byDchar; + + assert(column("1234 ") == 5); + assert(column("1234 "w) == 5); + assert(column("1234 "d) == 5); + + assert(column("1234 ".byChar()) == 5); + assert(column("1234 "w.byWchar()) == 5); + assert(column("1234 "d.byDchar()) == 5); + + // Tab stops are set at 8 spaces by default; tab characters insert enough + // spaces to bring the column position to the next multiple of 8. + assert(column("\t") == 8); + assert(column("1\t") == 8); + assert(column("\t1") == 9); + assert(column("123\t") == 8); + + // Other tab widths are possible by specifying it explicitly: + assert(column("\t", 4) == 4); + assert(column("1\t", 4) == 4); + assert(column("\t1", 4) == 5); + assert(column("123\t", 4) == 4); + + // New lines reset the column number. + assert(column("abc\n") == 0); + assert(column("abc\n1") == 1); + assert(column("abcdefg\r1234") == 4); + assert(column("abc\u20281") == 1); + assert(column("abc\u20291") == 1); + assert(column("abc\u00851") == 1); + assert(column("abc\u00861") == 5); +} + +@safe pure unittest +{ + import std.string; + + assert(wrap("a short string", 7) == "a short\nstring\n"); + + // wrap will not break inside of a word, but at the next space + assert(wrap("a short string", 4) == "a\nshort\nstring\n"); + + assert(wrap("a short string", 7, "\t") == "\ta\nshort\nstring\n"); + assert(wrap("a short string", 7, "\t", " ") == "\ta\n short\n string\n"); +} + +@safe pure unittest +{ + import std.string; + + enum pretty = q{ + import std.stdio; + void main() { + writeln("Hello"); + } + }.outdent(); + + enum ugly = q{ +import std.stdio; +void main() { + writeln("Hello"); +} +}; + + assert(pretty == ugly); +} + +@safe pure unittest +{ + import std.string; + + auto str1 = [ + " void main()\n", + " {\n", + " test();\n", + " }\n" + ]; + auto str1Expected = [ + "void main()\n", + "{\n", + " test();\n", + "}\n" + ]; + assert(str1.outdent == str1Expected); + + auto str2 = [ + "void main()\n", + " {\n", + " test();\n", + " }\n" + ]; + assert(str2.outdent == str2); +} + +@safe pure unittest +{ + import std.string; + + string a = "Hölo World"; + immutable(ubyte)[] b = a.representation; + string c = b.assumeUTF; + + assert(c == "Hölo World"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_sumtype.d b/libphobos/testsuite/libphobos.phobos/std_sumtype.d new file mode 100644 index 000000000000..2a7eaf35f125 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_sumtype.d @@ -0,0 +1,301 @@ +@safe unittest +{ + import std.sumtype; + + import std.math.operations : isClose; + + struct Fahrenheit { double degrees; } + struct Celsius { double degrees; } + struct Kelvin { double degrees; } + + alias Temperature = SumType!(Fahrenheit, Celsius, Kelvin); + + // Construct from any of the member types. + Temperature t1 = Fahrenheit(98.6); + Temperature t2 = Celsius(100); + Temperature t3 = Kelvin(273); + + // Use pattern matching to access the value. + Fahrenheit toFahrenheit(Temperature t) + { + return Fahrenheit( + t.match!( + (Fahrenheit f) => f.degrees, + (Celsius c) => c.degrees * 9.0/5 + 32, + (Kelvin k) => k.degrees * 9.0/5 - 459.4 + ) + ); + } + + assert(toFahrenheit(t1).degrees.isClose(98.6)); + assert(toFahrenheit(t2).degrees.isClose(212)); + assert(toFahrenheit(t3).degrees.isClose(32)); + + // Use ref to modify the value in place. + void freeze(ref Temperature t) + { + t.match!( + (ref Fahrenheit f) => f.degrees = 32, + (ref Celsius c) => c.degrees = 0, + (ref Kelvin k) => k.degrees = 273 + ); + } + + freeze(t1); + assert(toFahrenheit(t1).degrees.isClose(32)); + + // Use a catch-all handler to give a default result. + bool isFahrenheit(Temperature t) + { + return t.match!( + (Fahrenheit f) => true, + _ => false + ); + } + + assert(isFahrenheit(t1)); + assert(!isFahrenheit(t2)); + assert(!isFahrenheit(t3)); +} + +@safe unittest +{ + import std.sumtype; + + alias ExampleSumType = SumType!(int, string, double); + + ExampleSumType a = 123; + ExampleSumType b = "hello"; + ExampleSumType c = 3.14; + + assert(a.handle == "got an int"); + assert(b.handle == "got a string"); + assert(c.handle == "got a double"); +} + +@system unittest +{ + import std.sumtype; + + import std.functional : partial; + import std.traits : EnumMembers; + import std.typecons : Tuple; + + enum Op : string + { + Plus = "+", + Minus = "-", + Times = "*", + Div = "/" + } + + // An expression is either + // - a number, + // - a variable, or + // - a binary operation combining two sub-expressions. + alias Expr = SumType!( + double, + string, + Tuple!(Op, "op", This*, "lhs", This*, "rhs") + ); + + // Shorthand for Tuple!(Op, "op", Expr*, "lhs", Expr*, "rhs"), + // the Tuple type above with Expr substituted for This. + alias BinOp = Expr.Types[2]; + + // Factory function for number expressions + Expr* num(double value) + { + return new Expr(value); + } + + // Factory function for variable expressions + Expr* var(string name) + { + return new Expr(name); + } + + // Factory function for binary operation expressions + Expr* binOp(Op op, Expr* lhs, Expr* rhs) + { + return new Expr(BinOp(op, lhs, rhs)); + } + + // Convenience wrappers for creating BinOp expressions + alias sum = partial!(binOp, Op.Plus); + alias diff = partial!(binOp, Op.Minus); + alias prod = partial!(binOp, Op.Times); + alias quot = partial!(binOp, Op.Div); + + // Evaluate expr, looking up variables in env + double eval(Expr expr, double[string] env) + { + return expr.match!( + (double num) => num, + (string var) => env[var], + (BinOp bop) + { + double lhs = eval(*bop.lhs, env); + double rhs = eval(*bop.rhs, env); + final switch (bop.op) + { + static foreach (op; EnumMembers!Op) + { + case op: + return mixin("lhs" ~ op ~ "rhs"); + } + } + } + ); + } + + // Return a "pretty-printed" representation of expr + string pprint(Expr expr) + { + import std.format : format; + + return expr.match!( + (double num) => "%g".format(num), + (string var) => var, + (BinOp bop) => "(%s %s %s)".format( + pprint(*bop.lhs), + cast(string) bop.op, + pprint(*bop.rhs) + ) + ); + } + + Expr* myExpr = sum(var("a"), prod(num(2), var("b"))); + double[string] myEnv = ["a":3, "b":4, "c":7]; + + assert(eval(*myExpr, myEnv) == 11); + assert(pprint(*myExpr) == "(a + (2 * b))"); +} + +@safe unittest +{ + import std.sumtype; + + static struct ConvertsToSumType + { + SumType!int payload; + alias payload this; + } + + static struct ContainsSumType + { + SumType!int payload; + } + + assert(isSumType!(SumType!int)); + assert(isSumType!ConvertsToSumType); + assert(!isSumType!ContainsSumType); +} + +@safe unittest +{ + import std.sumtype; + + alias Number = SumType!(double, int); + + Number x; + + // Problem: because int implicitly converts to double, the double + // handler is used for both types, and the int handler never matches. + assert(!__traits(compiles, + x.match!( + (double d) => "got double", + (int n) => "got int" + ) + )); + + // Solution 1: put the handler for the "more specialized" type (in this + // case, int) before the handler for the type it converts to. + assert(__traits(compiles, + x.match!( + (int n) => "got int", + (double d) => "got double" + ) + )); + + // Solution 2: use a template that only accepts the exact type it's + // supposed to match, instead of any type that implicitly converts to it. + alias exactly(T, alias fun) = function (arg) + { + static assert(is(typeof(arg) == T)); + return fun(arg); + }; + + // Now, even if we put the double handler first, it will only be used for + // doubles, not ints. + assert(__traits(compiles, + x.match!( + exactly!(double, d => "got double"), + exactly!(int, n => "got int") + ) + )); +} + +@safe unittest +{ + import std.sumtype; + + struct Point2D { double x, y; } + struct Point3D { double x, y, z; } + + alias Point = SumType!(Point2D, Point3D); + + version (none) + { + // This function works, but the code is ugly and repetitive. + // It uses three separate calls to match! + @safe pure nothrow @nogc + bool sameDimensions(Point p1, Point p2) + { + return p1.match!( + (Point2D _) => p2.match!( + (Point2D _) => true, + _ => false + ), + (Point3D _) => p2.match!( + (Point3D _) => true, + _ => false + ) + ); + } + } + + // This version is much nicer. + @safe pure nothrow @nogc + bool sameDimensions(Point p1, Point p2) + { + alias doMatch = match!( + (Point2D _1, Point2D _2) => true, + (Point3D _1, Point3D _2) => true, + (_1, _2) => false + ); + + return doMatch(p1, p2); + } + + Point a = Point2D(1, 2); + Point b = Point2D(3, 4); + Point c = Point3D(5, 6, 7); + Point d = Point3D(8, 9, 0); + + assert( sameDimensions(a, b)); + assert( sameDimensions(c, d)); + assert(!sameDimensions(a, c)); + assert(!sameDimensions(d, b)); +} + +@safe unittest +{ + import std.sumtype; + + alias handleInt = (int i) => "got an int"; + + assert( canMatch!(handleInt, int)); + assert(!canMatch!(handleInt, string)); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_traits.d b/libphobos/testsuite/libphobos.phobos/std_traits.d new file mode 100644 index 000000000000..a86892c26ab8 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_traits.d @@ -0,0 +1,2419 @@ +@safe unittest +{ + import std.traits; + + static assert(is(InoutOf!(int) == inout int)); + static assert(is(InoutOf!(inout int) == inout int)); + static assert(is(InoutOf!(const int) == inout const int)); + static assert(is(InoutOf!(shared int) == inout shared int)); +} + +@safe unittest +{ + import std.traits; + + static assert(is(ConstOf!(int) == const int)); + static assert(is(ConstOf!(const int) == const int)); + static assert(is(ConstOf!(inout int) == const inout int)); + static assert(is(ConstOf!(shared int) == const shared int)); +} + +@safe unittest +{ + import std.traits; + + static assert(is(SharedOf!(int) == shared int)); + static assert(is(SharedOf!(shared int) == shared int)); + static assert(is(SharedOf!(inout int) == shared inout int)); + static assert(is(SharedOf!(immutable int) == shared immutable int)); +} + +@safe unittest +{ + import std.traits; + + static assert(is(SharedInoutOf!(int) == shared inout int)); + static assert(is(SharedInoutOf!(int) == inout shared int)); + + static assert(is(SharedInoutOf!(const int) == shared inout const int)); + static assert(is(SharedInoutOf!(immutable int) == shared inout immutable int)); +} + +@safe unittest +{ + import std.traits; + + static assert(is(SharedConstOf!(int) == shared const int)); + static assert(is(SharedConstOf!(int) == const shared int)); + + static assert(is(SharedConstOf!(inout int) == shared inout const int)); + // immutable variables are implicitly shared and const + static assert(is(SharedConstOf!(immutable int) == immutable int)); +} + +@safe unittest +{ + import std.traits; + + static assert(is(SharedConstInoutOf!(int) == shared const inout int)); + static assert(is(SharedConstInoutOf!(int) == const shared inout int)); + static assert(is(SharedConstInoutOf!(inout int) == shared inout const int)); + // immutable variables are implicitly shared and const + static assert(is(SharedConstInoutOf!(immutable int) == immutable int)); +} + +@safe unittest +{ + import std.traits; + + static assert(is(ImmutableOf!(int) == immutable int)); + static assert(is(ImmutableOf!(const int) == immutable int)); + static assert(is(ImmutableOf!(inout int) == immutable int)); + static assert(is(ImmutableOf!(shared int) == immutable int)); +} + +@safe unittest +{ + import std.traits; + + static assert(__traits(isSame, QualifierOf!(shared const inout int), SharedConstInoutOf)); + static assert(__traits(isSame, QualifierOf!(immutable int), ImmutableOf)); + static assert(__traits(isSame, QualifierOf!(shared int), SharedOf)); + static assert(__traits(isSame, QualifierOf!(shared inout int), SharedInoutOf)); + import std.meta : Alias; + static assert(__traits(isSame, QualifierOf!(int), Alias)); +} + +@safe unittest +{ + import std.traits; + + static assert(packageName!packageName == "std"); +} + +@safe unittest +{ + import std.traits; + + static assert(packageName!moduleName == "std"); +} + +@safe unittest +{ + import std.traits; + + static assert(moduleName!moduleName == "std.traits"); +} + +@safe unittest +{ + import std.traits; + + static assert(fullyQualifiedName!fullyQualifiedName == "std.traits.fullyQualifiedName"); +} + +@safe unittest +{ + import std.traits; + + int foo(); + ReturnType!foo x; // x is declared as int +} + +@safe unittest +{ + import std.traits; + + int foo(int, long); + void bar(Parameters!foo); // declares void bar(int, long); + void abc(Parameters!foo[1]); // declares void abc(long); +} + +@safe unittest +{ + import std.traits; + + void foo(){} + static assert(arity!foo == 0); + void bar(uint){} + static assert(arity!bar == 1); + void variadicFoo(uint...){} + static assert(!__traits(compiles, arity!variadicFoo)); +} + +@safe unittest +{ + import std.traits; + + alias STC = ParameterStorageClass; // shorten the enum name + + void func(ref int ctx, out real result, in real param, void* ptr) + { + } + alias pstc = ParameterStorageClassTuple!func; + static assert(pstc.length == 4); // number of parameters + static assert(pstc[0] == STC.ref_); + static assert(pstc[1] == STC.out_); + version (none) + { + // TODO: When the DMD PR (dlang/dmd#11474) gets merged, + // remove the versioning and the second test + static assert(pstc[2] == STC.in_); + // This is the current behavior, before `in` is fixed to not be an alias + static assert(pstc[2] == STC.scope_); + } + static assert(pstc[3] == STC.none); +} + +@safe unittest +{ + import std.traits; + + static void func(ref int ctx, out real result); + + enum param1 = extractParameterStorageClassFlags!( + __traits(getParameterStorageClasses, func, 0) + ); + static assert(param1 == ParameterStorageClass.ref_); + + enum param2 = extractParameterStorageClassFlags!( + __traits(getParameterStorageClasses, func, 1) + ); + static assert(param2 == ParameterStorageClass.out_); + + enum param3 = extractParameterStorageClassFlags!( + __traits(getParameterStorageClasses, func, 0), + __traits(getParameterStorageClasses, func, 1) + ); + static assert(param3 == (ParameterStorageClass.ref_ | ParameterStorageClass.out_)); +} + +@safe unittest +{ + import std.traits; + + int foo(int num, string name, int); + static assert([ParameterIdentifierTuple!foo] == ["num", "name", ""]); +} + +@safe unittest +{ + import std.traits; + + int foo(int num, string name = "hello", int[] = [1,2,3], lazy int x = 0); + static assert(is(ParameterDefaults!foo[0] == void)); + static assert( ParameterDefaults!foo[1] == "hello"); + static assert( ParameterDefaults!foo[2] == [1,2,3]); + static assert( ParameterDefaults!foo[3] == 0); +} + +@safe unittest +{ + import std.traits; + + alias FA = FunctionAttribute; // shorten the enum name + + real func(real x) pure nothrow @safe + { + return x; + } + static assert(functionAttributes!func & FA.pure_); + static assert(functionAttributes!func & FA.safe); + static assert(!(functionAttributes!func & FA.trusted)); // not @trusted +} + +@safe unittest +{ + import std.traits; + + real func(real x) pure nothrow @safe; + static assert(hasFunctionAttributes!(func, "@safe", "pure")); + static assert(!hasFunctionAttributes!(func, "@trusted")); + + // for templates attributes are automatically inferred + bool myFunc(T)(T b) + { + return !b; + } + static assert(hasFunctionAttributes!(myFunc!bool, "@safe", "pure", "@nogc", "nothrow")); + static assert(!hasFunctionAttributes!(myFunc!bool, "shared")); +} + +@safe unittest +{ + import std.traits; + + @safe int add(int a, int b) {return a+b;} + @trusted int sub(int a, int b) {return a-b;} + @system int mul(int a, int b) {return a*b;} + + static assert( isSafe!add); + static assert( isSafe!sub); + static assert(!isSafe!mul); +} + +@safe unittest +{ + import std.traits; + + @safe int add(int a, int b) {return a+b;} + @trusted int sub(int a, int b) {return a-b;} + @system int mul(int a, int b) {return a*b;} + + static assert(!isUnsafe!add); + static assert(!isUnsafe!sub); + static assert( isUnsafe!mul); +} + +@safe unittest +{ + import std.traits; + + extern(D) void Dfunc() {} + extern(C) void Cfunc() {} + static assert(functionLinkage!Dfunc == "D"); + static assert(functionLinkage!Cfunc == "C"); + + string a = functionLinkage!Dfunc; + assert(a == "D"); + + auto fp = &Cfunc; + string b = functionLinkage!fp; + assert(b == "C"); +} + +@safe unittest +{ + import std.traits; + + void func() {} + static assert(variadicFunctionStyle!func == Variadic.no); + + extern(C) int printf(const char*, ...); + static assert(variadicFunctionStyle!printf == Variadic.c); +} + +@safe unittest +{ + import std.traits; + + class C + { + int value() @property => 0; + static string opCall() => "hi"; + } + static assert(is( typeof(C.value) == int )); + static assert(is( FunctionTypeOf!(C.value) == function )); + static assert(is( FunctionTypeOf!C == typeof(C.opCall) )); + + int function() fp; + alias IntFn = int(); + static assert(is( typeof(fp) == IntFn* )); + static assert(is( FunctionTypeOf!fp == IntFn )); +} + +@safe unittest +{ + import std.traits; + + alias ExternC(T) = SetFunctionAttributes!(T, "C", functionAttributes!T); + + auto assumePure(T)(T t) + if (isFunctionPointer!T || isDelegate!T) + { + enum attrs = functionAttributes!T | FunctionAttribute.pure_; + return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t; + } + + int f() + { + import core.thread : getpid; + return getpid(); + } + + int g() pure @trusted + { + auto pureF = assumePure(&f); + return pureF(); + } + assert(g() > 0); +} + +@safe unittest +{ + import std.traits; + + class C + { + int outer; + } + static assert(!isInnerClass!C); + + class Outer1 + { + class Inner1 { } + class Inner2 + { + int outer; + } + } + static assert(isInnerClass!(Outer1.Inner1)); + static assert(!isInnerClass!(Outer1.Inner2)); + + static class Outer2 + { + static class Inner + { + int outer; + } + } + static assert(!isInnerClass!(Outer2.Inner)); +} + +@safe unittest +{ + import std.traits; + + static struct S { } + static assert(!isNested!S); + + int i; + struct NestedStruct { void f() { ++i; } } + static assert(isNested!NestedStruct); +} + +@safe unittest +{ + import std.traits; + + static struct S { } + + int i; + struct NS { void f() { ++i; } } + + static assert(!hasNested!(S[2])); + static assert(hasNested!(NS[2])); +} + +@safe unittest +{ + import std.traits; + + import std.meta : AliasSeq; + struct S { int x; float y; } + static assert(is(Fields!S == AliasSeq!(int, float))); +} + +@safe unittest +{ + import std.traits; + + import std.meta : AliasSeq; + struct S { int x; float y; } + static assert(FieldNameTuple!S == AliasSeq!("x", "y")); + static assert(FieldNameTuple!int == AliasSeq!""); +} + +@safe unittest +{ + import std.traits; + + struct S1 { int a; float b; } + struct S2 { char[] a; union { S1 b; S1 * c; } } + alias R = RepresentationTypeTuple!S2; + assert(R.length == 4 + && is(R[0] == char[]) && is(R[1] == int) + && is(R[2] == float) && is(R[3] == S1*)); +} + +@safe unittest +{ + import std.traits; + + struct S1 { int a; Object b; } + struct S2 { string a; } + struct S3 { int a; immutable Object b; } + struct S4 { float[3] vals; } + static assert( hasAliasing!S1); + static assert(!hasAliasing!S2); + static assert(!hasAliasing!S3); + static assert(!hasAliasing!S4); +} + +@safe unittest +{ + import std.traits; + + static assert( hasIndirections!(int[string])); + static assert( hasIndirections!(void delegate())); + static assert( hasIndirections!(void delegate() immutable)); + static assert( hasIndirections!(immutable(void delegate()))); + static assert( hasIndirections!(immutable(void delegate() immutable))); + + static assert(!hasIndirections!(void function())); + static assert( hasIndirections!(void*[1])); + static assert(!hasIndirections!(byte[1])); +} + +@safe unittest +{ + import std.traits; + + struct S1 { int a; Object b; } + struct S2 { string a; } + struct S3 { int a; immutable Object b; } + static assert( hasUnsharedAliasing!S1); + static assert(!hasUnsharedAliasing!S2); + static assert(!hasUnsharedAliasing!S3); + + struct S4 { int a; shared Object b; } + struct S5 { char[] a; } + struct S6 { shared char[] b; } + struct S7 { float[3] vals; } + static assert(!hasUnsharedAliasing!S4); + static assert( hasUnsharedAliasing!S5); + static assert(!hasUnsharedAliasing!S6); + static assert(!hasUnsharedAliasing!S7); +} + +@safe unittest +{ + import std.traits; + + static assert(!hasElaborateCopyConstructor!int); + + static struct S1 { } + static struct S2 { this(this) {} } + static struct S3 { S2 field; } + static struct S4 { S3[1] field; } + static struct S5 { S3[] field; } + static struct S6 { S3[0] field; } + static struct S7 { @disable this(); S3 field; } + static assert(!hasElaborateCopyConstructor!S1); + static assert( hasElaborateCopyConstructor!S2); + static assert( hasElaborateCopyConstructor!(immutable S2)); + static assert( hasElaborateCopyConstructor!S3); + static assert( hasElaborateCopyConstructor!(S3[1])); + static assert(!hasElaborateCopyConstructor!(S3[0])); + static assert( hasElaborateCopyConstructor!S4); + static assert(!hasElaborateCopyConstructor!S5); + static assert(!hasElaborateCopyConstructor!S6); + static assert( hasElaborateCopyConstructor!S7); +} + +@safe unittest +{ + import std.traits; + + static assert(!hasElaborateAssign!int); + + static struct S { void opAssign(S) {} } + static assert( hasElaborateAssign!S); + static assert(!hasElaborateAssign!(const(S))); + + static struct S1 { void opAssign(ref S1) {} } + static struct S2 { void opAssign(int) {} } + static struct S3 { S s; } + static assert( hasElaborateAssign!S1); + static assert(!hasElaborateAssign!S2); + static assert( hasElaborateAssign!S3); + static assert( hasElaborateAssign!(S3[1])); + static assert(!hasElaborateAssign!(S3[0])); +} + +@safe unittest +{ + import std.traits; + + static assert(!hasElaborateDestructor!int); + + static struct S1 { } + static struct S2 { ~this() {} } + static struct S3 { S2 field; } + static struct S4 { S3[1] field; } + static struct S5 { S3[] field; } + static struct S6 { S3[0] field; } + static struct S7 { @disable this(); S3 field; } + static assert(!hasElaborateDestructor!S1); + static assert( hasElaborateDestructor!S2); + static assert( hasElaborateDestructor!(immutable S2)); + static assert( hasElaborateDestructor!S3); + static assert( hasElaborateDestructor!(S3[1])); + static assert(!hasElaborateDestructor!(S3[0])); + static assert( hasElaborateDestructor!S4); + static assert(!hasElaborateDestructor!S5); + static assert(!hasElaborateDestructor!S6); + static assert( hasElaborateDestructor!S7); +} + +@safe unittest +{ + import std.traits; + + static assert(!hasElaborateMove!int); + + static struct S1 { } + static struct S2 { void opPostMove(ref S2) {} } + static struct S3 { void opPostMove(inout ref S3) inout {} } + static struct S4 { void opPostMove(const ref S4) {} } + static struct S5 { void opPostMove(S5) {} } + static struct S6 { void opPostMove(int) {} } + static struct S7 { S3[1] field; } + static struct S8 { S3[] field; } + static struct S9 { S3[0] field; } + static struct S10 { @disable this(); S3 field; } + static assert(!hasElaborateMove!S1); + static assert( hasElaborateMove!S2); + static assert( hasElaborateMove!S3); + static assert( hasElaborateMove!(immutable S3)); + static assert( hasElaborateMove!S4); + static assert(!hasElaborateMove!S5); + static assert(!hasElaborateMove!S6); + static assert( hasElaborateMove!S7); + static assert(!hasElaborateMove!S8); + static assert(!hasElaborateMove!S9); + static assert( hasElaborateMove!S10); +} + +@safe unittest +{ + import std.traits; + + static assert(!hasMember!(int, "blah")); + struct S1 { int blah; } + struct S2 { int blah(){ return 0; } } + class C1 { int blah; } + class C2 { int blah(){ return 0; } } + static assert(hasMember!(S1, "blah")); + static assert(hasMember!(S2, "blah")); + static assert(hasMember!(C1, "blah")); + static assert(hasMember!(C2, "blah")); +} + +@safe unittest +{ + import std.traits; + + static struct S + { + static void sf() {} + void f() {} + + static int si; + int i; + } + + static assert( hasStaticMember!(S, "sf")); + static assert(!hasStaticMember!(S, "f")); + + static assert( hasStaticMember!(S, "si")); + static assert(!hasStaticMember!(S, "i")); + + static assert(!hasStaticMember!(S, "hello")); +} + +@safe unittest +{ + import std.traits; + + enum Sqrts : real + { + one = 1, + two = 1.41421, + three = 1.73205 + } + auto sqrts = [EnumMembers!Sqrts]; + assert(sqrts == [Sqrts.one, Sqrts.two, Sqrts.three]); +} + +@safe unittest +{ + import std.traits; + + // Returns i if e is the i-th enumerator of E. + static size_t rank(E)(E e) + if (is(E == enum)) + { + static foreach (i, member; EnumMembers!E) + { + if (e == member) + return i; + } + assert(0, "Not an enum member"); + } + + enum Mode + { + read = 1, + write = 2, + map = 4 + } + assert(rank(Mode.read) == 0); + assert(rank(Mode.write) == 1); + assert(rank(Mode.map) == 2); +} + +@safe unittest +{ + import std.traits; + + import std.conv : to; + class FooClass + { + string calledMethod; + void foo() @safe { calledMethod = "foo"; } + void bar() @safe { calledMethod = "bar"; } + void baz() @safe { calledMethod = "baz"; } + } + + enum FooEnum { foo, bar, baz } + + auto var = FooEnum.bar; + auto fooObj = new FooClass(); + s: final switch (var) + { + static foreach (member; EnumMembers!FooEnum) + { + case member: // Generate a case for each enum value. + // Call fooObj.{name of enum value}(). + __traits(getMember, fooObj, to!string(member))(); + break s; + } + } + // As we pass in FooEnum.bar, the bar() method gets called. + assert(fooObj.calledMethod == "bar"); +} + +@safe unittest +{ + import std.traits; + + import std.meta : AliasSeq; + + interface I1 { } + interface I2 { } + interface I12 : I1, I2 { } + static assert(is(BaseTypeTuple!I12 == AliasSeq!(I1, I2))); + + interface I3 : I1 { } + interface I123 : I1, I2, I3 { } + static assert(is(BaseTypeTuple!I123 == AliasSeq!(I1, I2, I3))); +} + +@safe unittest +{ + import std.traits; + + import std.meta : AliasSeq; + + class C1 { } + class C2 : C1 { } + class C3 : C2 { } + static assert(!BaseClassesTuple!Object.length); + static assert(is(BaseClassesTuple!C1 == AliasSeq!(Object))); + static assert(is(BaseClassesTuple!C2 == AliasSeq!(C1, Object))); + static assert(is(BaseClassesTuple!C3 == AliasSeq!(C2, C1, Object))); +} + +@safe unittest +{ + import std.traits; + + interface I1 {} + interface I2 {} + class A : I1, I2 {} + class B : A, I1 {} + class C : B {} + + alias TL = InterfacesTuple!C; + static assert(is(TL[0] == I1) && is(TL[1] == I2)); +} + +@safe unittest +{ + import std.traits; + + interface J1 {} + interface J2 {} + class B1 {} + class B2 : B1, J1, J2 {} + class B3 : B2, J1 {} + alias TL = TransitiveBaseTypeTuple!B3; + assert(TL.length == 5); + assert(is (TL[0] == B2)); + assert(is (TL[1] == B1)); + assert(is (TL[2] == Object)); + assert(is (TL[3] == J1)); + assert(is (TL[4] == J2)); + + assert(TransitiveBaseTypeTuple!Object.length == 0); +} + +@safe unittest +{ + import std.traits; + + interface I { I foo(); } + class B + { + real foo(real v) { return v; } + } + class C : B, I + { + override C foo() { return this; } // covariant overriding of I.foo() + } + alias foos = MemberFunctionsTuple!(C, "foo"); + static assert(foos.length == 2); + static assert(__traits(isSame, foos[0], C.foo)); + static assert(__traits(isSame, foos[1], B.foo)); +} + +@safe unittest +{ + import std.traits; + + struct Foo(T, U) {} + static assert(__traits(isSame, TemplateOf!(Foo!(int, real)), Foo)); +} + +@safe unittest +{ + import std.traits; + + import std.meta : AliasSeq; + + struct Foo(T, U) {} + static assert(is(TemplateArgsOf!(Foo!(int, real)) == AliasSeq!(int, real))); +} + +@safe unittest +{ + import std.traits; + + class A { byte b; } + class B { long l; } + + // As class instance always has a hidden pointer + static assert(classInstanceAlignment!A == (void*).alignof); + static assert(classInstanceAlignment!B == long.alignof); +} + +@safe unittest +{ + import std.traits; + + alias X = CommonType!(int, long, short); + assert(is(X == long)); + alias Y = CommonType!(int, char[], short); + assert(is(Y == void)); +} + +@safe unittest +{ + import std.traits; + + static assert(is(CommonType!(3) == int)); + static assert(is(CommonType!(double, 4, float) == double)); + static assert(is(CommonType!(string, char[]) == const(char)[])); + static assert(is(CommonType!(3, 3U) == uint)); + static assert(is(CommonType!(double, int) == double)); +} + +@safe unittest +{ + import std.traits; + + import std.meta : AliasSeq; + + static assert(is(AllImplicitConversionTargets!(ulong) == AliasSeq!(long, float, double, real))); + static assert(is(AllImplicitConversionTargets!(int) == AliasSeq!(dchar, uint, long, ulong, float, double, real))); + static assert(is(AllImplicitConversionTargets!(float) == AliasSeq!(double, real))); + static assert(is(AllImplicitConversionTargets!(double) == AliasSeq!(float, real))); + + static assert(is(AllImplicitConversionTargets!(char) == + AliasSeq!(byte, ubyte, short, ushort, wchar, int, dchar, uint, long, + ulong, float, double, real) + )); + static assert(is(AllImplicitConversionTargets!(wchar) == AliasSeq!( + short, ushort, dchar, int, uint, long, ulong, float, double, real + ))); + static assert(is(AllImplicitConversionTargets!(dchar) == AliasSeq!( + int, uint, long, ulong, float, double, real + ))); + + static assert(is(AllImplicitConversionTargets!(string) == AliasSeq!(const(char)[]))); + static assert(is(AllImplicitConversionTargets!(int*) == AliasSeq!(void*))); + + interface A {} + interface B {} + class C : A, B {} + + static assert(is(AllImplicitConversionTargets!(C) == AliasSeq!(Object, A, B))); + static assert(is(AllImplicitConversionTargets!(const C) == AliasSeq!(const Object, const A, const B))); + static assert(is(AllImplicitConversionTargets!(immutable C) == AliasSeq!( + immutable Object, immutable A, immutable B + ))); + + interface I : A, B {} + + static assert(is(AllImplicitConversionTargets!(I) == AliasSeq!(A, B))); + static assert(is(AllImplicitConversionTargets!(const I) == AliasSeq!(const A, const B))); + static assert(is(AllImplicitConversionTargets!(immutable I) == AliasSeq!( + immutable A, immutable B + ))); +} + +@safe unittest +{ + import std.traits; + + static assert( isImplicitlyConvertible!(immutable(char), char)); + static assert( isImplicitlyConvertible!(const(char), char)); + static assert( isImplicitlyConvertible!(char, wchar)); + static assert(!isImplicitlyConvertible!(wchar, char)); + + static assert(!isImplicitlyConvertible!(const(ushort), ubyte)); + static assert(!isImplicitlyConvertible!(const(uint), ubyte)); + static assert(!isImplicitlyConvertible!(const(ulong), ubyte)); + + static assert(!isImplicitlyConvertible!(const(char)[], string)); + static assert( isImplicitlyConvertible!(string, const(char)[])); +} + +@safe unittest +{ + import std.traits; + + // Mutable and immmutable both convert to const... + static assert( isQualifierConvertible!(char, const(char))); + static assert( isQualifierConvertible!(immutable(char), const(char))); + // ...but const does not convert back to mutable or immutable + static assert(!isQualifierConvertible!(const(char), char)); + static assert(!isQualifierConvertible!(const(char), immutable(char))); +} + +@safe unittest +{ + import std.traits; + + static assert( isAssignable!(long, int)); + static assert(!isAssignable!(int, long)); + static assert( isAssignable!(const(char)[], string)); + static assert(!isAssignable!(string, char[])); + + // int is assignable to int + static assert( isAssignable!int); + + // immutable int is not assignable to immutable int + static assert(!isAssignable!(immutable int)); +} + +@safe unittest +{ + import std.traits; + + struct S1 + { + void opAssign(S1); + } + + struct S2 + { + void opAssign(ref S2); + } + + static assert( isRvalueAssignable!(long, int)); + static assert(!isRvalueAssignable!(int, long)); + static assert( isRvalueAssignable!S1); + static assert(!isRvalueAssignable!S2); +} + +@safe unittest +{ + import std.traits; + + struct S1 + { + void opAssign(S1); + } + + struct S2 + { + void opAssign(ref S2); + } + + static assert( isLvalueAssignable!(long, int)); + static assert(!isLvalueAssignable!(int, long)); + static assert( isLvalueAssignable!S1); + static assert( isLvalueAssignable!S2); +} + +@safe unittest +{ + import std.traits; + + interface I { I clone(); } + interface J { J clone(); } + class C : I + { + override C clone() // covariant overriding of I.clone() + { + return new C; + } + } + + // C.clone() can override I.clone(), indeed. + static assert(isCovariantWith!(typeof(C.clone), typeof(I.clone))); + + // C.clone() can't override J.clone(); the return type C is not implicitly + // convertible to J. + static assert(!isCovariantWith!(typeof(C.clone), typeof(J.clone))); +} + +@system unittest +{ + import std.traits; + + static int f(int); + static assert(is(typeof(f(rvalueOf!int)) == int)); +} + +@system unittest +{ + import std.traits; + + static bool f(ref int); + static assert(is(typeof(f(lvalueOf!int)) == bool)); +} + +@safe unittest +{ + import std.traits; + + static assert( isBoolean!bool); + enum EB : bool { a = true } + static assert( isBoolean!EB); + + struct SubTypeOfBool + { + bool val; + alias val this; + } + static assert(!isBoolean!(SubTypeOfBool)); +} + +@safe unittest +{ + import std.traits; + + static assert( + isIntegral!byte && + isIntegral!short && + isIntegral!int && + isIntegral!long && + isIntegral!(const(long)) && + isIntegral!(immutable(long)) + ); + + static assert( + !isIntegral!bool && + !isIntegral!char && + !isIntegral!double + ); + + // types which act as integral values do not pass + struct S + { + int val; + alias val this; + } + + static assert(!isIntegral!S); +} + +@safe unittest +{ + import std.traits; + + static assert( + isFloatingPoint!float && + isFloatingPoint!double && + isFloatingPoint!real && + isFloatingPoint!(const(real)) && + isFloatingPoint!(immutable(real)) + ); + + static assert(!isFloatingPoint!int); + + // types which act as floating point values do not pass + struct S + { + float val; + alias val this; + } + + static assert(!isFloatingPoint!S); +} + +@safe unittest +{ + import std.traits; + + static assert( + isNumeric!byte && + isNumeric!short && + isNumeric!int && + isNumeric!long && + isNumeric!float && + isNumeric!double && + isNumeric!real && + isNumeric!(const(real)) && + isNumeric!(immutable(real)) + ); + + static assert( + !isNumeric!void && + !isNumeric!bool && + !isNumeric!char && + !isNumeric!wchar && + !isNumeric!dchar + ); + + // types which act as numeric values do not pass + struct S + { + int val; + alias val this; + } + + static assert(!isNumeric!S); +} + +@safe unittest +{ + import std.traits; + + static assert(!isScalarType!void); + static assert( isScalarType!(immutable(byte))); + static assert( isScalarType!(immutable(ushort))); + static assert( isScalarType!(immutable(int))); + static assert( isScalarType!(ulong)); + static assert( isScalarType!(shared(float))); + static assert( isScalarType!(shared(const bool))); + static assert( isScalarType!(const(char))); + static assert( isScalarType!(wchar)); + static assert( isScalarType!(const(dchar))); + static assert( isScalarType!(const(double))); + static assert( isScalarType!(const(real))); +} + +@safe unittest +{ + import std.traits; + + static assert(isBasicType!void); + static assert(isBasicType!(const(void))); + static assert(isBasicType!(shared(void))); + static assert(isBasicType!(immutable(void))); + static assert(isBasicType!(shared const(void))); + static assert(isBasicType!(shared inout(void))); + static assert(isBasicType!(shared inout const(void))); + static assert(isBasicType!(inout(void))); + static assert(isBasicType!(inout const(void))); + static assert(isBasicType!(immutable(int))); + static assert(isBasicType!(shared(float))); + static assert(isBasicType!(shared(const bool))); + static assert(isBasicType!(const(dchar))); +} + +@safe unittest +{ + import std.traits; + + static assert( + isUnsigned!uint && + isUnsigned!ulong + ); + + static assert( + !isUnsigned!char && + !isUnsigned!int && + !isUnsigned!long && + !isUnsigned!char && + !isUnsigned!wchar && + !isUnsigned!dchar + ); +} + +@safe unittest +{ + import std.traits; + + static assert( + isSigned!int && + isSigned!long + ); + + static assert( + !isSigned!uint && + !isSigned!ulong + ); +} + +@safe unittest +{ + import std.traits; + + //Char types + static assert( isSomeChar!char); + static assert( isSomeChar!wchar); + static assert( isSomeChar!dchar); + static assert( isSomeChar!(typeof('c'))); + static assert( isSomeChar!(immutable char)); + static assert( isSomeChar!(const dchar)); + + //Non char types + static assert(!isSomeChar!int); + static assert(!isSomeChar!byte); + static assert(!isSomeChar!string); + static assert(!isSomeChar!wstring); + static assert(!isSomeChar!dstring); + static assert(!isSomeChar!(char[4])); +} + +@safe unittest +{ + import std.traits; + + //String types + static assert( isSomeString!string); + static assert( isSomeString!(wchar[])); + static assert( isSomeString!(dchar[])); + static assert( isSomeString!(typeof("aaa"))); + static assert( isSomeString!(const(char)[])); + + //Non string types + static assert(!isSomeString!int); + static assert(!isSomeString!(int[])); + static assert(!isSomeString!(byte[])); + static assert(!isSomeString!(typeof(null))); + static assert(!isSomeString!(char[4])); + + enum ES : string { a = "aaa", b = "bbb" } + static assert(!isSomeString!ES); + + static struct Stringish + { + string str; + alias str this; + } + static assert(!isSomeString!Stringish); +} + +@safe unittest +{ + import std.traits; + + static assert(isNarrowString!string); + static assert(isNarrowString!wstring); + static assert(isNarrowString!(char[])); + static assert(isNarrowString!(wchar[])); + + static assert(!isNarrowString!dstring); + static assert(!isNarrowString!(dchar[])); + + static assert(!isNarrowString!(typeof(null))); + static assert(!isNarrowString!(char[4])); + + enum ES : string { a = "aaa", b = "bbb" } + static assert(!isNarrowString!ES); + + static struct Stringish + { + string str; + alias str this; + } + static assert(!isNarrowString!Stringish); +} + +@safe unittest +{ + import std.traits; + + static assert(isOrderingComparable!int); + static assert(isOrderingComparable!string); + + static struct Foo {} + static assert(!isOrderingComparable!Foo); + + static struct Bar + { + int a; + auto opCmp(Bar b1) const { return a - b1.a; } + } + + Bar b1 = Bar(5); + Bar b2 = Bar(7); + assert(isOrderingComparable!Bar && b2 > b1); +} + +@safe unittest +{ + import std.traits; + + static struct AliasedString + { + string s; + alias s this; + } + + enum StringEnum { a = "foo" } + + assert(!isConvertibleToString!string); + assert(isConvertibleToString!AliasedString); + assert(isConvertibleToString!StringEnum); + assert(isConvertibleToString!(char[25])); + assert(!isConvertibleToString!(char[])); +} + +@safe unittest +{ + import std.traits; + + static struct Stringish + { + string s; + alias s this; + } + static assert(isAutodecodableString!wstring); + static assert(isAutodecodableString!Stringish); + static assert(!isAutodecodableString!dstring); + + enum E : const(char)[3] { X = "abc" } + enum F : const(char)[] { X = "abc" } + enum G : F { X = F.init } + + static assert(isAutodecodableString!(char[])); + static assert(!isAutodecodableString!(E)); + static assert(isAutodecodableString!(F)); + static assert(isAutodecodableString!(G)); + + struct Stringish2 + { + Stringish s; + alias s this; + } + + enum H : Stringish { X = Stringish() } + enum I : Stringish2 { X = Stringish2() } + + static assert(isAutodecodableString!(H)); + static assert(isAutodecodableString!(I)); + + static assert(!isAutodecodableString!(noreturn[])); + static assert(!isAutodecodableString!(immutable(noreturn)[])); +} + +@safe unittest +{ + import std.traits; + + static assert( isStaticArray!(int[3])); + static assert( isStaticArray!(const(int)[5])); + static assert( isStaticArray!(const(int)[][5])); + + static assert(!isStaticArray!(const(int)[])); + static assert(!isStaticArray!(immutable(int)[])); + static assert(!isStaticArray!(const(int)[4][])); + static assert(!isStaticArray!(int[])); + static assert(!isStaticArray!(int[char])); + static assert(!isStaticArray!(int[1][])); + static assert(!isStaticArray!(int[int])); + static assert(!isStaticArray!int); +} + +@safe unittest +{ + import std.traits; + + static assert( isDynamicArray!(int[])); + static assert( isDynamicArray!(string)); + static assert( isDynamicArray!(long[3][])); + + static assert(!isDynamicArray!(int[5])); + static assert(!isDynamicArray!(typeof(null))); +} + +@safe unittest +{ + import std.traits; + + static assert( isArray!(int[])); + static assert( isArray!(int[5])); + static assert( isArray!(string)); + + static assert(!isArray!uint); + static assert(!isArray!(uint[uint])); + static assert(!isArray!(typeof(null))); +} + +@safe unittest +{ + import std.traits; + + struct S; + + static assert( isAssociativeArray!(int[string])); + static assert( isAssociativeArray!(S[S])); + static assert(!isAssociativeArray!(string[])); + static assert(!isAssociativeArray!S); + static assert(!isAssociativeArray!(int[4])); +} + +@safe unittest +{ + import std.traits; + + class C; + union U; + struct S; + interface I; + + static assert( isBuiltinType!void); + static assert( isBuiltinType!string); + static assert( isBuiltinType!(int[])); + static assert( isBuiltinType!(C[string])); + static assert( isBuiltinType!(typeof(null))); + static assert(!isBuiltinType!C); + static assert(!isBuiltinType!U); + static assert(!isBuiltinType!S); + static assert(!isBuiltinType!I); + static assert(!isBuiltinType!(void delegate(int))); +} + +@safe unittest +{ + import std.traits; + + static if (is(__vector(float[4]))) + { + alias SimdVec = __vector(float[4]); + static assert(isSIMDVector!(__vector(float[4]))); + static assert(isSIMDVector!SimdVec); + } + static assert(!isSIMDVector!uint); + static assert(!isSIMDVector!(float[4])); +} + +@safe unittest +{ + import std.traits; + + void fun(); + + static assert( isPointer!(int*)); + static assert( isPointer!(int function())); + static assert(!isPointer!int); + static assert(!isPointer!string); + static assert(!isPointer!(typeof(null))); + static assert(!isPointer!(typeof(fun))); + static assert(!isPointer!(int delegate())); +} + +@safe unittest +{ + import std.traits; + + static assert(is(PointerTarget!(int*) == int)); + static assert(is(PointerTarget!(void*) == void)); +} + +@safe unittest +{ + import std.traits; + + class C {} + union U {} + struct S {} + interface I {} + + static assert( isAggregateType!C); + static assert( isAggregateType!U); + static assert( isAggregateType!S); + static assert( isAggregateType!I); + static assert(!isAggregateType!void); + static assert(!isAggregateType!string); + static assert(!isAggregateType!(int[])); + static assert(!isAggregateType!(C[string])); + static assert(!isAggregateType!(void delegate(int))); + + enum ES : S { a = S.init } + enum EC : C { a = C.init } + enum EI : I { a = I.init } + enum EU : U { a = U.init } + + static assert( isAggregateType!ES); + static assert( isAggregateType!EC); + static assert( isAggregateType!EI); + static assert( isAggregateType!EU); +} + +@safe unittest +{ + import std.traits; + + struct OpApply + { + int opApply(scope int delegate(ref uint) dg) { assert(0); } + } + + struct Range + { + @property uint front() { assert(0); } + void popFront() { assert(0); } + enum bool empty = false; + } + + static assert( isIterable!(uint[])); + static assert( isIterable!OpApply); + static assert( isIterable!(uint[string])); + static assert( isIterable!Range); + + static assert(!isIterable!uint); +} + +@safe unittest +{ + import std.traits; + + static assert( isMutable!int); + static assert( isMutable!string); + static assert( isMutable!(shared int)); + static assert( isMutable!(shared const(int)[])); + + static assert(!isMutable!(const int)); + static assert(!isMutable!(inout int)); + static assert(!isMutable!(shared(const int))); + static assert(!isMutable!(shared(inout int))); + static assert(!isMutable!(immutable string)); +} + +@safe unittest +{ + import std.traits; + + static struct Foo(T...) { } + static struct Bar(T...) { } + static struct Doo(T) { } + static struct ABC(int x) { } + static void fun(T)() { } + template templ(T) { } + + static assert(isInstanceOf!(Foo, Foo!int)); + static assert(!isInstanceOf!(Foo, Bar!int)); + static assert(!isInstanceOf!(Foo, int)); + static assert(isInstanceOf!(Doo, Doo!int)); + static assert(isInstanceOf!(ABC, ABC!1)); + static assert(!isInstanceOf!(Foo, Foo)); + static assert(isInstanceOf!(fun, fun!int)); + static assert(isInstanceOf!(templ, templ!int)); +} + +@safe unittest +{ + import std.traits; + + static struct A(T = void) + { + // doesn't work as expected, only accepts A when T = void + void func(B)(B b) + if (isInstanceOf!(A, B)) {} + + // correct behavior + void method(B)(B b) + if (isInstanceOf!(TemplateOf!(A), B)) {} + } + + A!(void) a1; + A!(void) a2; + A!(int) a3; + + static assert(!__traits(compiles, a1.func(a3))); + static assert( __traits(compiles, a1.method(a2))); + static assert( __traits(compiles, a1.method(a3))); +} + +@safe unittest +{ + import std.traits; + + static assert(isExpressions!(1, 2.0, "a")); + static assert(!isExpressions!(int, double, string)); + static assert(!isExpressions!(int, 2.0, "a")); +} + +@safe unittest +{ + import std.traits; + + static assert(isTypeTuple!(int, float, string)); + static assert(!isTypeTuple!(1, 2.0, "a")); + static assert(!isTypeTuple!(1, double, string)); +} + +@safe unittest +{ + import std.traits; + + static void foo() {} + void bar() {} + + auto fpfoo = &foo; + static assert( isFunctionPointer!fpfoo); + static assert( isFunctionPointer!(void function())); + + auto dgbar = &bar; + static assert(!isFunctionPointer!dgbar); + static assert(!isFunctionPointer!(void delegate())); + static assert(!isFunctionPointer!foo); + static assert(!isFunctionPointer!bar); + + static assert( isFunctionPointer!((int a) {})); +} + +@safe unittest +{ + import std.traits; + + static void sfunc() { } + int x; + void func() { x++; } + + int delegate() dg; + assert(isDelegate!dg); + assert(isDelegate!(int delegate())); + assert(isDelegate!(typeof(&func))); + + int function() fp; + assert(!isDelegate!fp); + assert(!isDelegate!(int function())); + assert(!isDelegate!(typeof(&sfunc))); +} + +@safe unittest +{ + import std.traits; + + static real func(ref int) { return 0; } + static void prop() @property { } + class C + { + real method(ref int) { return 0; } + real prop() @property { return 0; } + } + auto c = new C; + auto fp = &func; + auto dg = &c.method; + + static assert( isSomeFunction!func); + static assert( isSomeFunction!prop); + static assert( isSomeFunction!(C.method)); + static assert( isSomeFunction!(C.prop)); + static assert( isSomeFunction!(c.prop)); + static assert( isSomeFunction!fp); + static assert( isSomeFunction!dg); + + real val; + static assert(!isSomeFunction!int); + static assert(!isSomeFunction!val); +} + +@safe unittest +{ + import std.traits; + + void f() { } + int g(int x) { return x; } + + static assert( isCallable!f); + static assert( isCallable!g); + + class C { int opCall(int) { return 0; } } + auto c = new C; + struct S { static int opCall(int) { return 0; } } + interface I { real value() @property; } + + static assert( isCallable!c); + static assert( isCallable!(c.opCall)); + static assert( isCallable!S); + static assert( isCallable!(I.value)); + static assert( isCallable!((int a) { return a; })); + + static assert(!isCallable!I); +} + +@safe unittest +{ + import std.traits; + + void f()() { } + T g(T = int)(T x) { return x; } + struct S1 { static void opCall()() { } } + struct S2 { static T opCall(T = int)(T x) {return x; } } + + static assert( isCallable!f); + static assert( isCallable!g); + static assert( isCallable!S1); + static assert( isCallable!S2); +} + +@safe unittest +{ + import std.traits; + + static struct Wrapper + { + void f() { } + int f(int x) { return x; } + + void g()() { } + T g(T = int)(T x) { return x; } + } + + static assert(isCallable!(Wrapper.f)); + static assert(isCallable!(Wrapper.g)); +} + +@safe unittest +{ + import std.traits; + + struct S { void foo() { } } + class C { void foo() { } } + class AC { abstract void foo(); } + static assert(!isAbstractFunction!(int)); + static assert(!isAbstractFunction!(S.foo)); + static assert(!isAbstractFunction!(C.foo)); + static assert( isAbstractFunction!(AC.foo)); +} + +@safe unittest +{ + import std.traits; + + struct S { void bar() { } } + final class FC { void foo(); } + class C + { + void bar() { } + final void foo(); + } + static assert(!isFinalFunction!(int)); + static assert(!isFinalFunction!(S.bar)); + static assert( isFinalFunction!(FC.foo)); + static assert(!isFinalFunction!(C.bar)); + static assert( isFinalFunction!(C.foo)); +} + +@safe unittest +{ + import std.traits; + + static void f() {} + static void fun() + { + int i; + int f() { return i; } + + static assert(isNestedFunction!(f)); + } + + static assert(!isNestedFunction!f); +} + +@safe unittest +{ + import std.traits; + + struct S { } + class C { } + abstract class AC { } + static assert(!isAbstractClass!S); + static assert(!isAbstractClass!C); + static assert( isAbstractClass!AC); + C c; + static assert(!isAbstractClass!c); + AC ac; + static assert( isAbstractClass!ac); +} + +@safe unittest +{ + import std.traits; + + class C { } + abstract class AC { } + final class FC1 : C { } + final class FC2 { } + static assert(!isFinalClass!C); + static assert(!isFinalClass!AC); + static assert( isFinalClass!FC1); + static assert( isFinalClass!FC2); + C c; + static assert(!isFinalClass!c); + FC1 fc1; + static assert( isFinalClass!fc1); +} + +@safe unittest +{ + import std.traits; + + static assert(is(Unconst!int == int)); + static assert(is(Unconst!(const int) == int)); + static assert(is(Unconst!(immutable int) == int)); + static assert(is(Unconst!(shared int) == shared int)); + static assert(is(Unconst!(shared(const int)) == shared int)); +} + +@safe unittest +{ + import std.traits; + + static assert(is(Unshared!int == int)); + static assert(is(Unshared!(const int) == const int)); + static assert(is(Unshared!(immutable int) == immutable int)); + + static assert(is(Unshared!(shared int) == int)); + static assert(is(Unshared!(shared(const int)) == const int)); + + static assert(is(Unshared!(shared(int[])) == shared(int)[])); +} + +@safe unittest +{ + import std.traits; + + static assert(is(Unqual!int == int)); + static assert(is(Unqual!(const int) == int)); + static assert(is(Unqual!(immutable int) == int)); + static assert(is(Unqual!(shared int) == int)); + static assert(is(Unqual!(shared(const int)) == int)); +} + +@safe unittest +{ + import std.traits; + + static assert(is(CopyTypeQualifiers!(inout const real, int) == inout const int)); +} + +@safe unittest +{ + import std.traits; + + const(int) i; + CopyConstness!(typeof(i), float) f; + assert( is(typeof(f) == const float)); + + CopyConstness!(char, uint) u; + assert( is(typeof(u) == uint)); + + //The 'shared' qualifier will not be copied + assert(!is(CopyConstness!(shared bool, int) == shared int)); + + //But the constness will be + assert( is(CopyConstness!(shared const real, double) == const double)); + + //Careful, const(int)[] is a mutable array of const(int) + alias MutT = CopyConstness!(const(int)[], int); + assert(!is(MutT == const(int))); + + //Okay, const(int[]) applies to array and contained ints + alias CstT = CopyConstness!(const(int[]), int); + assert( is(CstT == const(int))); +} + +@safe unittest +{ + import std.traits; + + static assert(is(ForeachType!(uint[]) == uint)); + static assert(is(ForeachType!string == immutable(char))); + static assert(is(ForeachType!(string[string]) == string)); + static assert(is(ForeachType!(inout(int)[]) == inout(int))); +} + +@safe unittest +{ + import std.traits; + + enum E : real { a = 0 } // NOTE: explicit initialization to 0 required during Enum init deprecation cycle + enum F : E { a = E.a } + alias G = const(F); + static assert(is(OriginalType!E == real)); + static assert(is(OriginalType!F == real)); + static assert(is(OriginalType!G == const real)); +} + +@safe unittest +{ + import std.traits; + + alias Hash = int[string]; + static assert(is(KeyType!Hash == string)); + static assert(is(ValueType!Hash == int)); + KeyType!Hash str = "a"; // str is declared as string + ValueType!Hash num = 1; // num is declared as int +} + +@safe unittest +{ + import std.traits; + + alias Hash = int[string]; + static assert(is(KeyType!Hash == string)); + static assert(is(ValueType!Hash == int)); + KeyType!Hash str = "a"; // str is declared as string + ValueType!Hash num = 1; // num is declared as int +} + +@safe unittest +{ + import std.traits; + + static assert(is(Unsigned!(int) == uint)); + static assert(is(Unsigned!(long) == ulong)); + static assert(is(Unsigned!(const short) == const ushort)); + static assert(is(Unsigned!(immutable byte) == immutable ubyte)); + static assert(is(Unsigned!(inout int) == inout uint)); +} + +@safe unittest +{ + import std.traits; + + static assert(is(Unsigned!(uint) == uint)); + static assert(is(Unsigned!(const uint) == const uint)); + + static assert(is(Unsigned!(ubyte) == ubyte)); + static assert(is(Unsigned!(immutable uint) == immutable uint)); +} + +@safe unittest +{ + import std.traits; + + static assert(is(Largest!(uint, ubyte, ushort, real) == real)); + static assert(is(Largest!(ulong, double) == ulong)); + static assert(is(Largest!(double, ulong) == double)); + static assert(is(Largest!(uint, byte, double, short) == double)); + static if (is(ucent)) + static assert(is(Largest!(uint, ubyte, ucent, ushort) == ucent)); +} + +@safe unittest +{ + import std.traits; + + alias S1 = Signed!uint; + static assert(is(S1 == int)); + alias S2 = Signed!(const(uint)); + static assert(is(S2 == const(int))); + alias S3 = Signed!(immutable(uint)); + static assert(is(S3 == immutable(int))); + static if (is(ucent)) + { + alias S4 = Signed!ucent; + static assert(is(S4 == cent)); + } +} + +@safe unittest +{ + import std.traits; + + static assert(mostNegative!float == -float.max); + static assert(mostNegative!double == -double.max); + static assert(mostNegative!real == -real.max); + static assert(mostNegative!bool == false); +} + +@safe unittest +{ + import std.traits; + + import std.meta : AliasSeq; + + static foreach (T; AliasSeq!(bool, byte, short, int, long)) + static assert(mostNegative!T == T.min); + + static foreach (T; AliasSeq!(ubyte, ushort, uint, ulong, char, wchar, dchar)) + static assert(mostNegative!T == 0); +} + +@safe unittest +{ + import std.traits; + + ubyte a = 3, b = 5; + static assert(is(typeof(a * b) == Promoted!ubyte)); + static assert(is(Promoted!ubyte == int)); + + static assert(is(Promoted!(shared(bool)) == shared(int))); + static assert(is(Promoted!(const(int)) == const(int))); + static assert(is(Promoted!double == double)); +} + +@safe unittest +{ + import std.traits; + + import std.meta : AliasSeq; + alias TL = staticMap!(mangledName, int, const int, immutable int); + static assert(TL == AliasSeq!("i", "xi", "yi")); +} + +@safe unittest +{ + import std.traits; + + // can select types + static assert(is(Select!(true, int, long) == int)); + static assert(is(Select!(false, int, long) == long)); + static struct Foo {} + static assert(is(Select!(false, const(int), const(Foo)) == const(Foo))); + + // can select symbols + int a = 1; + int b = 2; + alias selA = Select!(true, a, b); + alias selB = Select!(false, a, b); + assert(selA == 1); + assert(selB == 2); + + // can select (compile-time) expressions + enum val = Select!(false, -4, 9 - 6); + static assert(val == 3); +} + +@safe unittest +{ + import std.traits; + + real run() { return 0; } + int fail() { assert(0); } + auto a = select!true(run(), fail()); + auto b = select!false(fail(), run()); + static assert(is(typeof(a) == real)); + static assert(is(typeof(b) == real)); +} + +@safe unittest +{ + import std.traits; + + enum E; + struct S {} + + @("alpha") int a; + static assert(hasUDA!(a, "alpha")); + static assert(!hasUDA!(a, S)); + static assert(!hasUDA!(a, E)); + + @(E) int b; + static assert(!hasUDA!(b, "alpha")); + static assert(!hasUDA!(b, S)); + static assert(hasUDA!(b, E)); + + @E int c; + static assert(!hasUDA!(c, "alpha")); + static assert(!hasUDA!(c, S)); + static assert(hasUDA!(c, E)); + + @(S, E) int d; + static assert(!hasUDA!(d, "alpha")); + static assert(hasUDA!(d, S)); + static assert(hasUDA!(d, E)); + + @S int e; + static assert(!hasUDA!(e, "alpha")); + static assert(hasUDA!(e, S)); + static assert(!hasUDA!(e, S())); + static assert(!hasUDA!(e, E)); + + @S() int f; + static assert(!hasUDA!(f, "alpha")); + static assert(hasUDA!(f, S)); + static assert(hasUDA!(f, S())); + static assert(!hasUDA!(f, E)); + + @(S, E, "alpha") int g; + static assert(hasUDA!(g, "alpha")); + static assert(hasUDA!(g, S)); + static assert(hasUDA!(g, E)); + + @(100) int h; + static assert(hasUDA!(h, 100)); + + struct Named { string name; } + + @Named("abc") int i; + static assert(hasUDA!(i, Named)); + static assert(hasUDA!(i, Named("abc"))); + static assert(!hasUDA!(i, Named("def"))); + + struct AttrT(T) + { + string name; + T value; + } + + @AttrT!int("answer", 42) int j; + static assert(hasUDA!(j, AttrT)); + static assert(hasUDA!(j, AttrT!int)); + static assert(!hasUDA!(j, AttrT!string)); + + @AttrT!string("hello", "world") int k; + static assert(hasUDA!(k, AttrT)); + static assert(!hasUDA!(k, AttrT!int)); + static assert(hasUDA!(k, AttrT!string)); + + struct FuncAttr(alias f) { alias func = f; } + static int fourtyTwo() { return 42; } + static size_t getLen(string s) { return s.length; } + + @FuncAttr!getLen int l; + static assert(hasUDA!(l, FuncAttr)); + static assert(!hasUDA!(l, FuncAttr!fourtyTwo)); + static assert(hasUDA!(l, FuncAttr!getLen)); + static assert(!hasUDA!(l, FuncAttr!fourtyTwo())); + static assert(!hasUDA!(l, FuncAttr!getLen())); + + @FuncAttr!getLen() int m; + static assert(hasUDA!(m, FuncAttr)); + static assert(!hasUDA!(m, FuncAttr!fourtyTwo)); + static assert(hasUDA!(m, FuncAttr!getLen)); + static assert(!hasUDA!(m, FuncAttr!fourtyTwo())); + static assert(hasUDA!(m, FuncAttr!getLen())); +} + +@safe unittest +{ + import std.traits; + + struct Attr + { + string name; + int value; + } + + @Attr("Answer", 42) int a; + static assert(getUDAs!(a, Attr).length == 1); + static assert(getUDAs!(a, Attr)[0].name == "Answer"); + static assert(getUDAs!(a, Attr)[0].value == 42); + + @(Attr("Answer", 42), "string", 9999) int b; + static assert(getUDAs!(b, Attr).length == 1); + static assert(getUDAs!(b, Attr)[0].name == "Answer"); + static assert(getUDAs!(b, Attr)[0].value == 42); + + @Attr("Answer", 42) @Attr("Pi", 3) int c; + static assert(getUDAs!(c, Attr).length == 2); + static assert(getUDAs!(c, Attr)[0].name == "Answer"); + static assert(getUDAs!(c, Attr)[0].value == 42); + static assert(getUDAs!(c, Attr)[1].name == "Pi"); + static assert(getUDAs!(c, Attr)[1].value == 3); + + static assert(getUDAs!(c, Attr("Answer", 42)).length == 1); + static assert(getUDAs!(c, Attr("Answer", 42))[0].name == "Answer"); + static assert(getUDAs!(c, Attr("Answer", 42))[0].value == 42); + + static assert(getUDAs!(c, Attr("Answer", 99)).length == 0); + + struct AttrT(T) + { + string name; + T value; + } + + @AttrT!uint("Answer", 42) @AttrT!int("Pi", 3) @AttrT int d; + static assert(getUDAs!(d, AttrT).length == 2); + static assert(getUDAs!(d, AttrT)[0].name == "Answer"); + static assert(getUDAs!(d, AttrT)[0].value == 42); + static assert(getUDAs!(d, AttrT)[1].name == "Pi"); + static assert(getUDAs!(d, AttrT)[1].value == 3); + + static assert(getUDAs!(d, AttrT!uint).length == 1); + static assert(getUDAs!(d, AttrT!uint)[0].name == "Answer"); + static assert(getUDAs!(d, AttrT!uint)[0].value == 42); + + static assert(getUDAs!(d, AttrT!int).length == 1); + static assert(getUDAs!(d, AttrT!int)[0].name == "Pi"); + static assert(getUDAs!(d, AttrT!int)[0].value == 3); + + struct SimpleAttr {} + + @SimpleAttr int e; + static assert(getUDAs!(e, SimpleAttr).length == 1); + static assert(is(getUDAs!(e, SimpleAttr)[0] == SimpleAttr)); + + @SimpleAttr() int f; + static assert(getUDAs!(f, SimpleAttr).length == 1); + static assert(is(typeof(getUDAs!(f, SimpleAttr)[0]) == SimpleAttr)); + + struct FuncAttr(alias f) { alias func = f; } + static int add42(int v) { return v + 42; } + static string concat(string l, string r) { return l ~ r; } + + @FuncAttr!add42 int g; + static assert(getUDAs!(g, FuncAttr).length == 1); + static assert(getUDAs!(g, FuncAttr)[0].func(5) == 47); + + static assert(getUDAs!(g, FuncAttr!add42).length == 1); + static assert(getUDAs!(g, FuncAttr!add42)[0].func(5) == 47); + + static assert(getUDAs!(g, FuncAttr!add42()).length == 0); + + static assert(getUDAs!(g, FuncAttr!concat).length == 0); + static assert(getUDAs!(g, FuncAttr!concat()).length == 0); + + @FuncAttr!add42() int h; + static assert(getUDAs!(h, FuncAttr).length == 1); + static assert(getUDAs!(h, FuncAttr)[0].func(5) == 47); + + static assert(getUDAs!(h, FuncAttr!add42).length == 1); + static assert(getUDAs!(h, FuncAttr!add42)[0].func(5) == 47); + + static assert(getUDAs!(h, FuncAttr!add42()).length == 1); + static assert(getUDAs!(h, FuncAttr!add42())[0].func(5) == 47); + + static assert(getUDAs!(h, FuncAttr!concat).length == 0); + static assert(getUDAs!(h, FuncAttr!concat()).length == 0); + + @("alpha") @(42) int i; + static assert(getUDAs!(i, "alpha").length == 1); + static assert(getUDAs!(i, "alpha")[0] == "alpha"); + + static assert(getUDAs!(i, 42).length == 1); + static assert(getUDAs!(i, 42)[0] == 42); + + static assert(getUDAs!(i, 'c').length == 0); +} + +@safe unittest +{ + import std.traits; + + enum Attr; + struct A + { + @Attr int a; + int b; + } + + static assert(getSymbolsByUDA!(A, Attr).length == 1); + static assert(hasUDA!(getSymbolsByUDA!(A, Attr)[0], Attr)); +} + +@safe unittest +{ + import std.traits; + + enum Attr; + + static struct A + { + @Attr int a; + int b; + @Attr void doStuff() {} + void doOtherStuff() {} + static struct Inner + { + // Not found by getSymbolsByUDA + @Attr int c; + } + } + + // Finds both variables and functions with the attribute, but + // doesn't include the variables and functions without it. + static assert(getSymbolsByUDA!(A, Attr).length == 2); + // Can access attributes on the symbols returned by getSymbolsByUDA. + static assert(hasUDA!(getSymbolsByUDA!(A, Attr)[0], Attr)); + static assert(hasUDA!(getSymbolsByUDA!(A, Attr)[1], Attr)); +} + +@safe unittest +{ + import std.traits; + + static struct UDA { string name; } + + static struct B + { + @UDA("X") + int x; + @UDA("Y") + int y; + @(100) + int z; + } + + // Finds both UDA attributes. + static assert(getSymbolsByUDA!(B, UDA).length == 2); + // Finds one `100` attribute. + static assert(getSymbolsByUDA!(B, 100).length == 1); + // Can get the value of the UDA from the return value + static assert(getUDAs!(getSymbolsByUDA!(B, UDA)[0], UDA)[0].name == "X"); +} + +@safe unittest +{ + import std.traits; + + static struct UDA { string name; } + + @UDA("A") + static struct C + { + @UDA("B") + int d; + } + + static assert(getSymbolsByUDA!(C, UDA).length == 2); + static assert(getSymbolsByUDA!(C, UDA)[0].stringof == "C"); + static assert(getSymbolsByUDA!(C, UDA)[1].stringof == "d"); +} + +@safe unittest +{ + import std.traits; + + static struct UDA { string name; } + + static struct D + { + int x; + } + + static assert(getSymbolsByUDA!(D, UDA).length == 0); +} + +@safe unittest +{ + import std.traits; + + static assert(allSameType!()); + static assert(allSameType!(int)); + static assert(allSameType!(int, int)); + static assert(allSameType!(int, int, int)); + static assert(allSameType!(float, float, float)); + static assert(!allSameType!(int, double)); + static assert(!allSameType!(int, float, double)); + static assert(!allSameType!(int, float, double, real)); + static assert(!allSameType!(short, int, float, double, real)); +} + +@safe unittest +{ + import std.traits; + + class C; + struct S1; + struct S2 + { + T opCast(T)() const; + } + + static assert( ifTestable!bool); + static assert( ifTestable!int); + static assert( ifTestable!(S1*)); + static assert( ifTestable!(typeof(null))); + static assert( ifTestable!(int[])); + static assert( ifTestable!(int[string])); + static assert( ifTestable!S2); + static assert( ifTestable!C); + static assert(!ifTestable!S1); +} + +@safe unittest +{ + import std.traits; + + struct S { + template Test() {} + } + class C {} + interface I {} + union U {} + static assert(isType!int); + static assert(isType!string); + static assert(isType!(int[int])); + static assert(isType!S); + static assert(isType!C); + static assert(isType!I); + static assert(isType!U); + + int n; + void func(){} + static assert(!isType!n); + static assert(!isType!func); + static assert(!isType!(S.Test)); + static assert(!isType!(S.Test!())); +} + +@safe unittest +{ + import std.traits; + + static void func(){} + static assert(isFunction!func); + + struct S + { + void func(){} + } + static assert(isFunction!(S.func)); +} + +@safe unittest +{ + import std.traits; + + class C + { + void nf() {} + static void sf() {} + final void ff() {} + } + final class FC { } + + static assert(!isFinal!(C)); + static assert( isFinal!(FC)); + + static assert(!isFinal!(C.nf)); + static assert(!isFinal!(C.sf)); + static assert( isFinal!(C.ff)); +} + +@safe unittest +{ + import std.traits; + + struct S1 {} // Fine. Can be copied + struct S2 { this(this) {}} // Fine. Can be copied + struct S3 {@disable this(this); } // Not fine. Copying is disabled. + struct S4 {S3 s;} // Not fine. A field has copying disabled. + + class C1 {} + + static assert( isCopyable!S1); + static assert( isCopyable!S2); + static assert(!isCopyable!S3); + static assert(!isCopyable!S4); + + static assert(isCopyable!C1); + static assert(isCopyable!int); + static assert(isCopyable!(int[])); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_typecons.d b/libphobos/testsuite/libphobos.phobos/std_typecons.d new file mode 100644 index 000000000000..c8e43ac499aa --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_typecons.d @@ -0,0 +1,1931 @@ +@safe unittest +{ + import std.typecons; + + alias Coord = Tuple!(int, "x", int, "y", int, "z"); + Coord c; + c[1] = 1; // access by index + c.z = 1; // access by given name + assert(c == Coord(0, 1, 1)); + + // names can be omitted, types can be mixed + alias DictEntry = Tuple!(string, int); + auto dict = DictEntry("seven", 7); + + // element types can be inferred + assert(tuple(2, 3, 4)[1] == 3); + // type inference works with names too + auto tup = tuple!("x", "y", "z")(2, 3, 4); + assert(tup.y == 3); +} + +@safe unittest +{ + import std.typecons; + + class Widget + { + void foo() const @safe {} + } + const w1 = new Widget, w2 = new Widget; + w1.foo(); + // w1 = w2 would not work; can't rebind const object + + auto r = Rebindable!(const Widget)(w1); + // invoke method as if r were a Widget object + r.foo(); + // rebind r to refer to another object + r = w2; +} + +@safe unittest +{ + import std.typecons; + + struct S + { + int i; + this(int i){this.i = i;} + } + Unique!S produce() + { + // Construct a unique instance of S on the heap + Unique!S ut = new S(5); + // Implicit transfer of ownership + return ut; + } + // Borrow a unique resource by ref + void increment(ref Unique!S ur) + { + ur.i++; + } + void consume(Unique!S u2) + { + assert(u2.i == 6); + // Resource automatically deleted here + } + Unique!S u1; + assert(u1.isEmpty); + u1 = produce(); + assert(u1.i == 5); + increment(u1); + assert(u1.i == 6); + //consume(u1); // Error: u1 is not copyable + // Transfer ownership of the resource + consume(u1.release); + assert(u1.isEmpty); +} + +@safe unittest +{ + import std.typecons; + + import std.meta : AliasSeq; + alias Fields = Tuple!(int, "id", string, float); + static assert(is(Fields.Types == AliasSeq!(int, string, float))); + +} + +@safe unittest +{ + import std.typecons; + + import std.meta : AliasSeq; + alias Fields = Tuple!(int, "id", string, float); + static assert(Fields.fieldNames == AliasSeq!("id", "", "")); + +} + +@safe unittest +{ + import std.typecons; + + auto t1 = tuple(1, " hello ", 'a'); + assert(t1.toString() == `Tuple!(int, string, char)(1, " hello ", 'a')`); + + void takeSeveralTypes(int n, string s, bool b) + { + assert(n == 4 && s == "test" && b == false); + } + + auto t2 = tuple(4, "test", false); + //t.expand acting as a list of values + takeSeveralTypes(t2.expand); + +} + +@safe unittest +{ + import std.typecons; + + alias ISD = Tuple!(int, string, double); + auto tup = ISD(1, "test", 3.2); + assert(tup.toString() == `Tuple!(int, string, double)(1, "test", 3.2)`); + +} + +@safe unittest +{ + import std.typecons; + + int[2] ints; + Tuple!(int, int) t = ints; + +} + +@safe unittest +{ + import std.typecons; + + alias IntVec = Tuple!(int, int, int); + alias DubVec = Tuple!(double, double, double); + + IntVec iv = tuple(1, 1, 1); + + //Ok, int can implicitly convert to double + DubVec dv = iv; + //Error: double cannot implicitly convert to int + //IntVec iv2 = dv; + +} + +@safe unittest +{ + import std.typecons; + + Tuple!(int, string) t1 = tuple(1, "test"); + Tuple!(double, string) t2 = tuple(1.0, "test"); + //Ok, int can be compared with double and + //both have a value of 1 + assert(t1 == t2); + +} + +@safe unittest +{ + import std.typecons; + + auto tup1 = tuple(1, 1, 1); + auto tup2 = tuple(1, 100, 100); + assert(tup1 < tup2); + + //Only the first result matters for comparison + tup1[0] = 2; + assert(tup1 > tup2); + +} + +@safe unittest +{ + import std.typecons; + + auto t0 = tuple(4, "hello"); + + auto t0Named = t0.rename!("val", "tag"); + assert(t0Named.val == 4); + assert(t0Named.tag == "hello"); + + Tuple!(float, "dat", size_t[2], "pos") t1; + t1.pos = [2, 1]; + auto t1Named = t1.rename!"height"; + t1Named.height = 3.4f; + assert(t1Named.height == 3.4f); + assert(t1Named.pos == [2, 1]); + t1Named.rename!"altitude".altitude = 5; + assert(t1Named.height == 5); + + Tuple!(int, "a", int, int, "c") t2; + t2 = tuple(3,4,5); + auto t2Named = t2.rename!("", "b"); + // "a" no longer has a name + static assert(!__traits(hasMember, typeof(t2Named), "a")); + assert(t2Named[0] == 3); + assert(t2Named.b == 4); + assert(t2Named.c == 5); + + // not allowed to specify more names than the tuple has members + static assert(!__traits(compiles, t2.rename!("a","b","c","d"))); + + // use it in a range pipeline + import std.range : iota, zip; + import std.algorithm.iteration : map, sum; + auto res = zip(iota(1, 4), iota(10, 13)) + .map!(t => t.rename!("a", "b")) + .map!(t => t.a * t.b) + .sum; + assert(res == 68); + + const tup = Tuple!(int, "a", int, "b")(2, 3); + const renamed = tup.rename!("c", "d"); + assert(renamed.c + renamed.d == 5); + +} + +@safe unittest +{ + import std.typecons; + + //replacing names by their current name + + Tuple!(float, "dat", size_t[2], "pos") t1; + t1.pos = [2, 1]; + auto t1Named = t1.rename!(["dat": "height"]); + t1Named.height = 3.4; + assert(t1Named.pos == [2, 1]); + t1Named.rename!(["height": "altitude"]).altitude = 5; + assert(t1Named.height == 5); + + Tuple!(int, "a", int, "b") t2; + t2 = tuple(3, 4); + auto t2Named = t2.rename!(["a": "b", "b": "c"]); + assert(t2Named.b == 3); + assert(t2Named.c == 4); + + const t3 = Tuple!(int, "a", int, "b")(3, 4); + const t3Named = t3.rename!(["a": "b", "b": "c"]); + assert(t3Named.b == 3); + assert(t3Named.c == 4); + +} + +@system unittest +{ + import std.typecons; + + //replace names by their position + + Tuple!(float, "dat", size_t[2], "pos") t1; + t1.pos = [2, 1]; + auto t1Named = t1.rename!([0: "height"]); + t1Named.height = 3.4; + assert(t1Named.pos == [2, 1]); + t1Named.rename!([0: "altitude"]).altitude = 5; + assert(t1Named.height == 5); + + Tuple!(int, "a", int, "b", int, "c") t2; + t2 = tuple(3, 4, 5); + auto t2Named = t2.rename!([0: "c", 2: "a"]); + assert(t2Named.a == 5); + assert(t2Named.b == 4); + assert(t2Named.c == 3); + +} + +@safe unittest +{ + import std.typecons; + + Tuple!(int, string, float, double) a; + a[1] = "abc"; + a[2] = 4.5; + auto s = a.slice!(1, 3); + static assert(is(typeof(s) == Tuple!(string, float))); + assert(s[0] == "abc" && s[1] == 4.5); + + // https://issues.dlang.org/show_bug.cgi?id=15645 + Tuple!(int, short, bool, double) b; + static assert(!__traits(compiles, b.slice!(2, 4))); + +} + +@safe unittest +{ + import std.typecons; + + import std.format : format; + + Tuple!(int, double)[3] tupList = [ tuple(1, 1.0), tuple(2, 4.0), tuple(3, 9.0) ]; + + // Default format + assert(format("%s", tuple("a", 1)) == `Tuple!(string, int)("a", 1)`); + + // One Format for each individual component + assert(format("%(%#x v %.4f w %#x%)", tuple(1, 1.0, 10)) == `0x1 v 1.0000 w 0xa`); + assert(format( "%#x v %.4f w %#x" , tuple(1, 1.0, 10).expand) == `0x1 v 1.0000 w 0xa`); + + // One Format for all components + assert(format("%(>%s<%| & %)", tuple("abc", 1, 2.3, [4, 5])) == `>abc< & >1< & >2.3< & >[4, 5]<`); + + // Array of Tuples + assert(format("%(%(f(%d) = %.1f%); %)", tupList) == `f(1) = 1.0; f(2) = 4.0; f(3) = 9.0`); + +} + +@safe unittest +{ + import std.typecons; + + import std.exception : assertThrown; + import std.format : format, FormatException; + + // Error: %( %) missing. + assertThrown!FormatException( + format("%d, %f", tuple(1, 2.0)) == `1, 2.0` + ); + + // Error: %( %| %) missing. + assertThrown!FormatException( + format("%d", tuple(1, 2)) == `1, 2` + ); + + // Error: %d inadequate for double + assertThrown!FormatException( + format("%(%d%|, %)", tuple(1, 2.0)) == `1, 2.0` + ); + +} + +@safe unittest +{ + import std.typecons; + + Tuple!(int, int) point; + // assign coordinates + point[0] = 5; + point[1] = 6; + // read coordinates + auto x = point[0]; + auto y = point[1]; +} + +@safe unittest +{ + import std.typecons; + + alias Entry = Tuple!(int, "index", string, "value"); + Entry e; + e.index = 4; + e.value = "Hello"; + assert(e[1] == "Hello"); + assert(e[0] == 4); +} + +@safe unittest +{ + import std.typecons; + + Tuple!(int, "x", int, "y") point1; + Tuple!(int, int) point2; + assert(!is(typeof(point1) == typeof(point2))); +} + +@safe unittest +{ + import std.typecons; + + import std.algorithm.iteration : sum; + import std.range : only; + auto t = tuple(1, 2); + assert(t.expand.only.sum == 3); +} + +@safe unittest +{ + import std.typecons; + + import std.meta : AliasSeq; + auto t = tuple(1, "2") ~ tuple(ushort(42), true); + static assert(is(t.Types == AliasSeq!(int, string, ushort, bool))); + assert(t[1] == "2"); + assert(t[2] == 42); + assert(t[3] == true); +} + +@safe unittest +{ + import std.typecons; + + auto tup = tuple(1, "2"); + assert(tup.reverse == tuple("2", 1)); +} + +@safe unittest +{ + import std.typecons; + + auto value = tuple(5, 6.7, "hello"); + assert(value[0] == 5); + assert(value[1] == 6.7); + assert(value[2] == "hello"); + + // Field names can be provided. + auto entry = tuple!("index", "value")(4, "Hello"); + assert(entry.index == 4); + assert(entry.value == "Hello"); +} + +@safe unittest +{ + import std.typecons; + + static assert(isTuple!(Tuple!())); + static assert(isTuple!(Tuple!(int))); + static assert(isTuple!(Tuple!(int, real, string))); + static assert(isTuple!(Tuple!(int, "x", real, "y"))); + static assert(isTuple!(Tuple!(int, Tuple!(real), string))); +} + +@safe unittest +{ + import std.typecons; + + class Widget { int x; int y() @safe const { return x; } } + const a = new Widget; + // Fine + a.y(); + // error! can't modify const a + // a.x = 5; + // error! can't modify const a + // a = new Widget; +} + +@safe unittest +{ + import std.typecons; + + class Widget { int x; int y() const @safe { return x; } } + auto a = Rebindable!(const Widget)(new Widget); + // Fine + a.y(); + // error! can't modify const a + // a.x = 5; + // Fine + a = new Widget; +} + +@safe unittest +{ + import std.typecons; + + import std.range.primitives : front, popFront; + + // simple version of std.algorithm.searching.maxElement + typeof(R.init.front) maxElement(R)(R r) + { + auto max = rebindable(r.front); + r.popFront; + foreach (e; r) + if (e > max) + max = e; // Rebindable allows const-correct reassignment + return max; + } + struct S + { + char[] arr; + alias arr this; // for comparison + } + // can't convert to mutable + const S cs; + static assert(!__traits(compiles, { S s = cs; })); + + alias CS = const S; + CS[] arr = [CS("harp"), CS("apple"), CS("pot")]; + CS ms = maxElement(arr); + assert(ms.arr == "pot"); +} + +@system unittest +{ + import std.typecons; + + static struct S + { + int* ptr; + } + S s = S(new int); + + const cs = s; + // Can't assign s.ptr to cs.ptr + static assert(!__traits(compiles, {s = cs;})); + + Rebindable!(const S) rs = s; + assert(rs.ptr is s.ptr); + // rs.ptr is const + static assert(!__traits(compiles, {rs.ptr = null;})); + + // Can't assign s.ptr to rs.ptr + static assert(!__traits(compiles, {s = rs;})); + + const S cs2 = rs; + // Rebind rs + rs = cs2; + rs = S(); + assert(rs.ptr is null); +} + +@system unittest +{ + import std.typecons; + + class C + { + int payload; + this(int p) { payload = p; } + } + const c = new C(1); + + auto c2 = c.rebindable; + assert(c2.payload == 1); + // passing Rebindable to rebindable + c2 = c2.rebindable; + + c2 = new C(2); + assert(c2.payload == 2); + + const c3 = c2.get; + assert(c3.payload == 2); +} + +@safe unittest +{ + import std.typecons; + + immutable struct S + { + int[] array; + } + auto s1 = [3].idup.rebindable; + s1 = [4].idup.rebindable; + assert(s1 == [4]); +} + +@system unittest +{ + import std.typecons; + + class C + { + int payload; + this(int p) { payload = p; } + } + const c = new C(1); + + auto c2 = c.rebindable; + assert(c2.payload == 1); + // passing Rebindable to rebindable + c2 = c2.rebindable; + assert(c2.payload == 1); +} + +@system unittest +{ + import std.typecons; + + class Data {} + + static shared(Data) a; + static UnqualRef!(shared Data) b; + + import core.thread; + + auto thread = new core.thread.Thread({ + a = new shared Data(); + b = new shared Data(); + }); + + thread.start(); + thread.join(); + + assert(a !is null); + assert(b is null); +} + +@safe unittest +{ + import std.typecons; + + struct Banner { + mixin(alignForSize!(byte[6], double)(["name", "height"])); + } +} + +@safe unittest +{ + import std.typecons; + + Nullable!int empty; + Nullable!int a = 42; + Nullable!int b = 42; + Nullable!int c = 27; + + assert(empty == empty); + assert(empty == Nullable!int.init); + assert(empty != a); + assert(empty != b); + assert(empty != c); + + assert(a == b); + assert(a != c); + + assert(empty != 42); + assert(a == 42); + assert(c != 42); + +} + +@safe unittest +{ + import std.typecons; + + Nullable!int ni; + assert(ni.isNull); + + ni = 0; + assert(!ni.isNull); + +} + +@safe unittest +{ + import std.typecons; + + Nullable!int ni = 0; + assert(!ni.isNull); + + ni.nullify(); + assert(ni.isNull); + +} + +@safe unittest +{ + import std.typecons; + + //Passes + Nullable!(int*) npi; + assert(npi.isNull); + + //Passes?! + npi = null; + assert(!npi.isNull); + +} + +@safe unittest +{ + import std.typecons; + + struct CustomerRecord + { + string name; + string address; + int customerNum; + } + + Nullable!CustomerRecord getByName(string name) + { + //A bunch of hairy stuff + + return Nullable!CustomerRecord.init; + } + + auto queryResult = getByName("Doe, John"); + if (!queryResult.isNull) + { + //Process Mr. Doe's customer record + auto address = queryResult.get.address; + auto customerNum = queryResult.get.customerNum; + + //Do some things with this customer's info + } + else + { + //Add the customer to the database + } +} + +@system unittest +{ + import std.typecons; + + import std.exception : assertThrown; + + auto a = 42.nullable; + assert(!a.isNull); + assert(a.get == 42); + + a.nullify(); + assert(a.isNull); + assertThrown!Throwable(a.get); +} + +@safe unittest +{ + import std.typecons; + + import std.algorithm.iteration : each, joiner; + Nullable!int a = 42; + Nullable!int b; + // Add each value to an array + int[] arr; + a.each!((n) => arr ~= n); + assert(arr == [42]); + b.each!((n) => arr ~= n); + assert(arr == [42]); + // Take first value from an array of Nullables + Nullable!int[] c = new Nullable!int[](10); + c[7] = Nullable!int(42); + assert(c.joiner.front == 42); +} + +@safe unittest +{ + import std.typecons; + + Nullable!(int, -1) ni; + //Initialized to "null" state + assert(ni.isNull); + + ni = 0; + assert(!ni.isNull); +} + +@safe unittest +{ + import std.typecons; + + Nullable!(int, -1) ni = 0; + assert(!ni.isNull); + + ni = -1; + assert(ni.isNull); +} + +@system unittest +{ + import std.typecons; + + //Passes + enum nullVal = cast(int*) 0xCAFEBABE; + Nullable!(int*, nullVal) npi; + assert(npi.isNull); + + //Passes?! + npi = null; + assert(!npi.isNull); +} + +@system unittest +{ + import std.typecons; + + import std.exception : assertThrown, assertNotThrown; + + Nullable!(int, -1) ni; + //`get` is implicitly called. Will throw + //an error in non-release mode + assertThrown!Throwable(ni == 0); + + ni = 0; + assertNotThrown!Throwable(ni == 0); +} + +@safe unittest +{ + import std.typecons; + + Nullable!(size_t, size_t.max) indexOf(string[] haystack, string needle) + { + //Find the needle, returning -1 if not found + + return Nullable!(size_t, size_t.max).init; + } + + void sendLunchInvite(string name) + { + } + + //It's safer than C... + auto coworkers = ["Jane", "Jim", "Marry", "Fred"]; + auto pos = indexOf(coworkers, "Bob"); + if (!pos.isNull) + { + //Send Bob an invitation to lunch + sendLunchInvite(coworkers[pos]); + } + else + { + //Bob not found; report the error + } + + //And there's no overhead + static assert(Nullable!(size_t, size_t.max).sizeof == size_t.sizeof); +} + +@system unittest +{ + import std.typecons; + + import std.exception : assertThrown; + + Nullable!(int, int.min) a; + assert(a.isNull); + assertThrown!Throwable(a.get); + a = 5; + assert(!a.isNull); + assert(a == 5); + static assert(a.sizeof == int.sizeof); +} + +@safe unittest +{ + import std.typecons; + + auto a = nullable!(int.min)(8); + assert(a == 8); + a.nullify(); + assert(a.isNull); +} + +nothrow pure @nogc @safe unittest +{ + import std.typecons; + + alias toFloat = i => cast(float) i; + + Nullable!int sample; + + // apply(null) results in a null `Nullable` of the function's return type. + Nullable!float f = sample.apply!toFloat; + assert(sample.isNull && f.isNull); + + sample = 3; + + // apply(non-null) calls the function and wraps the result in a `Nullable`. + f = sample.apply!toFloat; + assert(!sample.isNull && !f.isNull); + assert(f.get == 3.0f); +} + +nothrow pure @nogc @safe unittest +{ + import std.typecons; + + alias greaterThree = i => (i > 3) ? i.nullable : Nullable!(typeof(i)).init; + + Nullable!int sample; + + // when the function already returns a `Nullable`, that `Nullable` is not wrapped. + auto result = sample.apply!greaterThree; + assert(sample.isNull && result.isNull); + + // The function may decide to return a null `Nullable`. + sample = 3; + result = sample.apply!greaterThree; + assert(!sample.isNull && result.isNull); + + // Or it may return a value already wrapped in a `Nullable`. + sample = 4; + result = sample.apply!greaterThree; + assert(!sample.isNull && !result.isNull); + assert(result.get == 4); +} + +@safe unittest +{ + import std.typecons; + + NullableRef!int nr = new int(42); + assert(nr == 42); + + int* n = new int(1); + nr.bind(n); + assert(nr == 1); + +} + +@safe unittest +{ + import std.typecons; + + NullableRef!int nr; + assert(nr.isNull); + + int* n = new int(42); + nr.bind(n); + assert(!nr.isNull && nr == 42); + +} + +@safe unittest +{ + import std.typecons; + + NullableRef!int nr = new int(42); + assert(!nr.isNull); + + nr.nullify(); + assert(nr.isNull); + +} + +@system unittest +{ + import std.typecons; + + import std.exception : assertThrown, assertNotThrown; + + NullableRef!int nr; + assert(nr.isNull); + assertThrown!Throwable(nr = 42); + + nr.bind(new int(0)); + assert(!nr.isNull); + assertNotThrown!Throwable(nr = 42); + assert(nr == 42); + +} + +@system unittest +{ + import std.typecons; + + import std.exception : assertThrown, assertNotThrown; + + NullableRef!int nr; + //`get` is implicitly called. Will throw + //an error in non-release mode + assertThrown!Throwable(nr == 0); + + nr.bind(new int(0)); + assertNotThrown!Throwable(nr == 0); + +} + +@system unittest +{ + import std.typecons; + + import std.exception : assertThrown; + + int x = 5, y = 7; + auto a = nullableRef(&x); + assert(!a.isNull); + assert(a == 5); + assert(x == 5); + a = 42; + assert(x == 42); + assert(!a.isNull); + assert(a == 42); + a.nullify(); + assert(x == 42); + assert(a.isNull); + assertThrown!Throwable(a.get); + assertThrown!Throwable(a = 71); + a.bind(&y); + assert(a == 7); + y = 135; + assert(a == 135); +} + +@system unittest +{ + import std.typecons; + + import std.math.traits : isNaN; + + static abstract class C + { + int m_value; + this(int v) { m_value = v; } + int value() @property { return m_value; } + + abstract real realValue() @property; + abstract void doSomething(); + } + + auto c = new BlackHole!C(42); + assert(c.value == 42); + + // Returns real.init which is NaN + assert(c.realValue.isNaN); + // Abstract functions are implemented as do-nothing + c.doSomething(); +} + +@system unittest +{ + import std.typecons; + + import std.exception : assertThrown; + + static class C + { + abstract void notYetImplemented(); + } + + auto c = new WhiteHole!C; + assertThrown!NotImplementedError(c.notYetImplemented()); // throws an Error +} + +@system unittest +{ + import std.typecons; + + import std.exception : assertThrown; + // nothrow + { + interface I_1 + { + void foo(); + void bar() nothrow; + } + auto o = new WhiteHole!I_1; + assertThrown!NotImplementedError(o.foo()); + assertThrown!NotImplementedError(o.bar()); + } + // doc example + { + static class C + { + abstract void notYetImplemented(); + } + + auto c = new WhiteHole!C; + try + { + c.notYetImplemented(); + assert(0); + } + catch (Error e) {} + } +} + +@system unittest +{ + import std.typecons; + + interface PackageSupplier + { + int foo(); + int bar(); + } + + static abstract class AbstractFallbackPackageSupplier : PackageSupplier + { + protected PackageSupplier default_, fallback; + + this(PackageSupplier default_, PackageSupplier fallback) + { + this.default_ = default_; + this.fallback = fallback; + } + + abstract int foo(); + abstract int bar(); + } + + template fallback(T, alias func) + { + import std.format : format; + // for all implemented methods: + // - try default first + // - only on a failure run & return fallback + enum fallback = q{ + try + { + return default_.%1$s(args); + } + catch (Exception) + { + return fallback.%1$s(args); + } + }.format(__traits(identifier, func)); + } + + // combines two classes and use the second one as fallback + alias FallbackPackageSupplier = AutoImplement!(AbstractFallbackPackageSupplier, fallback); + + class FailingPackageSupplier : PackageSupplier + { + int foo(){ throw new Exception("failure"); } + int bar(){ return 2;} + } + + class BackupPackageSupplier : PackageSupplier + { + int foo(){ return -1; } + int bar(){ return -1;} + } + + auto registry = new FallbackPackageSupplier(new FailingPackageSupplier(), new BackupPackageSupplier()); + + assert(registry.foo() == -1); + assert(registry.bar() == 2); +} + +@system unittest +{ + import std.typecons; + + alias BlackHole(Base) = AutoImplement!(Base, generateEmptyFunction); + + interface I + { + int foo(); + string bar(); + } + + auto i = new BlackHole!I(); + // generateEmptyFunction returns the default value of the return type without doing anything + assert(i.foo == 0); + assert(i.bar is null); +} + +@system unittest +{ + import std.typecons; + + import std.exception : assertThrown; + + alias WhiteHole(Base) = AutoImplement!(Base, generateAssertTrap); + + interface I + { + int foo(); + string bar(); + } + + auto i = new WhiteHole!I(); + // generateAssertTrap throws an exception for every unimplemented function of the interface + assertThrown!NotImplementedError(i.foo); + assertThrown!NotImplementedError(i.bar); +} + +@system unittest +{ + import std.typecons; + + interface Quack + { + int quack(); + @property int height(); + } + interface Flyer + { + @property int height(); + } + class Duck : Quack + { + int quack() { return 1; } + @property int height() { return 10; } + } + class Human + { + int quack() { return 2; } + @property int height() { return 20; } + } + + Duck d1 = new Duck(); + Human h1 = new Human(); + + interface Refleshable + { + int reflesh(); + } + + // does not have structural conformance + static assert(!__traits(compiles, d1.wrap!Refleshable)); + static assert(!__traits(compiles, h1.wrap!Refleshable)); + + // strict upcast + Quack qd = d1.wrap!Quack; + assert(qd is d1); + assert(qd.quack() == 1); // calls Duck.quack + // strict downcast + Duck d2 = qd.unwrap!Duck; + assert(d2 is d1); + + // structural upcast + Quack qh = h1.wrap!Quack; + assert(qh.quack() == 2); // calls Human.quack + // structural downcast + Human h2 = qh.unwrap!Human; + assert(h2 is h1); + + // structural upcast (two steps) + Quack qx = h1.wrap!Quack; // Human -> Quack + Flyer fx = qx.wrap!Flyer; // Quack -> Flyer + assert(fx.height == 20); // calls Human.height + // structural downcast (two steps) + Quack qy = fx.unwrap!Quack; // Flyer -> Quack + Human hy = qy.unwrap!Human; // Quack -> Human + assert(hy is h1); + // structural downcast (one step) + Human hz = fx.unwrap!Human; // Flyer -> Human + assert(hz is h1); +} + +@system unittest +{ + import std.typecons; + + import std.traits : FunctionAttribute, functionAttributes; + interface A { int run(); } + interface B { int stop(); @property int status(); } + class X + { + int run() { return 1; } + int stop() { return 2; } + @property int status() { return 3; } + } + + auto x = new X(); + auto ab = x.wrap!(A, B); + A a = ab; + B b = ab; + assert(a.run() == 1); + assert(b.stop() == 2); + assert(b.status == 3); + static assert(functionAttributes!(typeof(ab).status) & FunctionAttribute.property); +} + +@system unittest +{ + import std.typecons; + + import core.exception : AssertError; + import std.exception : assertThrown; + + struct Foo + { + int a = 42; + } + + SafeRefCounted!(Foo, RefCountedAutoInitialize.yes) rcAuto; + SafeRefCounted!(Foo, RefCountedAutoInitialize.no) rcNoAuto; + + assert(rcAuto.refCountedPayload.a == 42); + + assertThrown!AssertError(rcNoAuto.refCountedPayload); + rcNoAuto.refCountedStore.ensureInitialized; + assert(rcNoAuto.refCountedPayload.a == 42); +} + +pure @system nothrow @nogc unittest +{ + import std.typecons; + + // A pair of an `int` and a `size_t` - the latter being the + // reference count - will be dynamically allocated + auto rc1 = SafeRefCounted!int(5); + assert(rc1 == 5); + // No more allocation, add just one extra reference count + auto rc2 = rc1; + // Reference semantics + rc2 = 42; + assert(rc1 == 42); + // the pair will be freed when rc1 and rc2 go out of scope +} + +@safe pure nothrow unittest +{ + import std.typecons; + + auto rcInt = safeRefCounted(5); + assert(rcInt.borrow!(theInt => theInt) == 5); + auto sameInt = rcInt; + assert(sameInt.borrow!"a" == 5); + + // using `ref` in the function + auto arr = [0, 1, 2, 3, 4, 5, 6]; + sameInt.borrow!(ref (x) => arr[x]) = 10; + assert(arr == [0, 1, 2, 3, 4, 10, 6]); + + // modifying the payload via an alias + sameInt.borrow!"a*=2"; + assert(rcInt.borrow!"a" == 10); +} + +@system unittest +{ + import std.typecons; + + static struct File + { + static size_t nDestroyed; + string name; + @disable this(this); // not copyable + ~this() { name = null; ++nDestroyed; } + } + + auto file = File("name"); + assert(file.name == "name"); + // file cannot be copied and has unique ownership + static assert(!__traits(compiles, {auto file2 = file;})); + + assert(File.nDestroyed == 0); + + // make the file ref counted to share ownership + // Note: + // We write a compound statement (brace-delimited scope) in which all `SafeRefCounted!File` handles are created and deleted. + // This allows us to see (after the scope) what happens after all handles have been destroyed. + { + // We move the content of `file` to a separate (and heap-allocated) `File` object, + // managed-and-accessed via one-or-multiple (initially: one) `SafeRefCounted!File` objects ("handles"). + // This "moving": + // (1) invokes `file`'s destructor (=> `File.nDestroyed` is incremented from 0 to 1 and `file.name` becomes `null`); + // (2) overwrites `file` with `File.init` (=> `file.name` becomes `null`). + // It appears that writing `name = null;` in the destructor is redundant, + // but please note that (2) is only performed if `File` defines a destructor (or post-blit operator), + // and in the absence of the `nDestroyed` instrumentation there would have been no reason to define a destructor. + import std.algorithm.mutation : move; + auto rcFile = safeRefCounted(move(file)); + assert(rcFile.name == "name"); + assert(File.nDestroyed == 1); + assert(file.name == null); + + // We create another `SafeRefCounted!File` handle to the same separate `File` object. + // While any of the handles is still alive, the `File` object is kept alive (=> `File.nDestroyed` is not modified). + auto rcFile2 = rcFile; + assert(rcFile.refCountedStore.refCount == 2); + assert(File.nDestroyed == 1); + } + // The separate `File` object is deleted when the last `SafeRefCounted!File` handle is destroyed + // (i.e. at the closing brace of the compound statement above, which destroys both handles: `rcFile` and `rcFile2`) + // (=> `File.nDestroyed` is incremented again, from 1 to 2): + assert(File.nDestroyed == 2); +} + +@safe unittest +{ + import std.typecons; + + struct MyInt + { + private int value; + mixin Proxy!value; + + this(int n){ value = n; } + } + + MyInt n = 10; + + // Enable operations that original type has. + ++n; + assert(n == 11); + assert(n * 2 == 22); + + void func(int n) { } + + // Disable implicit conversions to original type. + //int x = n; + //func(n); +} + +@safe unittest +{ + import std.typecons; + + struct NewIntType + { + //Won't work; the literal '1' + //is an rvalue, not an lvalue + //mixin Proxy!1; + + //Okay, n is an lvalue + int n; + mixin Proxy!n; + + this(int n) { this.n = n; } + } + + NewIntType nit = 0; + nit++; + assert(nit == 1); + + + struct NewObjectType + { + Object obj; + //Ok, obj is an lvalue + mixin Proxy!obj; + + this (Object o) { obj = o; } + } + + NewObjectType not = new Object(); + assert(__traits(compiles, not.toHash())); +} + +@safe unittest +{ + import std.typecons; + + import std.math.traits : isInfinity; + + float f = 1.0; + assert(!f.isInfinity); + + struct NewFloat + { + float _; + mixin Proxy!_; + + this(float f) { _ = f; } + } + + NewFloat nf = 1.0f; + assert(!nf.isInfinity); +} + +@safe unittest +{ + import std.typecons; + + import std.conv : to; + + int i = 123; + auto td = Typedef!int(i); + assert(i.to!string == td.to!string); + +} + +@safe unittest +{ + import std.typecons; + + alias MyInt = Typedef!int; + MyInt foo = 10; + foo++; + assert(foo == 11); +} + +@safe unittest +{ + import std.typecons; + + alias MyIntInit = Typedef!(int, 42); + static assert(is(TypedefType!MyIntInit == int)); + static assert(MyIntInit() == 42); +} + +@safe unittest +{ + import std.typecons; + + alias MyInt = Typedef!int; + static void takeInt(int) {} + static void takeMyInt(MyInt) {} + + int i; + takeInt(i); // ok + static assert(!__traits(compiles, takeMyInt(i))); + + MyInt myInt; + static assert(!__traits(compiles, takeInt(myInt))); + takeMyInt(myInt); // ok +} + +@safe unittest +{ + import std.typecons; + + alias TypeInt1 = Typedef!int; + alias TypeInt2 = Typedef!int; + + // The two Typedefs are the same type. + static assert(is(TypeInt1 == TypeInt2)); + + alias MoneyEuros = Typedef!(float, float.init, "euros"); + alias MoneyDollars = Typedef!(float, float.init, "dollars"); + + // The two Typedefs are _not_ the same type. + static assert(!is(MoneyEuros == MoneyDollars)); +} + +@safe unittest +{ + import std.typecons; + + import std.conv : to; + + alias MyInt = Typedef!int; + static assert(is(TypedefType!MyInt == int)); + + /// Instantiating with a non-Typedef will return that type + static assert(is(TypedefType!int == int)); + + string num = "5"; + + // extract the needed type + MyInt myInt = MyInt( num.to!(TypedefType!MyInt) ); + assert(myInt == 5); + + // cast to the underlying type to get the value that's being wrapped + int x = cast(TypedefType!MyInt) myInt; + + alias MyIntInit = Typedef!(int, 42); + static assert(is(TypedefType!MyIntInit == int)); + static assert(MyIntInit() == 42); +} + +@system unittest +{ + import std.typecons; + + class A + { + int x; + this() {x = 0;} + this(int i){x = i;} + ~this() {} + } + + // Standard usage, constructing A on the stack + auto a1 = scoped!A(); + a1.x = 42; + + // Result of `scoped` call implicitly converts to a class reference + A aRef = a1; + assert(aRef.x == 42); + + // Scoped destruction + { + auto a2 = scoped!A(1); + assert(a2.x == 1); + aRef = a2; + // a2 is destroyed here, calling A's destructor + } + // aRef is now an invalid reference + + // Here the temporary scoped A is immediately destroyed. + // This means the reference is then invalid. + version (Bug) + { + // Wrong, should use `auto` + A invalid = scoped!A(); + } + + // Restrictions + version (Bug) + { + import std.algorithm.mutation : move; + auto invalid = a1.move; // illegal, scoped objects can't be moved + } + static assert(!is(typeof({ + auto e1 = a1; // illegal, scoped objects can't be copied + assert([a1][0].x == 42); // ditto + }))); + static assert(!is(typeof({ + alias ScopedObject = typeof(a1); + auto e2 = ScopedObject(); // illegal, must be built via scoped!A + auto e3 = ScopedObject(1); // ditto + }))); + + // Use with alias + alias makeScopedA = scoped!A; + auto a3 = makeScopedA(); + auto a4 = makeScopedA(1); + + // Use as member variable + struct B + { + typeof(scoped!A()) a; // note the trailing parentheses + + this(int i) + { + // construct member + a = scoped!A(i); + } + } + + // Stack-allocate + auto b1 = B(5); + aRef = b1.a; + assert(aRef.x == 5); + destroy(b1); // calls A's destructor for b1.a + // aRef is now an invalid reference + + // Heap-allocate + auto b2 = new B(6); + assert(b2.a.x == 6); + destroy(*b2); // calls A's destructor for b2.a +} + +@safe unittest +{ + import std.typecons; + + Flag!"abc" flag; + + assert(flag == Flag!"abc".no); + assert(flag == No.abc); + assert(!flag); + if (flag) assert(0); +} + +@safe unittest +{ + import std.typecons; + + auto flag = Yes.abc; + + assert(flag); + assert(flag == Yes.abc); + if (!flag) assert(0); + if (flag) {} else assert(0); +} + +@safe unittest +{ + import std.typecons; + + Flag!"abc" flag; + + assert(flag == Flag!"abc".no); + assert(flag == No.abc); + assert(!flag); + if (flag) assert(0); +} + +@safe unittest +{ + import std.typecons; + + auto flag = Yes.abc; + + assert(flag); + assert(flag == Yes.abc); + if (!flag) assert(0); + if (flag) {} else assert(0); +} + +@safe pure nothrow unittest +{ + import std.typecons; + + enum A + { + None, + A = 1 << 0, + B = 1 << 1, + C = 1 << 2, + D = 1 << 3, + } + + static assert(isBitFlagEnum!A); +} + +@safe pure nothrow unittest +{ + import std.typecons; + + enum B + { + A, + B, + C, + D // D == 3 + } + + static assert(!isBitFlagEnum!B); +} + +@safe pure nothrow unittest +{ + import std.typecons; + + enum C: double + { + A = 1 << 0, + B = 1 << 1 + } + + static assert(!isBitFlagEnum!C); +} + +@safe @nogc pure nothrow unittest +{ + import std.typecons; + + enum Enum + { + A = 1 << 0, + } + + // A default constructed BitFlags has no value set + immutable BitFlags!Enum flags_empty; + assert(!flags_empty.A); + + // Value can be set with the | operator + immutable flags_A = flags_empty | Enum.A; + + // and tested using property access + assert(flags_A.A); + + // or the & operator + assert(flags_A & Enum.A); + // which commutes. + assert(Enum.A & flags_A); +} + +@safe @nogc pure nothrow unittest +{ + import std.typecons; + + enum Enum + { + None, + A = 1 << 0, + B = 1 << 1, + C = 1 << 2 + } + + immutable BitFlags!Enum flags_empty; + assert(!(flags_empty & (Enum.A | Enum.B | Enum.C))); + assert(!(flags_empty & Enum.A) && !(flags_empty & Enum.B) && !(flags_empty & Enum.C)); +} + +@safe @nogc pure nothrow unittest +{ + import std.typecons; + + enum Enum + { + A = 1 << 0, + B = 1 << 1, + C = 1 << 2, + } + immutable BitFlags!Enum flags_AB = BitFlags!Enum(Enum.A, Enum.B); + immutable BitFlags!Enum flags_BC = BitFlags!Enum(Enum.B, Enum.C); + + // Use the ~ operator for subtracting flags + immutable BitFlags!Enum flags_B = flags_AB & ~BitFlags!Enum(Enum.A); + assert(!flags_B.A && flags_B.B && !flags_B.C); + + // use & between BitFlags for intersection + assert(flags_B == (flags_BC & flags_AB)); +} + +@safe @nogc pure nothrow unittest +{ + import std.typecons; + + enum Enum + { + A = 1 << 0, + B = 1 << 1, + } + + BitFlags!Enum flags_empty, temp, flags_AB; + flags_AB = Enum.A | Enum.B; + + temp |= flags_AB; + assert(temp == (flags_empty | flags_AB)); + + temp = flags_empty; + temp |= Enum.B; + assert(temp == (flags_empty | Enum.B)); + + temp = flags_empty; + temp &= flags_AB; + assert(temp == (flags_empty & flags_AB)); + + temp = flags_empty; + temp &= Enum.A; + assert(temp == (flags_empty & Enum.A)); +} + +@safe @nogc pure nothrow unittest +{ + import std.typecons; + + enum Enum + { + A = 1 << 0, + B = 1 << 1, + } + + BitFlags!Enum flags; + + // BitFlags with no value set evaluate to false + assert(!flags); + + // BitFlags with at least one value set evaluate to true + flags |= Enum.A; + assert(flags); + + // This can be useful to check intersection between BitFlags + BitFlags!Enum flags_AB = Enum.A | Enum.B; + assert(flags & flags_AB); + assert(flags & Enum.A); + + // You can of course get you raw value out of flags + auto value = cast(int) flags; + assert(value == Enum.A); +} + +@safe @nogc pure nothrow unittest +{ + import std.typecons; + + enum UnsafeEnum + { + A = 1, + B = 2, + C = 4, + BC = B|C + } + static assert(!__traits(compiles, { BitFlags!UnsafeEnum flags; })); + BitFlags!(UnsafeEnum, Yes.unsafe) flags; + + // property access tests for exact match of unsafe enums + flags.B = true; + assert(!flags.BC); // only B + flags.C = true; + assert(flags.BC); // both B and C + flags.B = false; + assert(!flags.BC); // only C + + // property access sets all bits of unsafe enum group + flags = flags.init; + flags.BC = true; + assert(!flags.A && flags.B && flags.C); + flags.A = true; + flags.BC = false; + assert(flags.A && !flags.B && !flags.C); +} + +@safe unittest +{ + import std.typecons; + + static assert( + is(ReplaceType!(int, string, int[]) == string[]) && + is(ReplaceType!(int, string, int[int]) == string[string]) && + is(ReplaceType!(int, string, const(int)[]) == const(string)[]) && + is(ReplaceType!(int, string, Tuple!(int[], float)) + == Tuple!(string[], float)) + ); +} + +@safe unittest +{ + import std.typecons; + + import std.traits : isArray; + + static assert( + is(ReplaceTypeUnless!(isArray, int, string, int*) == string*) && + is(ReplaceTypeUnless!(isArray, int, string, int[]) == int[]) && + is(ReplaceTypeUnless!(isArray, int, string, Tuple!(int, int[])) + == Tuple!(string, int[])) + ); +} + +@safe @nogc nothrow pure unittest +{ + import std.typecons; + + Ternary a; + assert(a == Ternary.unknown); + + assert(~Ternary.yes == Ternary.no); + assert(~Ternary.no == Ternary.yes); + assert(~Ternary.unknown == Ternary.unknown); +} + +pure @system nothrow @nogc unittest +{ + import std.typecons; + + auto rc1 = RefCounted!int(5); + assert(rc1 == 5); + auto rc2 = rc1; + rc2 = 42; + assert(rc1 == 42); +} + +@system unittest +{ + import std.typecons; + + static struct File + { + static size_t nDestroyed; + string name; + @disable this(this); // not copyable + ~this() { name = null; ++nDestroyed; } + } + + auto file = File("name"); + assert(file.name == "name"); + static assert(!__traits(compiles, {auto file2 = file;})); + assert(File.nDestroyed == 0); + + { + import std.algorithm.mutation : move; + auto rcFile = refCounted(move(file)); + assert(rcFile.name == "name"); + assert(File.nDestroyed == 1); + assert(file.name == null); + + auto rcFile2 = rcFile; + assert(rcFile.refCountedStore.refCount == 2); + assert(File.nDestroyed == 1); + } + + assert(File.nDestroyed == 2); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_typetuple.d b/libphobos/testsuite/libphobos.phobos/std_typetuple.d new file mode 100644 index 000000000000..e5ccd7637a21 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_typetuple.d @@ -0,0 +1,24 @@ +@safe unittest +{ + import std.typetuple; + + import std.typetuple; + alias TL = TypeTuple!(int, double); + + int foo(TL td) // same as int foo(int, double); + { + return td[0] + cast(int) td[1]; + } + assert(foo(1, 2.5) == 3); +} + +@safe unittest +{ + import std.typetuple; + + alias TL = TypeTuple!(int, double); + + alias Types = TypeTuple!(TL, char); + static assert(is(Types == TypeTuple!(int, double, char))); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_uni_package.d b/libphobos/testsuite/libphobos.phobos/std_uni_package.d new file mode 100644 index 000000000000..cdb3439c941c --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_uni_package.d @@ -0,0 +1,547 @@ +pure @safe unittest +{ + import std.uni; + + import std.algorithm.comparison : equal; + + auto set = CodepointSet('a', 'z'+1, 'а', 'Ñ'+1); + foreach (v; 'a'..'z'+1) + assert(set[v]); + // Cyrillic lowercase interval + foreach (v; 'а'..'Ñ'+1) + assert(set[v]); + //specific order is not required, intervals may interesect + auto set2 = CodepointSet('а', 'Ñ'+1, 'a', 'd', 'b', 'z'+1); + //the same end result + assert(set2.byInterval.equal(set.byInterval)); + // test constructor this(Range)(Range intervals) + auto chessPiecesWhite = CodepointInterval(9812, 9818); + auto chessPiecesBlack = CodepointInterval(9818, 9824); + auto set3 = CodepointSet([chessPiecesWhite, chessPiecesBlack]); + foreach (v; 'â™”'..'♟'+1) + assert(set3[v]); + +} + +pure @safe unittest +{ + import std.uni; + + auto gothic = unicode.Gothic; + // Gothic letter ahsa + assert(gothic['\U00010330']); + // no ascii in Gothic obviously + assert(!gothic['$']); + +} + +pure @safe unittest +{ + import std.uni; + + import std.algorithm.comparison : equal; + import std.range : iota; + + auto lower = unicode.LowerCase; + auto upper = unicode.UpperCase; + auto ascii = unicode.ASCII; + + assert((lower & upper).empty); // no intersection + auto lowerASCII = lower & ascii; + assert(lowerASCII.byCodepoint.equal(iota('a', 'z'+1))); + // throw away all of the lowercase ASCII + assert((ascii - lower).length == 128 - 26); + + auto onlyOneOf = lower ~ ascii; + assert(!onlyOneOf['Δ']); // not ASCII and not lowercase + assert(onlyOneOf['$']); // ASCII and not lowercase + assert(!onlyOneOf['a']); // ASCII and lowercase + assert(onlyOneOf['Ñ']); // not ASCII but lowercase + + // throw away all cased letters from ASCII + auto noLetters = ascii - (lower | upper); + assert(noLetters.length == 128 - 26*2); + +} + +pure @safe unittest +{ + import std.uni; + + assert('Ñ' in unicode.Cyrillic); + assert(!('z' in unicode.Cyrillic)); + +} + +pure @safe unittest +{ + import std.uni; + + import std.algorithm.comparison : equal; + import std.range : iota; + + auto set = unicode.ASCII; + set.byCodepoint.equal(iota(0, 0x80)); + +} + +pure @safe unittest +{ + import std.uni; + + import std.conv : to; + import std.format : format; + import std.uni : unicode; + + // This was originally using Cyrillic script. + // Unfortunately this is a pretty active range for changes, + // and hence broke in an update. + // Therefore the range Basic latin was used instead as it + // unlikely to ever change. + + assert(unicode.InBasic_latin.to!string == "[0..128)"); + + // The specs '%s' and '%d' are equivalent to the to!string call above. + assert(format("%d", unicode.InBasic_latin) == unicode.InBasic_latin.to!string); + + assert(format("%#x", unicode.InBasic_latin) == "[0..0x80)"); + assert(format("%#X", unicode.InBasic_latin) == "[0..0X80)"); + +} + +pure @safe unittest +{ + import std.uni; + + CodepointSet someSet; + someSet.add('0', '5').add('A','Z'+1); + someSet.add('5', '9'+1); + assert(someSet['0']); + assert(someSet['5']); + assert(someSet['9']); + assert(someSet['Z']); + +} + +pure @safe unittest +{ + import std.uni; + + auto set = unicode.ASCII; + // union with the inverse gets all of the code points in the Unicode + assert((set | set.inverted).length == 0x110000); + // no intersection with the inverse + assert((set & set.inverted).empty); + +} + +pure @safe unittest +{ + import std.uni; + + CodepointSet emptySet; + assert(emptySet.length == 0); + assert(emptySet.empty); + +} + +pure @safe unittest +{ + import std.uni; + + string truth = "2² = 4"; + auto m = utfMatcher!char(unicode.Number); + assert(m.match(truth)); // '2' is a number all right + assert(truth == "² = 4"); // skips on match + assert(m.match(truth)); // so is the superscript '2' + assert(!m.match(truth)); // space is not a number + assert(truth == " = 4"); // unaffected on no match + assert(!m.skip(truth)); // same test ... + assert(truth == "= 4"); // but skips a codepoint regardless + assert(!m.test(truth)); // '=' is not a number + assert(truth == "= 4"); // test never affects argument + +} + +@safe unittest +{ + import std.uni; + + import std.exception : collectException; + auto ascii = unicode.ASCII; + assert(ascii['A']); + assert(ascii['~']); + assert(!ascii['\u00e0']); + // matching is case-insensitive + assert(ascii == unicode.ascII); + assert(!ascii['à ']); + // underscores, '-' and whitespace in names are ignored too + auto latin = unicode.in_latin1_Supplement; + assert(latin['à ']); + assert(!latin['$']); + // BTW Latin 1 Supplement is a block, hence "In" prefix + assert(latin == unicode("In Latin 1 Supplement")); + // run-time look up throws if no such set is found + assert(collectException(unicode("InCyrilliac"))); + +} + +@safe unittest +{ + import std.uni; + + // use .block for explicitness + assert(unicode.block.Greek_and_Coptic == unicode.InGreek_and_Coptic); + +} + +@safe unittest +{ + import std.uni; + + auto arabicScript = unicode.script.arabic; + auto arabicBlock = unicode.block.arabic; + // there is an intersection between script and block + assert(arabicBlock['Ø']); + assert(arabicScript['Ø']); + // but they are different + assert(arabicBlock != arabicScript); + assert(arabicBlock == unicode.inArabic); + assert(arabicScript == unicode.arabic); + +} + +@safe unittest +{ + import std.uni; + + // L here is syllable type not Letter as in unicode.L short-cut + auto leadingVowel = unicode.hangulSyllableType("L"); + // check that some leading vowels are present + foreach (vowel; '\u1110'..'\u115F') + assert(leadingVowel[vowel]); + assert(leadingVowel == unicode.hangulSyllableType.L); + +} + +@safe unittest +{ + import std.uni; + + import std.uni : unicode; + string pat = "[a-zA-Z0-9]hello"; + auto set = unicode.parseSet(pat); + // check some of the codepoints + assert(set['a'] && set['A'] && set['9']); + assert(pat == "hello"); + +} + +@safe unittest +{ + import std.uni; + + assert(graphemeStride(" ", 1) == 1); + // A + combing ring above + string city = "A\u030Arhus"; + size_t first = graphemeStride(city, 0); + assert(first == 3); //\u030A has 2 UTF-8 code units + assert(city[0 .. first] == "A\u030A"); + assert(city[first..$] == "rhus"); +} + +@safe pure unittest +{ + import std.uni; + + // Two Union Jacks of the Great Britain in each + string s = "\U0001F1EC\U0001F1E7\U0001F1EC\U0001F1E7"; + wstring ws = "\U0001F1EC\U0001F1E7\U0001F1EC\U0001F1E7"; + dstring ds = "\U0001F1EC\U0001F1E7\U0001F1EC\U0001F1E7"; + + // String pop length in code units, not points. + assert(s.popGrapheme() == 8); + assert(ws.popGrapheme() == 4); + assert(ds.popGrapheme() == 2); + + assert(s == "\U0001F1EC\U0001F1E7"); + assert(ws == "\U0001F1EC\U0001F1E7"); + assert(ds == "\U0001F1EC\U0001F1E7"); + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : filter; + + // Also works for non-random access ranges as long as the + // character type is 32-bit. + auto testPiece = "\r\nhello!"d.filter!(x => !x.isAlpha); + // Windows-style line ending is two code points in a single grapheme. + assert(testPiece.popGrapheme() == 2); + assert(testPiece.equal("!"d)); +} + +@safe unittest +{ + import std.uni; + + import std.algorithm.comparison : equal; + import std.range.primitives : walkLength; + import std.range : take, drop; + auto text = "noe\u0308l"; // noël using e + combining diaeresis + assert(text.walkLength == 5); // 5 code points + + auto gText = text.byGrapheme; + assert(gText.walkLength == 4); // 4 graphemes + + assert(gText.take(3).equal("noe\u0308".byGrapheme)); + assert(gText.drop(3).equal("l".byGrapheme)); +} + +@safe unittest +{ + import std.uni; + + import std.array : array; + import std.conv : text; + import std.range : retro; + + string s = "noe\u0308l"; // noël + + // reverse it and convert the result to a string + string reverse = s.byGrapheme + .array + .retro + .byCodePoint + .text; + + assert(reverse == "le\u0308on"); // lëon +} + +@safe unittest +{ + import std.uni; + + auto g = Grapheme("A\u0302"); + assert(g[0] == 'A'); + assert(g.valid); + g[1] = '~'; // ASCII tilda is not a combining mark + assert(g[1] == '~'); + assert(!g.valid); + +} + +@safe unittest +{ + import std.uni; + + import std.algorithm.comparison : equal; + auto g = Grapheme("A"); + assert(g.valid); + g ~= '\u0301'; + assert(g[].equal("A\u0301")); + assert(g.valid); + g ~= "B"; + // not a valid grapheme cluster anymore + assert(!g.valid); + // still could be useful though + assert(g[].equal("A\u0301B")); + +} + +@safe unittest +{ + import std.uni; + + import std.algorithm.comparison : equal; + import std.algorithm.iteration : filter; + import std.range : isRandomAccessRange; + + string bold = "ku\u0308hn"; + + // note that decodeGrapheme takes parameter by ref + auto first = decodeGrapheme(bold); + + assert(first.length == 1); + assert(first[0] == 'k'); + + // the next grapheme is 2 characters long + auto wideOne = decodeGrapheme(bold); + // slicing a grapheme yields a random-access range of dchar + assert(wideOne[].equal("u\u0308")); + assert(wideOne.length == 2); + static assert(isRandomAccessRange!(typeof(wideOne[]))); + + // all of the usual range manipulation is possible + assert(wideOne[].filter!isMark().equal("\u0308")); + + auto g = Grapheme("A"); + assert(g.valid); + g ~= '\u0301'; + assert(g[].equal("A\u0301")); + assert(g.valid); + g ~= "B"; + // not a valid grapheme cluster anymore + assert(!g.valid); + // still could be useful though + assert(g[].equal("A\u0301B")); +} + +@safe @nogc pure nothrow unittest +{ + import std.uni; + + assert(sicmp("ÐвгуÑÑ‚", "авгуÑТ") == 0); + // Greek also works as long as there is no 1:M mapping in sight + assert(sicmp("ΌΎ", "ÏŒÏ") == 0); + // things like the following won't get matched as equal + // Greek small letter iota with dialytika and tonos + assert(sicmp("Î", "\u03B9\u0308\u0301") != 0); + + // while icmp has no problem with that + assert(icmp("Î", "\u03B9\u0308\u0301") == 0); + assert(icmp("ΌΎ", "ÏŒÏ") == 0); +} + +@safe @nogc pure nothrow unittest +{ + import std.uni; + + assert(icmp("Rußland", "Russland") == 0); + assert(icmp("ᾩ -> \u1F70\u03B9", "\u1F61\u03B9 -> á¾²") == 0); +} + +@safe @nogc nothrow pure unittest +{ + import std.uni; + + import std.utf : byDchar; + + assert(icmp("Rußland".byDchar, "Russland".byDchar) == 0); + assert(icmp("ᾩ -> \u1F70\u03B9".byDchar, "\u1F61\u03B9 -> á¾²".byDchar) == 0); +} + +@safe unittest +{ + import std.uni; + + // shorten the code + alias CC = combiningClass; + + // combining tilda + assert(CC('\u0303') == 230); + // combining ring below + assert(CC('\u0325') == 220); + // the simple consequence is that "tilda" should be + // placed after a "ring below" in a sequence +} + +@safe unittest +{ + import std.uni; + + assert(compose('A','\u0308') == '\u00C4'); + assert(compose('A', 'B') == dchar.init); + assert(compose('C', '\u0301') == '\u0106'); + // note that the starter is the first one + // thus the following doesn't compose + assert(compose('\u0308', 'A') == dchar.init); +} + +@safe unittest +{ + import std.uni; + + import std.algorithm.comparison : equal; + + assert(compose('A','\u0308') == '\u00C4'); + assert(compose('A', 'B') == dchar.init); + assert(compose('C', '\u0301') == '\u0106'); + // note that the starter is the first one + // thus the following doesn't compose + assert(compose('\u0308', 'A') == dchar.init); + + assert(decompose('Ĉ')[].equal("C\u0302")); + assert(decompose('D')[].equal("D")); + assert(decompose('\uD4DC')[].equal("\u1111\u1171\u11B7")); + assert(decompose!Compatibility('¹')[].equal("1")); +} + +@safe unittest +{ + import std.uni; + + import std.algorithm.comparison : equal; + assert(decomposeHangul('\uD4DB')[].equal("\u1111\u1171\u11B6")); +} + +@safe unittest +{ + import std.uni; + + assert(composeJamo('\u1111', '\u1171', '\u11B6') == '\uD4DB'); + // leaving out T-vowel, or passing any codepoint + // that is not trailing consonant composes an LV-syllable + assert(composeJamo('\u1111', '\u1171') == '\uD4CC'); + assert(composeJamo('\u1111', '\u1171', ' ') == '\uD4CC'); + assert(composeJamo('\u1111', 'A') == dchar.init); + assert(composeJamo('A', '\u1171') == dchar.init); +} + +@safe pure unittest +{ + import std.uni; + + // any encoding works + wstring greet = "Hello world"; + assert(normalize(greet) is greet); // the same exact slice + + // An example of a character with all 4 forms being different: + // Greek upsilon with acute and hook symbol (code point 0x03D3) + assert(normalize!NFC("Ï“") == "\u03D3"); + assert(normalize!NFD("Ï“") == "\u03D2\u0301"); + assert(normalize!NFKC("Ï“") == "\u038E"); + assert(normalize!NFKD("Ï“") == "\u03A5\u0301"); +} + +@safe unittest +{ + import std.uni; + + // e.g. Cyrillic is always allowed, so is ASCII + assert(allowedIn!NFC('Ñ')); + assert(allowedIn!NFD('Ñ')); + assert(allowedIn!NFKC('Ñ')); + assert(allowedIn!NFKD('Ñ')); + assert(allowedIn!NFC('Z')); +} + +@safe pure unittest +{ + import std.uni; + + import std.algorithm.comparison : equal; + + assert("hEllo".asUpperCase.equal("HELLO")); +} + +@safe pure unittest +{ + import std.uni; + + import std.algorithm.comparison : equal; + + assert("hEllo".asCapitalized.equal("Hello")); +} + +@safe unittest +{ + import std.uni; + + import std.algorithm.iteration : map; + import std.algorithm.mutation : copy; + import std.array : appender; + + auto abuf = appender!(char[])(); + "hello".map!toUpper.copy(abuf); + assert(abuf.data == "HELLO"); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_uri.d b/libphobos/testsuite/libphobos.phobos/std_uri.d new file mode 100644 index 000000000000..5d57062c42ef --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_uri.d @@ -0,0 +1,71 @@ +@safe unittest +{ + import std.uri; + + import std.exception : assertThrown; + assertThrown!URIException("%ab".decode); +} + +@safe unittest +{ + import std.uri; + + assert("foo%20bar".decode == "foo bar"); + assert("%3C%3E.@.%E2%84%A2".decode == "<>.@.â„¢"); + assert("foo&/".decode == "foo&/"); + assert("!@#$&*(".decode == "!@#$&*("); +} + +@safe unittest +{ + import std.uri; + + assert("foo%2F%26".decodeComponent == "foo/&"); + assert("dl%C3%A4ng%20r%C3%B6cks".decodeComponent == "dläng röcks"); + assert("!%40%23%24%25%5E%26*(".decodeComponent == "!@#$%^&*("); +} + +@safe unittest +{ + import std.uri; + + assert("foo bar".encode == "foo%20bar"); + assert("<>.@.â„¢".encode == "%3C%3E.@.%E2%84%A2"); + assert("foo/#?a=1&b=2".encode == "foo/#?a=1&b=2"); + assert("dlang+rocks!".encode == "dlang+rocks!"); + assert("!@#$%^&*(".encode == "!@#$%25%5E&*("); +} + +@safe unittest +{ + import std.uri; + + assert("!@#$%^&*(".encodeComponent == "!%40%23%24%25%5E%26*("); + assert("<>.@.â„¢".encodeComponent == "%3C%3E.%40.%E2%84%A2"); + assert("foo/&".encodeComponent == "foo%2F%26"); + assert("dläng röcks".encodeComponent == "dl%C3%A4ng%20r%C3%B6cks"); + assert("dlang+rocks!".encodeComponent == "dlang%2Brocks!"); +} + +@safe pure unittest +{ + import std.uri; + + string s1 = "http://www.digitalmars.com/~fred/fredsRX.html#foo end!"; + assert(uriLength(s1) == 49); + string s2 = "no uri here"; + assert(uriLength(s2) == -1); + assert(uriLength("issue 14924") < 0); +} + +@safe pure unittest +{ + import std.uri; + + string s1 = "my.e-mail@www.example-domain.com with garbage added"; + assert(emailLength(s1) == 32); + string s2 = "no email address here"; + assert(emailLength(s2) == -1); + assert(emailLength("issue 14924") < 0); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_utf.d b/libphobos/testsuite/libphobos.phobos/std_utf.d new file mode 100644 index 000000000000..e758d488ae01 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_utf.d @@ -0,0 +1,474 @@ +@safe unittest +{ + import std.utf; + + import std.exception : assertThrown; + + char[4] buf; + assertThrown!UTFException(encode(buf, cast(dchar) 0xD800)); + assertThrown!UTFException(encode(buf, cast(dchar) 0xDBFF)); + assertThrown!UTFException(encode(buf, cast(dchar) 0xDC00)); + assertThrown!UTFException(encode(buf, cast(dchar) 0xDFFF)); + assertThrown!UTFException(encode(buf, cast(dchar) 0x110000)); +} + +@safe @nogc pure nothrow unittest +{ + import std.utf; + + assert( isValidDchar(cast(dchar) 0x41)); + assert( isValidDchar(cast(dchar) 0x00)); + assert(!isValidDchar(cast(dchar) 0xD800)); + assert(!isValidDchar(cast(dchar) 0x11FFFF)); +} + +@safe pure nothrow unittest +{ + import std.utf; + + assert( isValidCodepoint(cast(char) 0x40)); + assert(!isValidCodepoint(cast(char) 0x80)); + assert( isValidCodepoint(cast(wchar) 0x1234)); + assert(!isValidCodepoint(cast(wchar) 0xD800)); + assert( isValidCodepoint(cast(dchar) 0x0010FFFF)); + assert(!isValidCodepoint(cast(dchar) 0x12345678)); +} + +@safe unittest +{ + import std.utf; + + assert("a".stride == 1); + assert("λ".stride == 2); + assert("aλ".stride == 1); + assert("aλ".stride(1) == 2); + assert("ð·".stride == 4); +} + +@safe unittest +{ + import std.utf; + + assert("a".strideBack == 1); + assert("λ".strideBack == 2); + assert("aλ".strideBack == 2); + assert("aλ".strideBack(1) == 1); + assert("ð·".strideBack == 4); +} + +@safe unittest +{ + import std.utf; + + assert(toUCSindex(`hello world`, 7) == 7); + assert(toUCSindex(`hello world`w, 7) == 7); + assert(toUCSindex(`hello world`d, 7) == 7); + + assert(toUCSindex(`Ma Chérie`, 7) == 6); + assert(toUCSindex(`Ma Chérie`w, 7) == 7); + assert(toUCSindex(`Ma Chérie`d, 7) == 7); + + assert(toUCSindex(`ã•ã„ã”ã®æžœå®Ÿ / ミツãƒãƒã¨ç§‘å¦è€…`, 9) == 3); + assert(toUCSindex(`ã•ã„ã”ã®æžœå®Ÿ / ミツãƒãƒã¨ç§‘å¦è€…`w, 9) == 9); + assert(toUCSindex(`ã•ã„ã”ã®æžœå®Ÿ / ミツãƒãƒã¨ç§‘å¦è€…`d, 9) == 9); +} + +@safe unittest +{ + import std.utf; + + assert(toUTFindex(`hello world`, 7) == 7); + assert(toUTFindex(`hello world`w, 7) == 7); + assert(toUTFindex(`hello world`d, 7) == 7); + + assert(toUTFindex(`Ma Chérie`, 6) == 7); + assert(toUTFindex(`Ma Chérie`w, 7) == 7); + assert(toUTFindex(`Ma Chérie`d, 7) == 7); + + assert(toUTFindex(`ã•ã„ã”ã®æžœå®Ÿ / ミツãƒãƒã¨ç§‘å¦è€…`, 3) == 9); + assert(toUTFindex(`ã•ã„ã”ã®æžœå®Ÿ / ミツãƒãƒã¨ç§‘å¦è€…`w, 9) == 9); + assert(toUTFindex(`ã•ã„ã”ã®æžœå®Ÿ / ミツãƒãƒã¨ç§‘å¦è€…`d, 9) == 9); +} + +@safe pure unittest +{ + import std.utf; + + size_t i; + + assert("a".decode(i) == 'a' && i == 1); + i = 0; + assert("Ã¥".decode(i) == 'Ã¥' && i == 2); + i = 1; + assert("aÃ¥".decode(i) == 'Ã¥' && i == 3); + i = 0; + assert("Ã¥"w.decode(i) == 'Ã¥' && i == 1); + + // ë as a multi-code point grapheme + i = 0; + assert("e\u0308".decode(i) == 'e' && i == 1); + // ë as a single code point grapheme + i = 0; + assert("ë".decode(i) == 'ë' && i == 2); + i = 0; + assert("ë"w.decode(i) == 'ë' && i == 1); +} + +@safe pure unittest +{ + import std.utf; + + import std.range.primitives; + string str = "Hello, World!"; + + assert(str.decodeFront == 'H' && str == "ello, World!"); + str = "Ã¥"; + assert(str.decodeFront == 'Ã¥' && str.empty); + str = "Ã¥"; + size_t i; + assert(str.decodeFront(i) == 'Ã¥' && i == 2 && str.empty); +} + +@system pure unittest +{ + import std.utf; + + import std.range.primitives; + string str = "Hello, World!"; + + assert(str.decodeBack == '!' && str == "Hello, World"); + str = "Ã¥"; + assert(str.decodeBack == 'Ã¥' && str.empty); + str = "Ã¥"; + size_t i; + assert(str.decodeBack(i) == 'Ã¥' && i == 2 && str.empty); +} + +@safe unittest +{ + import std.utf; + + import std.exception : assertThrown; + import std.typecons : Yes; + + char[4] buf; + + assert(encode(buf, '\u0000') == 1 && buf[0 .. 1] == "\u0000"); + assert(encode(buf, '\u007F') == 1 && buf[0 .. 1] == "\u007F"); + assert(encode(buf, '\u0080') == 2 && buf[0 .. 2] == "\u0080"); + assert(encode(buf, '\uE000') == 3 && buf[0 .. 3] == "\uE000"); + assert(encode(buf, 0xFFFE) == 3 && buf[0 .. 3] == "\xEF\xBF\xBE"); + assertThrown!UTFException(encode(buf, cast(dchar) 0x110000)); + + encode!(Yes.useReplacementDchar)(buf, cast(dchar) 0x110000); + auto slice = buf[]; + assert(slice.decodeFront == replacementDchar); +} + +@safe unittest +{ + import std.utf; + + import std.exception : assertThrown; + import std.typecons : Yes; + + wchar[2] buf; + + assert(encode(buf, '\u0000') == 1 && buf[0 .. 1] == "\u0000"); + assert(encode(buf, '\uD7FF') == 1 && buf[0 .. 1] == "\uD7FF"); + assert(encode(buf, '\uE000') == 1 && buf[0 .. 1] == "\uE000"); + assert(encode(buf, '\U00010000') == 2 && buf[0 .. 2] == "\U00010000"); + assert(encode(buf, '\U0010FFFF') == 2 && buf[0 .. 2] == "\U0010FFFF"); + assertThrown!UTFException(encode(buf, cast(dchar) 0xD800)); + + encode!(Yes.useReplacementDchar)(buf, cast(dchar) 0x110000); + auto slice = buf[]; + assert(slice.decodeFront == replacementDchar); +} + +@safe unittest +{ + import std.utf; + + import std.exception : assertThrown; + import std.typecons : Yes; + + dchar[1] buf; + + assert(encode(buf, '\u0000') == 1 && buf[0] == '\u0000'); + assert(encode(buf, '\uD7FF') == 1 && buf[0] == '\uD7FF'); + assert(encode(buf, '\uE000') == 1 && buf[0] == '\uE000'); + assert(encode(buf, '\U0010FFFF') == 1 && buf[0] == '\U0010FFFF'); + assertThrown!UTFException(encode(buf, cast(dchar) 0xD800)); + + encode!(Yes.useReplacementDchar)(buf, cast(dchar) 0x110000); + assert(buf[0] == replacementDchar); +} + +@safe unittest +{ + import std.utf; + + char[] s = "abcd".dup; + dchar d1 = 'a'; + dchar d2 = 'ø'; + + encode(s, d1); + assert(s.length == 5); + assert(s == "abcda"); + encode(s, d2); + assert(s.length == 7); + assert(s == "abcdaø"); +} + +@safe pure nothrow @nogc unittest +{ + import std.utf; + + assert(codeLength!char('a') == 1); + assert(codeLength!wchar('a') == 1); + assert(codeLength!dchar('a') == 1); + + assert(codeLength!char('\U0010FFFF') == 4); + assert(codeLength!wchar('\U0010FFFF') == 2); + assert(codeLength!dchar('\U0010FFFF') == 1); +} + +@safe unittest +{ + import std.utf; + + assert(codeLength!char("hello world") == + "hello world".length); + assert(codeLength!wchar("hello world") == + "hello world"w.length); + assert(codeLength!dchar("hello world") == + "hello world"d.length); + + assert(codeLength!char(`プãƒã‚°ãƒ©ãƒŸãƒ³ã‚°`) == + `プãƒã‚°ãƒ©ãƒŸãƒ³ã‚°`.length); + assert(codeLength!wchar(`プãƒã‚°ãƒ©ãƒŸãƒ³ã‚°`) == + `プãƒã‚°ãƒ©ãƒŸãƒ³ã‚°`w.length); + assert(codeLength!dchar(`プãƒã‚°ãƒ©ãƒŸãƒ³ã‚°`) == + `プãƒã‚°ãƒ©ãƒŸãƒ³ã‚°`d.length); + + string haystack = `Être sans la verité, ça, ce ne serait pas bien.`; + wstring needle = `Être sans la verité`; + assert(haystack[codeLength!char(needle) .. $] == + `, ça, ce ne serait pas bien.`); +} + +@safe unittest +{ + import std.utf; + + import std.exception : assertThrown; + char[] a = [167, 133, 175]; + assertThrown!UTFException(validate(a)); +} + +@safe pure unittest +{ + import std.utf; + + import std.algorithm.comparison : equal; + + // The ö is represented by two UTF-8 code units + assert("Hellø"w.toUTF8.equal(['H', 'e', 'l', 'l', 0xC3, 0xB8])); + + // ð· is four code units in UTF-8 + assert("ð·"d.toUTF8.equal([0xF0, 0x90, 0x90, 0xB7])); +} + +@safe pure unittest +{ + import std.utf; + + import std.algorithm.comparison : equal; + + // these graphemes are two code units in UTF-16 and one in UTF-32 + assert("ð¤¢"d.length == 1); + assert("ð·"d.length == 1); + + assert("ð¤¢"d.toUTF16.equal([0xD852, 0xDF62])); + assert("ð·"d.toUTF16.equal([0xD801, 0xDC37])); +} + +@safe pure unittest +{ + import std.utf; + + import std.algorithm.comparison : equal; + + // these graphemes are two code units in UTF-16 and one in UTF-32 + assert("ð¤¢"w.length == 2); + assert("ð·"w.length == 2); + + assert("ð¤¢"w.toUTF32.equal([0x00024B62])); + assert("ð·"w.toUTF32.equal([0x00010437])); +} + +@safe pure unittest +{ + import std.utf; + + auto p1 = toUTFz!(char*)("hello world"); + auto p2 = toUTFz!(const(char)*)("hello world"); + auto p3 = toUTFz!(immutable(char)*)("hello world"); + auto p4 = toUTFz!(char*)("hello world"d); + auto p5 = toUTFz!(const(wchar)*)("hello world"); + auto p6 = toUTFz!(immutable(dchar)*)("hello world"w); +} + +@system unittest +{ + import std.utf; + + string str = "Hello, World!"; + const(wchar)* p = str.toUTF16z; + assert(p[str.length] == '\0'); +} + +@safe pure nothrow @nogc unittest +{ + import std.utf; + + assert(count("") == 0); + assert(count("a") == 1); + assert(count("abc") == 3); + assert(count("\u20AC100") == 4); +} + +@safe unittest +{ + import std.utf; + + import std.range.primitives; + import std.traits : isAutodecodableString; + + auto r = "Hello, World!".byCodeUnit(); + static assert(hasLength!(typeof(r))); + static assert(hasSlicing!(typeof(r))); + static assert(isRandomAccessRange!(typeof(r))); + static assert(is(ElementType!(typeof(r)) == immutable char)); + + // contrast with the range capabilities of standard strings (with or + // without autodecoding enabled). + auto s = "Hello, World!"; + static assert(isBidirectionalRange!(typeof(r))); + static if (isAutodecodableString!(typeof(s))) + { + // with autodecoding enabled, strings are non-random-access ranges of + // dchar. + static assert(is(ElementType!(typeof(s)) == dchar)); + static assert(!isRandomAccessRange!(typeof(s))); + static assert(!hasSlicing!(typeof(s))); + static assert(!hasLength!(typeof(s))); + } + else + { + // without autodecoding, strings are normal arrays. + static assert(is(ElementType!(typeof(s)) == immutable char)); + static assert(isRandomAccessRange!(typeof(s))); + static assert(hasSlicing!(typeof(s))); + static assert(hasLength!(typeof(s))); + } +} + +@safe unittest +{ + import std.utf; + + string noel1 = "noe\u0308l"; // noël using e + combining diaeresis + assert(noel1.byCodeUnit[2] != 'ë'); + assert(noel1.byCodeUnit[2] == 'e'); + + string noel2 = "no\u00EBl"; // noël using a precomposed ë character + // Because string is UTF-8, the code unit at index 2 is just + // the first of a sequence that encodes 'ë' + assert(noel2.byCodeUnit[2] != 'ë'); +} + +@safe unittest +{ + import std.utf; + + import std.algorithm.comparison : equal; + import std.range : popFrontN; + import std.traits : isAutodecodableString; + { + auto range = byCodeUnit("hello world"); + range.popFrontN(3); + assert(equal(range.save, "lo world")); + static if (isAutodecodableString!string) // only enabled with autodecoding + { + string str = range.source; + assert(str == "lo world"); + } + } + // source only exists if the range was wrapped + { + auto range = byCodeUnit("hello world"d); + static assert(!__traits(compiles, range.source)); + } +} + +@safe pure nothrow unittest +{ + import std.utf; + + import std.algorithm.comparison : equal; + + // hellö as a range of `char`s, which are UTF-8 + assert("hell\u00F6".byUTF!char().equal(['h', 'e', 'l', 'l', 0xC3, 0xB6])); + + // `wchar`s are able to hold the ö in a single element (UTF-16 code unit) + assert("hell\u00F6".byUTF!wchar().equal(['h', 'e', 'l', 'l', 'ö'])); + + // ð· is four code units in UTF-8, two in UTF-16, and one in UTF-32 + assert("ð·".byUTF!char().equal([0xF0, 0x90, 0x90, 0xB7])); + assert("ð·".byUTF!wchar().equal([0xD801, 0xDC37])); + assert("ð·".byUTF!dchar().equal([0x00010437])); +} + +@safe unittest +{ + import std.utf; + + import std.algorithm.comparison : equal; + import std.exception : assertThrown; + + assert("hello\xF0betty".byChar.byUTF!(dchar, UseReplacementDchar.yes).equal("hello\uFFFDetty")); + assertThrown!UTFException("hello\xF0betty".byChar.byUTF!(dchar, UseReplacementDchar.no).equal("hello betty")); +} + +@safe pure nothrow unittest +{ + import std.utf; + + import std.range.primitives; + wchar[] s = ['ă', 'î']; + + auto rc = s.byUTF!char; + static assert(isBidirectionalRange!(typeof(rc))); + assert(rc.back == 0xae); + rc.popBack; + assert(rc.back == 0xc3); + rc.popBack; + assert(rc.back == 0x83); + rc.popBack; + assert(rc.back == 0xc4); + + auto rw = s.byUTF!wchar; + static assert(isBidirectionalRange!(typeof(rw))); + assert(rw.back == 'î'); + rw.popBack; + assert(rw.back == 'ă'); + + auto rd = s.byUTF!dchar; + static assert(isBidirectionalRange!(typeof(rd))); + assert(rd.back == 'î'); + rd.popBack; + assert(rd.back == 'ă'); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_uuid.d b/libphobos/testsuite/libphobos.phobos/std_uuid.d new file mode 100644 index 000000000000..2486083cd26c --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_uuid.d @@ -0,0 +1,252 @@ +@safe unittest +{ + import std.uuid; + + import std.uuid; + + UUID[] ids; + ids ~= randomUUID(); + ids ~= md5UUID("test.name.123"); + ids ~= sha1UUID("test.name.123"); + + foreach (entry; ids) + { + assert(entry.variant == UUID.Variant.rfc4122); + } + assert(ids[0].uuidVersion == UUID.Version.randomNumberBased); + assert(ids[1].toString() == "22390768-cced-325f-8f0f-cfeaa19d0ccd"); + assert(ids[1].data == [34, 57, 7, 104, 204, 237, 50, 95, 143, 15, 207, + 234, 161, 157, 12, 205]); + UUID id; + assert(id.empty); +} + +@safe pure unittest +{ + import std.uuid; + + enum ubyte[16] data = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]; + auto uuid = UUID(data); + enum ctfe = UUID(data); + assert(uuid.data == data); + assert(ctfe.data == data); + +} + +@safe unittest +{ + import std.uuid; + + auto tmp = UUID(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15); + assert(tmp.data == cast(ubyte[16])[0,1,2,3,4,5,6,7,8,9,10,11, + 12,13,14,15]); + +} + +@safe pure unittest +{ + import std.uuid; + + auto id = UUID("8AB3060E-2cba-4f23-b74c-b52db3bdfb46"); + assert(id.data == [138, 179, 6, 14, 44, 186, 79, 35, 183, 76, + 181, 45, 179, 189, 251, 70]); + assert(id.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46"); + + //Can also be used in CTFE, for example as UUID literals: + enum ctfeID = UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"); + //here parsing is done at compile time, no runtime overhead! + +} + +@safe pure unittest +{ + import std.uuid; + + UUID id; + assert(id.empty); + id = UUID("00000000-0000-0000-0000-000000000001"); + assert(!id.empty); + +} + +@safe pure unittest +{ + import std.uuid; + + assert(UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46").variant + == UUID.Variant.rfc4122); + +} + +@safe unittest +{ + import std.uuid; + + assert(UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46").uuidVersion + == UUID.Version.randomNumberBased); + +} + +@safe unittest +{ + import std.uuid; + + immutable ubyte[16] data = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]; + UUID u1; + UUID u2 = UUID(data); + u1.swap(u2); + + assert(u1 == UUID(data)); + assert(u2 == UUID.init); + +} + +@safe pure unittest +{ + import std.uuid; + + //compare UUIDs + assert(UUID("00000000-0000-0000-0000-000000000000") == UUID.init); + + //UUIDs in associative arrays: + int[UUID] test = [UUID("8a94f585-d180-44f7-8929-6fca0189c7d0") : 1, + UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a") : 2, + UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1") : 3]; + + assert(test[UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")] == 3); + + //UUIDS can be sorted: + import std.algorithm; + UUID[] ids = [UUID("8a94f585-d180-44f7-8929-6fca0189c7d0"), + UUID("7c351fd4-b860-4ee3-bbdc-7f79f3dfb00a"), + UUID("9ac0a4e5-10ee-493a-86fc-d29eeb82ecc1")]; + sort(ids); + +} + +@safe pure unittest +{ + import std.uuid; + + immutable str = "8ab3060e-2cba-4f23-b74c-b52db3bdfb46"; + auto id = UUID(str); + assert(id.toString() == str); + +} + +@safe unittest +{ + import std.uuid; + + UUID id; + assert(id.empty); + + id = randomUUID; + assert(!id.empty); + + id = UUID(cast(ubyte[16]) [138, 179, 6, 14, 44, 186, 79, + 35, 183, 76, 181, 45, 179, 189, 251, 70]); + assert(id.toString() == "8ab3060e-2cba-4f23-b74c-b52db3bdfb46"); +} + +@safe unittest +{ + import std.uuid; + + //Use default UUID.init namespace + auto simpleID = md5UUID("test.uuid.any.string"); + + //use a name-based id as namespace + auto namespace = md5UUID("my.app"); + auto id = md5UUID("some-description", namespace); +} + +@safe unittest +{ + import std.uuid; + + //Use default UUID.init namespace + auto simpleID = sha1UUID("test.uuid.any.string"); + + //use a name-based id as namespace + auto namespace = sha1UUID("my.app"); + auto id = sha1UUID("some-description", namespace); +} + +@safe unittest +{ + import std.uuid; + + import std.random : Xorshift192, unpredictableSeed; + + //simple call + auto uuid = randomUUID(); + + //provide a custom RNG. Must be seeded manually. + Xorshift192 gen; + + gen.seed(unpredictableSeed); + auto uuid3 = randomUUID(gen); +} + +@safe unittest +{ + import std.uuid; + + auto id = parseUUID("8AB3060E-2CBA-4F23-b74c-B52Db3BDFB46"); + //no dashes + id = parseUUID("8ab3060e2cba4f23b74cb52db3bdfb46"); + //dashes at different positions + id = parseUUID("8a-b3-06-0e2cba4f23b74c-b52db3bdfb-46"); + //leading / trailing characters + id = parseUUID("{8ab3060e-2cba-4f23-b74c-b52db3bdfb46}"); + //unicode + id = parseUUID("ü8ab3060e2cba4f23b74cb52db3bdfb46ü"); + //multiple trailing/leading characters + id = parseUUID("///8ab3060e2cba4f23b74cb52db3bdfb46||"); + + //Can also be used in CTFE, for example as UUID literals: + enum ctfeID = parseUUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"); + //here parsing is done at compile time, no runtime overhead! +} + +@safe unittest +{ + import std.uuid; + + import std.algorithm; + import std.regex; + + string test = "Lorem ipsum dolor sit amet, consetetur "~ + "6ba7b814-9dad-11d1-80b4-00c04fd430c8 sadipscing \n"~ + "elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore \r\n"~ + "magna aliquyam erat, sed diam voluptua. "~ + "8ab3060e-2cba-4f23-b74c-b52db3bdfb46 At vero eos et accusam et "~ + "justo duo dolores et ea rebum."; + + auto r = regex(uuidRegex, "g"); + UUID[] found; + foreach (c; match(test, r)) + { + found ~= UUID(c.hit); + } + assert(found == [ + UUID("6ba7b814-9dad-11d1-80b4-00c04fd430c8"), + UUID("8ab3060e-2cba-4f23-b74c-b52db3bdfb46"), + ]); +} + +@safe unittest +{ + import std.uuid; + + import std.exception : collectException; + + const inputUUID = "this-is-an-invalid-uuid"; + auto ex = collectException!UUIDParsingException(UUID(inputUUID)); + assert(ex !is null); // check that exception was thrown + assert(ex.input == inputUUID); + assert(ex.position == 0); + assert(ex.reason == UUIDParsingException.Reason.tooLittle); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_variant.d b/libphobos/testsuite/libphobos.phobos/std_variant.d new file mode 100644 index 000000000000..374dd7852aa7 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_variant.d @@ -0,0 +1,291 @@ +@system unittest +{ + import std.variant; + + Variant a; // Must assign before use, otherwise exception ensues + // Initialize with an integer; make the type int + Variant b = 42; + assert(b.type == typeid(int)); + // Peek at the value + assert(b.peek!(int) !is null && *b.peek!(int) == 42); + // Automatically convert per language rules + auto x = b.get!(real); + + // Assign any other type, including other variants + a = b; + a = 3.14; + assert(a.type == typeid(double)); + // Implicit conversions work just as with built-in types + assert(a < b); + // Check for convertibility + assert(!a.convertsTo!(int)); // double not convertible to int + // Strings and all other arrays are supported + a = "now I'm a string"; + assert(a == "now I'm a string"); + + // can also assign arrays + a = new int[42]; + assert(a.length == 42); + a[5] = 7; + assert(a[5] == 7); + + // Can also assign class values + class Foo {} + auto foo = new Foo; + a = foo; + assert(*a.peek!(Foo) == foo); // and full type information is preserved +} + +@safe unittest +{ + import std.variant; + + struct Cat { int a, b, c; } + + align(1) struct S + { + long l; + ubyte b; + } + + align(1) struct T + { + ubyte b; + long l; + } + + static assert(maxSize!(int, long) == 8); + static assert(maxSize!(bool, byte) == 1); + static assert(maxSize!(bool, Cat) == 12); + static assert(maxSize!(char) == 1); + static assert(maxSize!(char, short, ubyte) == 2); + static assert(maxSize!(char, long, ubyte) == 8); + import std.algorithm.comparison : max; + static assert(maxSize!(long, S) == max(long.sizeof, S.sizeof)); + static assert(maxSize!(S, T) == max(S.sizeof, T.sizeof)); + static assert(maxSize!(int, ubyte[7]) == 7); + static assert(maxSize!(int, ubyte[3]) == 4); + static assert(maxSize!(int, int, ubyte[3]) == 4); + static assert(maxSize!(void, int, ubyte[3]) == 4); + static assert(maxSize!(void) == 1); +} + +@system unittest +{ + import std.variant; + + alias Var = VariantN!(maxSize!(int, double, string)); + + Var a; // Must assign before use, otherwise exception ensues + // Initialize with an integer; make the type int + Var b = 42; + assert(b.type == typeid(int)); + // Peek at the value + assert(b.peek!(int) !is null && *b.peek!(int) == 42); + // Automatically convert per language rules + auto x = b.get!(real); + + // Assign any other type, including other variants + a = b; + a = 3.14; + assert(a.type == typeid(double)); + // Implicit conversions work just as with built-in types + assert(a < b); + // Check for convertibility + assert(!a.convertsTo!(int)); // double not convertible to int + // Strings and all other arrays are supported + a = "now I'm a string"; + assert(a == "now I'm a string"); +} + +@system unittest +{ + import std.variant; + + alias Var = VariantN!(maxSize!(int[])); + + Var a = new int[42]; + assert(a.length == 42); + a[5] = 7; + assert(a[5] == 7); +} + +@system unittest +{ + import std.variant; + + alias Var = VariantN!(maxSize!(int*)); // classes are pointers + Var a; + + class Foo {} + auto foo = new Foo; + a = foo; + assert(*a.peek!(Foo) == foo); // and full type information is preserved +} + +@system unittest +{ + import std.variant; + + auto v = Algebraic!(int, double, string)(5); + assert(v.peek!(int)); + v = 3.14; + assert(v.peek!(double)); + // auto x = v.peek!(long); // won't compile, type long not allowed + // v = '1'; // won't compile, type char not allowed +} + +@system unittest +{ + import std.variant; + + import std.typecons : Tuple, tuple; + + // A tree is either a leaf or a branch of two other trees + alias Tree(Leaf) = Algebraic!(Leaf, Tuple!(This*, This*)); + Tree!int tree = tuple(new Tree!int(42), new Tree!int(43)); + Tree!int* right = tree.get!1[1]; + assert(*right == 43); + + // An object is a double, a string, or a hash of objects + alias Obj = Algebraic!(double, string, This[string]); + Obj obj = "hello"; + assert(obj.get!1 == "hello"); + obj = 42.0; + assert(obj.get!0 == 42); + obj = ["customer": Obj("John"), "paid": Obj(23.95)]; + assert(obj.get!2["customer"] == "John"); +} + +@system unittest +{ + import std.variant; + + Variant a; // Must assign before use, otherwise exception ensues + // Initialize with an integer; make the type int + Variant b = 42; + assert(b.type == typeid(int)); + // Peek at the value + assert(b.peek!(int) !is null && *b.peek!(int) == 42); + // Automatically convert per language rules + auto x = b.get!(real); + + // Assign any other type, including other variants + a = b; + a = 3.14; + assert(a.type == typeid(double)); + // Implicit conversions work just as with built-in types + assert(a < b); + // Check for convertibility + assert(!a.convertsTo!(int)); // double not convertible to int + // Strings and all other arrays are supported + a = "now I'm a string"; + assert(a == "now I'm a string"); +} + +@system unittest +{ + import std.variant; + + Variant a = new int[42]; + assert(a.length == 42); + a[5] = 7; + assert(a[5] == 7); +} + +@system unittest +{ + import std.variant; + + Variant a; + + class Foo {} + auto foo = new Foo; + a = foo; + assert(*a.peek!(Foo) == foo); // and full type information is preserved +} + +@system unittest +{ + import std.variant; + + auto a = variantArray(1, 3.14, "Hi!"); + assert(a[1] == 3.14); + auto b = Variant(a); // variant array as variant + assert(b[1] == 3.14); +} + +@system unittest +{ + import std.variant; + + import std.exception : assertThrown; + + Variant v; + + // uninitialized use + assertThrown!VariantException(v + 1); + assertThrown!VariantException(v.length); + + // .get with an incompatible target type + assertThrown!VariantException(Variant("a").get!int); + + // comparison between incompatible types + assertThrown!VariantException(Variant(3) < Variant("a")); +} + +@system unittest +{ + import std.variant; + + Algebraic!(int, string) variant; + + variant = 10; + assert(variant.visit!((string s) => cast(int) s.length, + (int i) => i)() + == 10); + variant = "string"; + assert(variant.visit!((int i) => i, + (string s) => cast(int) s.length)() + == 6); + + // Error function usage + Algebraic!(int, string) emptyVar; + auto rslt = emptyVar.visit!((string s) => cast(int) s.length, + (int i) => i, + () => -1)(); + assert(rslt == -1); + + // Generic function usage + Algebraic!(int, float, real) number = 2; + assert(number.visit!(x => x += 1) == 3); + + // Generic function for int/float with separate behavior for string + Algebraic!(int, float, string) something = 2; + assert(something.visit!((string s) => s.length, x => x) == 2); // generic + something = "asdf"; + assert(something.visit!((string s) => s.length, x => x) == 4); // string + + // Generic handler and empty handler + Algebraic!(int, float, real) empty2; + assert(empty2.visit!(x => x + 1, () => -1) == -1); +} + +@system unittest +{ + import std.variant; + + Algebraic!(int, string) variant; + + variant = 10; + auto which = -1; + variant.tryVisit!((int i) { which = 0; })(); + assert(which == 0); + + // Error function usage + variant = "test"; + variant.tryVisit!((int i) { which = 0; }, + () { which = -100; })(); + assert(which == -100); +} + diff --git a/libphobos/testsuite/libphobos.phobos/std_zlib.d b/libphobos/testsuite/libphobos.phobos/std_zlib.d new file mode 100644 index 000000000000..3cc9462b6898 --- /dev/null +++ b/libphobos/testsuite/libphobos.phobos/std_zlib.d @@ -0,0 +1,29 @@ +@system unittest +{ + import std.zlib; + + static ubyte[] data = [1,2,3,4,5,6,7,8,9,10]; + + uint adler = adler32(0u, data); + assert(adler == 0xdc0037); +} + +@system unittest +{ + import std.zlib; + + // some random data + ubyte[1024] originalData = void; + + // append garbage data (or don't, this works in both cases) + auto compressedData = cast(ubyte[]) compress(originalData) ~ cast(ubyte[]) "whatever"; + + auto decompressor = new UnCompress(); + auto uncompressedData = decompressor.uncompress(compressedData); + + assert(uncompressedData[] == originalData[], + "The uncompressed and the original data differ"); + assert(decompressor.empty, "The UnCompressor reports not being done"); + +} + -- GitLab