diff options
-rw-r--r-- | .gitignore (renamed from geom_bottleneck/.gitignore) | 1 | ||||
-rw-r--r-- | README.txt | 15 | ||||
-rw-r--r-- | bottleneck/CMakeLists.txt (renamed from geom_bottleneck/CMakeLists.txt) | 0 | ||||
-rw-r--r-- | bottleneck/README (renamed from geom_bottleneck/README) | 2 | ||||
-rw-r--r-- | bottleneck/example/CMakeLists.txt (renamed from geom_bottleneck/example/CMakeLists.txt) | 0 | ||||
-rw-r--r-- | bottleneck/example/bottleneck_dist.cpp (renamed from geom_bottleneck/example/bottleneck_dist.cpp) | 0 | ||||
-rw-r--r-- | bottleneck/include/basic_defs_bt.h (renamed from geom_bottleneck/include/basic_defs_bt.h) | 0 | ||||
-rw-r--r-- | bottleneck/include/bottleneck.h (renamed from geom_bottleneck/include/bottleneck.h) | 0 | ||||
-rw-r--r-- | bottleneck/include/bottleneck_detail.h (renamed from geom_bottleneck/include/bottleneck_detail.h) | 0 | ||||
-rw-r--r-- | bottleneck/include/bottleneck_detail.hpp (renamed from geom_bottleneck/include/bottleneck_detail.hpp) | 0 | ||||
-rw-r--r-- | bottleneck/include/bound_match.h (renamed from geom_bottleneck/include/bound_match.h) | 0 | ||||
-rw-r--r-- | bottleneck/include/bound_match.hpp (renamed from geom_bottleneck/include/bound_match.hpp) | 0 | ||||
-rw-r--r-- | bottleneck/include/catch/catch.hpp (renamed from geom_bottleneck/include/catch/catch.hpp) | 0 | ||||
-rw-r--r-- | bottleneck/include/def_debug_bt.h (renamed from geom_bottleneck/include/def_debug_bt.h) | 0 | ||||
-rw-r--r-- | bottleneck/include/diagram_reader.h (renamed from geom_bottleneck/include/diagram_reader.h) | 0 | ||||
-rw-r--r-- | bottleneck/include/diagram_traits.h (renamed from geom_bottleneck/include/diagram_traits.h) | 0 | ||||
-rw-r--r-- | bottleneck/include/dnn/geometry/euclidean-fixed.h (renamed from geom_bottleneck/include/dnn/geometry/euclidean-fixed.h) | 0 | ||||
-rw-r--r-- | bottleneck/include/dnn/local/kd-tree.h (renamed from geom_bottleneck/include/dnn/local/kd-tree.h) | 0 | ||||
-rw-r--r-- | bottleneck/include/dnn/local/kd-tree.hpp (renamed from geom_bottleneck/include/dnn/local/kd-tree.hpp) | 0 | ||||
-rw-r--r-- | bottleneck/include/dnn/local/search-functors.h (renamed from geom_bottleneck/include/dnn/local/search-functors.h) | 0 | ||||
-rw-r--r-- | bottleneck/include/dnn/parallel/tbb.h (renamed from geom_bottleneck/include/dnn/parallel/tbb.h) | 0 | ||||
-rw-r--r-- | bottleneck/include/dnn/parallel/utils.h (renamed from geom_bottleneck/include/dnn/parallel/utils.h) | 0 | ||||
-rw-r--r-- | bottleneck/include/dnn/utils.h (renamed from geom_bottleneck/include/dnn/utils.h) | 0 | ||||
-rw-r--r-- | bottleneck/include/neighb_oracle.h (renamed from geom_bottleneck/include/neighb_oracle.h) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_001_A (renamed from geom_bottleneck/tests/data/test_001_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_001_B (renamed from geom_bottleneck/tests/data/test_001_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_002_A (renamed from geom_bottleneck/tests/data/test_002_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_002_B (renamed from geom_bottleneck/tests/data/test_002_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_003_A (renamed from geom_bottleneck/tests/data/test_003_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_003_B (renamed from geom_bottleneck/tests/data/test_003_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_004_A (renamed from geom_bottleneck/tests/data/test_004_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_004_B (renamed from geom_bottleneck/tests/data/test_004_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_005_A (renamed from geom_bottleneck/tests/data/test_005_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_005_B (renamed from geom_bottleneck/tests/data/test_005_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_006_A (renamed from geom_bottleneck/tests/data/test_006_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_006_B (renamed from geom_bottleneck/tests/data/test_006_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_007_A (renamed from geom_bottleneck/tests/data/test_007_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_007_B (renamed from geom_bottleneck/tests/data/test_007_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_008_A (renamed from geom_bottleneck/tests/data/test_008_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_008_B (renamed from geom_bottleneck/tests/data/test_008_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_009_A (renamed from geom_bottleneck/tests/data/test_009_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_009_B (renamed from geom_bottleneck/tests/data/test_009_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_010_A (renamed from geom_bottleneck/tests/data/test_010_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_010_B (renamed from geom_bottleneck/tests/data/test_010_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_011_A (renamed from geom_bottleneck/tests/data/test_011_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_011_B (renamed from geom_bottleneck/tests/data/test_011_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_012_A (renamed from geom_bottleneck/tests/data/test_012_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_012_B (renamed from geom_bottleneck/tests/data/test_012_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_013_A (renamed from geom_bottleneck/tests/data/test_013_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_013_B (renamed from geom_bottleneck/tests/data/test_013_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_014_A (renamed from geom_bottleneck/tests/data/test_014_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_014_B (renamed from geom_bottleneck/tests/data/test_014_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_015_A (renamed from geom_bottleneck/tests/data/test_015_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_015_B (renamed from geom_bottleneck/tests/data/test_015_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_016_A (renamed from geom_bottleneck/tests/data/test_016_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_016_B (renamed from geom_bottleneck/tests/data/test_016_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_100_A (renamed from geom_bottleneck/tests/data/test_100_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_100_B (renamed from geom_bottleneck/tests/data/test_100_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_101_A (renamed from geom_bottleneck/tests/data/test_101_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_101_B (renamed from geom_bottleneck/tests/data/test_101_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_102_A (renamed from geom_bottleneck/tests/data/test_102_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_102_B (renamed from geom_bottleneck/tests/data/test_102_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_103_A (renamed from geom_bottleneck/tests/data/test_103_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_103_B (renamed from geom_bottleneck/tests/data/test_103_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_104_A (renamed from geom_bottleneck/tests/data/test_104_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_104_B (renamed from geom_bottleneck/tests/data/test_104_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_105_A (renamed from geom_bottleneck/tests/data/test_105_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_105_B (renamed from geom_bottleneck/tests/data/test_105_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_106_A (renamed from geom_bottleneck/tests/data/test_106_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_106_B (renamed from geom_bottleneck/tests/data/test_106_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_107_A (renamed from geom_bottleneck/tests/data/test_107_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_107_B (renamed from geom_bottleneck/tests/data/test_107_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_108_A (renamed from geom_bottleneck/tests/data/test_108_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_108_B (renamed from geom_bottleneck/tests/data/test_108_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_109_A (renamed from geom_bottleneck/tests/data/test_109_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_109_B (renamed from geom_bottleneck/tests/data/test_109_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_110_A (renamed from geom_bottleneck/tests/data/test_110_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_110_B (renamed from geom_bottleneck/tests/data/test_110_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_111_A (renamed from geom_bottleneck/tests/data/test_111_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_111_B (renamed from geom_bottleneck/tests/data/test_111_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_112_A (renamed from geom_bottleneck/tests/data/test_112_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_112_B (renamed from geom_bottleneck/tests/data/test_112_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_113_A (renamed from geom_bottleneck/tests/data/test_113_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_113_B (renamed from geom_bottleneck/tests/data/test_113_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_114_A (renamed from geom_bottleneck/tests/data/test_114_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_114_B (renamed from geom_bottleneck/tests/data/test_114_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_115_A (renamed from geom_bottleneck/tests/data/test_115_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_115_B (renamed from geom_bottleneck/tests/data/test_115_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_116_A (renamed from geom_bottleneck/tests/data/test_116_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_116_B (renamed from geom_bottleneck/tests/data/test_116_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_117_A (renamed from geom_bottleneck/tests/data/test_117_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_117_B (renamed from geom_bottleneck/tests/data/test_117_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_118_A (renamed from geom_bottleneck/tests/data/test_118_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_118_B (renamed from geom_bottleneck/tests/data/test_118_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_119_A (renamed from geom_bottleneck/tests/data/test_119_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_119_B (renamed from geom_bottleneck/tests/data/test_119_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_120_A (renamed from geom_bottleneck/tests/data/test_120_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_120_B (renamed from geom_bottleneck/tests/data/test_120_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_121_A (renamed from geom_bottleneck/tests/data/test_121_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_121_B (renamed from geom_bottleneck/tests/data/test_121_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_122_A (renamed from geom_bottleneck/tests/data/test_122_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_122_B (renamed from geom_bottleneck/tests/data/test_122_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_123_A (renamed from geom_bottleneck/tests/data/test_123_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_123_B (renamed from geom_bottleneck/tests/data/test_123_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_124_A (renamed from geom_bottleneck/tests/data/test_124_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_124_B (renamed from geom_bottleneck/tests/data/test_124_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_125_A (renamed from geom_bottleneck/tests/data/test_125_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_125_B (renamed from geom_bottleneck/tests/data/test_125_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_126_A (renamed from geom_bottleneck/tests/data/test_126_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_126_B (renamed from geom_bottleneck/tests/data/test_126_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_127_A (renamed from geom_bottleneck/tests/data/test_127_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_127_B (renamed from geom_bottleneck/tests/data/test_127_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_128_A (renamed from geom_bottleneck/tests/data/test_128_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_128_B (renamed from geom_bottleneck/tests/data/test_128_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_129_A (renamed from geom_bottleneck/tests/data/test_129_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_129_B (renamed from geom_bottleneck/tests/data/test_129_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_130_A (renamed from geom_bottleneck/tests/data/test_130_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_130_B (renamed from geom_bottleneck/tests/data/test_130_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_131_A (renamed from geom_bottleneck/tests/data/test_131_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_131_B (renamed from geom_bottleneck/tests/data/test_131_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_132_A (renamed from geom_bottleneck/tests/data/test_132_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_132_B (renamed from geom_bottleneck/tests/data/test_132_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_133_A (renamed from geom_bottleneck/tests/data/test_133_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_133_B (renamed from geom_bottleneck/tests/data/test_133_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_134_A (renamed from geom_bottleneck/tests/data/test_134_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_134_B (renamed from geom_bottleneck/tests/data/test_134_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_135_A (renamed from geom_bottleneck/tests/data/test_135_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_135_B (renamed from geom_bottleneck/tests/data/test_135_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_136_A (renamed from geom_bottleneck/tests/data/test_136_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_136_B (renamed from geom_bottleneck/tests/data/test_136_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_137_A (renamed from geom_bottleneck/tests/data/test_137_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_137_B (renamed from geom_bottleneck/tests/data/test_137_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_138_A (renamed from geom_bottleneck/tests/data/test_138_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_138_B (renamed from geom_bottleneck/tests/data/test_138_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_139_A (renamed from geom_bottleneck/tests/data/test_139_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_139_B (renamed from geom_bottleneck/tests/data/test_139_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_140_A (renamed from geom_bottleneck/tests/data/test_140_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_140_B (renamed from geom_bottleneck/tests/data/test_140_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_141_A (renamed from geom_bottleneck/tests/data/test_141_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_141_B (renamed from geom_bottleneck/tests/data/test_141_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_142_A (renamed from geom_bottleneck/tests/data/test_142_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_142_B (renamed from geom_bottleneck/tests/data/test_142_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_143_A (renamed from geom_bottleneck/tests/data/test_143_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_143_B (renamed from geom_bottleneck/tests/data/test_143_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_144_A (renamed from geom_bottleneck/tests/data/test_144_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_144_B (renamed from geom_bottleneck/tests/data/test_144_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_145_A (renamed from geom_bottleneck/tests/data/test_145_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_145_B (renamed from geom_bottleneck/tests/data/test_145_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_146_A (renamed from geom_bottleneck/tests/data/test_146_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_146_B (renamed from geom_bottleneck/tests/data/test_146_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_147_A (renamed from geom_bottleneck/tests/data/test_147_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_147_B (renamed from geom_bottleneck/tests/data/test_147_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_148_A (renamed from geom_bottleneck/tests/data/test_148_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_148_B (renamed from geom_bottleneck/tests/data/test_148_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_149_A (renamed from geom_bottleneck/tests/data/test_149_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_149_B (renamed from geom_bottleneck/tests/data/test_149_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_150_A (renamed from geom_bottleneck/tests/data/test_150_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_150_B (renamed from geom_bottleneck/tests/data/test_150_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_151_A (renamed from geom_bottleneck/tests/data/test_151_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_151_B (renamed from geom_bottleneck/tests/data/test_151_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_152_A (renamed from geom_bottleneck/tests/data/test_152_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_152_B (renamed from geom_bottleneck/tests/data/test_152_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_153_A (renamed from geom_bottleneck/tests/data/test_153_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_153_B (renamed from geom_bottleneck/tests/data/test_153_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_154_A (renamed from geom_bottleneck/tests/data/test_154_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_154_B (renamed from geom_bottleneck/tests/data/test_154_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_155_A (renamed from geom_bottleneck/tests/data/test_155_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_155_B (renamed from geom_bottleneck/tests/data/test_155_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_156_A (renamed from geom_bottleneck/tests/data/test_156_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_156_B (renamed from geom_bottleneck/tests/data/test_156_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_157_A (renamed from geom_bottleneck/tests/data/test_157_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_157_B (renamed from geom_bottleneck/tests/data/test_157_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_158_A (renamed from geom_bottleneck/tests/data/test_158_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_158_B (renamed from geom_bottleneck/tests/data/test_158_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_159_A (renamed from geom_bottleneck/tests/data/test_159_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_159_B (renamed from geom_bottleneck/tests/data/test_159_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_160_A (renamed from geom_bottleneck/tests/data/test_160_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_160_B (renamed from geom_bottleneck/tests/data/test_160_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_161_A (renamed from geom_bottleneck/tests/data/test_161_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_161_B (renamed from geom_bottleneck/tests/data/test_161_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_162_A (renamed from geom_bottleneck/tests/data/test_162_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_162_B (renamed from geom_bottleneck/tests/data/test_162_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_163_A (renamed from geom_bottleneck/tests/data/test_163_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_163_B (renamed from geom_bottleneck/tests/data/test_163_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_164_A (renamed from geom_bottleneck/tests/data/test_164_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_164_B (renamed from geom_bottleneck/tests/data/test_164_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_165_A (renamed from geom_bottleneck/tests/data/test_165_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_165_B (renamed from geom_bottleneck/tests/data/test_165_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_166_A (renamed from geom_bottleneck/tests/data/test_166_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_166_B (renamed from geom_bottleneck/tests/data/test_166_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_167_A (renamed from geom_bottleneck/tests/data/test_167_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_167_B (renamed from geom_bottleneck/tests/data/test_167_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_168_A (renamed from geom_bottleneck/tests/data/test_168_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_168_B (renamed from geom_bottleneck/tests/data/test_168_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_169_A (renamed from geom_bottleneck/tests/data/test_169_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_169_B (renamed from geom_bottleneck/tests/data/test_169_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_170_A (renamed from geom_bottleneck/tests/data/test_170_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_170_B (renamed from geom_bottleneck/tests/data/test_170_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_171_A (renamed from geom_bottleneck/tests/data/test_171_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_171_B (renamed from geom_bottleneck/tests/data/test_171_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_172_A (renamed from geom_bottleneck/tests/data/test_172_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_172_B (renamed from geom_bottleneck/tests/data/test_172_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_173_A (renamed from geom_bottleneck/tests/data/test_173_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_173_B (renamed from geom_bottleneck/tests/data/test_173_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_174_A (renamed from geom_bottleneck/tests/data/test_174_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_174_B (renamed from geom_bottleneck/tests/data/test_174_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_175_A (renamed from geom_bottleneck/tests/data/test_175_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_175_B (renamed from geom_bottleneck/tests/data/test_175_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_176_A (renamed from geom_bottleneck/tests/data/test_176_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_176_B (renamed from geom_bottleneck/tests/data/test_176_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_177_A (renamed from geom_bottleneck/tests/data/test_177_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_177_B (renamed from geom_bottleneck/tests/data/test_177_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_178_A (renamed from geom_bottleneck/tests/data/test_178_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_178_B (renamed from geom_bottleneck/tests/data/test_178_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_179_A (renamed from geom_bottleneck/tests/data/test_179_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_179_B (renamed from geom_bottleneck/tests/data/test_179_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_180_A (renamed from geom_bottleneck/tests/data/test_180_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_180_B (renamed from geom_bottleneck/tests/data/test_180_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_181_A (renamed from geom_bottleneck/tests/data/test_181_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_181_B (renamed from geom_bottleneck/tests/data/test_181_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_182_A (renamed from geom_bottleneck/tests/data/test_182_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_182_B (renamed from geom_bottleneck/tests/data/test_182_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_183_A (renamed from geom_bottleneck/tests/data/test_183_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_183_B (renamed from geom_bottleneck/tests/data/test_183_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_184_A (renamed from geom_bottleneck/tests/data/test_184_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_184_B (renamed from geom_bottleneck/tests/data/test_184_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_185_A (renamed from geom_bottleneck/tests/data/test_185_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_185_B (renamed from geom_bottleneck/tests/data/test_185_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_186_A (renamed from geom_bottleneck/tests/data/test_186_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_186_B (renamed from geom_bottleneck/tests/data/test_186_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_187_A (renamed from geom_bottleneck/tests/data/test_187_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_187_B (renamed from geom_bottleneck/tests/data/test_187_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_188_A (renamed from geom_bottleneck/tests/data/test_188_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_188_B (renamed from geom_bottleneck/tests/data/test_188_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_189_A (renamed from geom_bottleneck/tests/data/test_189_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_189_B (renamed from geom_bottleneck/tests/data/test_189_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_190_A (renamed from geom_bottleneck/tests/data/test_190_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_190_B (renamed from geom_bottleneck/tests/data/test_190_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_191_A (renamed from geom_bottleneck/tests/data/test_191_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_191_B (renamed from geom_bottleneck/tests/data/test_191_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_192_A (renamed from geom_bottleneck/tests/data/test_192_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_192_B (renamed from geom_bottleneck/tests/data/test_192_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_193_A (renamed from geom_bottleneck/tests/data/test_193_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_193_B (renamed from geom_bottleneck/tests/data/test_193_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_194_A (renamed from geom_bottleneck/tests/data/test_194_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_194_B (renamed from geom_bottleneck/tests/data/test_194_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_195_A (renamed from geom_bottleneck/tests/data/test_195_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_195_B (renamed from geom_bottleneck/tests/data/test_195_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_196_A (renamed from geom_bottleneck/tests/data/test_196_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_196_B (renamed from geom_bottleneck/tests/data/test_196_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_197_A (renamed from geom_bottleneck/tests/data/test_197_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_197_B (renamed from geom_bottleneck/tests/data/test_197_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_198_A (renamed from geom_bottleneck/tests/data/test_198_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_198_B (renamed from geom_bottleneck/tests/data/test_198_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_199_A (renamed from geom_bottleneck/tests/data/test_199_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_199_B (renamed from geom_bottleneck/tests/data/test_199_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_200_A (renamed from geom_bottleneck/tests/data/test_200_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_200_B (renamed from geom_bottleneck/tests/data/test_200_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_201_A (renamed from geom_bottleneck/tests/data/test_201_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_201_B (renamed from geom_bottleneck/tests/data/test_201_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_202_A (renamed from geom_bottleneck/tests/data/test_202_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_202_B (renamed from geom_bottleneck/tests/data/test_202_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_203_A (renamed from geom_bottleneck/tests/data/test_203_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_203_B (renamed from geom_bottleneck/tests/data/test_203_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_204_A (renamed from geom_bottleneck/tests/data/test_204_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_204_B (renamed from geom_bottleneck/tests/data/test_204_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_205_A (renamed from geom_bottleneck/tests/data/test_205_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_205_B (renamed from geom_bottleneck/tests/data/test_205_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_206_A (renamed from geom_bottleneck/tests/data/test_206_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_206_B (renamed from geom_bottleneck/tests/data/test_206_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_207_A (renamed from geom_bottleneck/tests/data/test_207_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_207_B (renamed from geom_bottleneck/tests/data/test_207_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_208_A (renamed from geom_bottleneck/tests/data/test_208_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_208_B (renamed from geom_bottleneck/tests/data/test_208_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_209_A (renamed from geom_bottleneck/tests/data/test_209_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_209_B (renamed from geom_bottleneck/tests/data/test_209_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_210_A (renamed from geom_bottleneck/tests/data/test_210_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_210_B (renamed from geom_bottleneck/tests/data/test_210_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_211_A (renamed from geom_bottleneck/tests/data/test_211_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_211_B (renamed from geom_bottleneck/tests/data/test_211_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_212_A (renamed from geom_bottleneck/tests/data/test_212_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_212_B (renamed from geom_bottleneck/tests/data/test_212_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_213_A (renamed from geom_bottleneck/tests/data/test_213_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_213_B (renamed from geom_bottleneck/tests/data/test_213_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_214_A (renamed from geom_bottleneck/tests/data/test_214_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_214_B (renamed from geom_bottleneck/tests/data/test_214_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_215_A (renamed from geom_bottleneck/tests/data/test_215_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_215_B (renamed from geom_bottleneck/tests/data/test_215_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_216_A (renamed from geom_bottleneck/tests/data/test_216_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_216_B (renamed from geom_bottleneck/tests/data/test_216_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_217_A (renamed from geom_bottleneck/tests/data/test_217_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_217_B (renamed from geom_bottleneck/tests/data/test_217_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_218_A (renamed from geom_bottleneck/tests/data/test_218_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_218_B (renamed from geom_bottleneck/tests/data/test_218_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_219_A (renamed from geom_bottleneck/tests/data/test_219_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_219_B (renamed from geom_bottleneck/tests/data/test_219_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_220_A (renamed from geom_bottleneck/tests/data/test_220_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_220_B (renamed from geom_bottleneck/tests/data/test_220_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_221_A (renamed from geom_bottleneck/tests/data/test_221_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_221_B (renamed from geom_bottleneck/tests/data/test_221_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_222_A (renamed from geom_bottleneck/tests/data/test_222_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_222_B (renamed from geom_bottleneck/tests/data/test_222_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_223_A (renamed from geom_bottleneck/tests/data/test_223_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_223_B (renamed from geom_bottleneck/tests/data/test_223_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_224_A (renamed from geom_bottleneck/tests/data/test_224_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_224_B (renamed from geom_bottleneck/tests/data/test_224_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_225_A (renamed from geom_bottleneck/tests/data/test_225_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_225_B (renamed from geom_bottleneck/tests/data/test_225_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_226_A (renamed from geom_bottleneck/tests/data/test_226_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_226_B (renamed from geom_bottleneck/tests/data/test_226_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_227_A (renamed from geom_bottleneck/tests/data/test_227_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_227_B (renamed from geom_bottleneck/tests/data/test_227_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_228_A (renamed from geom_bottleneck/tests/data/test_228_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_228_B (renamed from geom_bottleneck/tests/data/test_228_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_229_A (renamed from geom_bottleneck/tests/data/test_229_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_229_B (renamed from geom_bottleneck/tests/data/test_229_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_230_A (renamed from geom_bottleneck/tests/data/test_230_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_230_B (renamed from geom_bottleneck/tests/data/test_230_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_231_A (renamed from geom_bottleneck/tests/data/test_231_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_231_B (renamed from geom_bottleneck/tests/data/test_231_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_232_A (renamed from geom_bottleneck/tests/data/test_232_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_232_B (renamed from geom_bottleneck/tests/data/test_232_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_233_A (renamed from geom_bottleneck/tests/data/test_233_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_233_B (renamed from geom_bottleneck/tests/data/test_233_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_234_A (renamed from geom_bottleneck/tests/data/test_234_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_234_B (renamed from geom_bottleneck/tests/data/test_234_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_235_A (renamed from geom_bottleneck/tests/data/test_235_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_235_B (renamed from geom_bottleneck/tests/data/test_235_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_236_A (renamed from geom_bottleneck/tests/data/test_236_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_236_B (renamed from geom_bottleneck/tests/data/test_236_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_237_A (renamed from geom_bottleneck/tests/data/test_237_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_237_B (renamed from geom_bottleneck/tests/data/test_237_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_238_A (renamed from geom_bottleneck/tests/data/test_238_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_238_B (renamed from geom_bottleneck/tests/data/test_238_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_239_A (renamed from geom_bottleneck/tests/data/test_239_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_239_B (renamed from geom_bottleneck/tests/data/test_239_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_240_A (renamed from geom_bottleneck/tests/data/test_240_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_240_B (renamed from geom_bottleneck/tests/data/test_240_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_241_A (renamed from geom_bottleneck/tests/data/test_241_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_241_B (renamed from geom_bottleneck/tests/data/test_241_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_242_A (renamed from geom_bottleneck/tests/data/test_242_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_242_B (renamed from geom_bottleneck/tests/data/test_242_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_243_A (renamed from geom_bottleneck/tests/data/test_243_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_243_B (renamed from geom_bottleneck/tests/data/test_243_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_244_A (renamed from geom_bottleneck/tests/data/test_244_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_244_B (renamed from geom_bottleneck/tests/data/test_244_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_245_A (renamed from geom_bottleneck/tests/data/test_245_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_245_B (renamed from geom_bottleneck/tests/data/test_245_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_246_A (renamed from geom_bottleneck/tests/data/test_246_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_246_B (renamed from geom_bottleneck/tests/data/test_246_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_247_A (renamed from geom_bottleneck/tests/data/test_247_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_247_B (renamed from geom_bottleneck/tests/data/test_247_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_248_A (renamed from geom_bottleneck/tests/data/test_248_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_248_B (renamed from geom_bottleneck/tests/data/test_248_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_249_A (renamed from geom_bottleneck/tests/data/test_249_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_249_B (renamed from geom_bottleneck/tests/data/test_249_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_250_A (renamed from geom_bottleneck/tests/data/test_250_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_250_B (renamed from geom_bottleneck/tests/data/test_250_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_251_A (renamed from geom_bottleneck/tests/data/test_251_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_251_B (renamed from geom_bottleneck/tests/data/test_251_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_252_A (renamed from geom_bottleneck/tests/data/test_252_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_252_B (renamed from geom_bottleneck/tests/data/test_252_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_253_A (renamed from geom_bottleneck/tests/data/test_253_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_253_B (renamed from geom_bottleneck/tests/data/test_253_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_254_A (renamed from geom_bottleneck/tests/data/test_254_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_254_B (renamed from geom_bottleneck/tests/data/test_254_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_255_A (renamed from geom_bottleneck/tests/data/test_255_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_255_B (renamed from geom_bottleneck/tests/data/test_255_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_256_A (renamed from geom_bottleneck/tests/data/test_256_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_256_B (renamed from geom_bottleneck/tests/data/test_256_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_257_A (renamed from geom_bottleneck/tests/data/test_257_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_257_B (renamed from geom_bottleneck/tests/data/test_257_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_258_A (renamed from geom_bottleneck/tests/data/test_258_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_258_B (renamed from geom_bottleneck/tests/data/test_258_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_259_A (renamed from geom_bottleneck/tests/data/test_259_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_259_B (renamed from geom_bottleneck/tests/data/test_259_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_260_A (renamed from geom_bottleneck/tests/data/test_260_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_260_B (renamed from geom_bottleneck/tests/data/test_260_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_261_A (renamed from geom_bottleneck/tests/data/test_261_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_261_B (renamed from geom_bottleneck/tests/data/test_261_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_262_A (renamed from geom_bottleneck/tests/data/test_262_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_262_B (renamed from geom_bottleneck/tests/data/test_262_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_263_A (renamed from geom_bottleneck/tests/data/test_263_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_263_B (renamed from geom_bottleneck/tests/data/test_263_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_264_A (renamed from geom_bottleneck/tests/data/test_264_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_264_B (renamed from geom_bottleneck/tests/data/test_264_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_265_A (renamed from geom_bottleneck/tests/data/test_265_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_265_B (renamed from geom_bottleneck/tests/data/test_265_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_266_A (renamed from geom_bottleneck/tests/data/test_266_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_266_B (renamed from geom_bottleneck/tests/data/test_266_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_267_A (renamed from geom_bottleneck/tests/data/test_267_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_267_B (renamed from geom_bottleneck/tests/data/test_267_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_268_A (renamed from geom_bottleneck/tests/data/test_268_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_268_B (renamed from geom_bottleneck/tests/data/test_268_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_269_A (renamed from geom_bottleneck/tests/data/test_269_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_269_B (renamed from geom_bottleneck/tests/data/test_269_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_270_A (renamed from geom_bottleneck/tests/data/test_270_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_270_B (renamed from geom_bottleneck/tests/data/test_270_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_271_A (renamed from geom_bottleneck/tests/data/test_271_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_271_B (renamed from geom_bottleneck/tests/data/test_271_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_272_A (renamed from geom_bottleneck/tests/data/test_272_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_272_B (renamed from geom_bottleneck/tests/data/test_272_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_273_A (renamed from geom_bottleneck/tests/data/test_273_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_273_B (renamed from geom_bottleneck/tests/data/test_273_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_274_A (renamed from geom_bottleneck/tests/data/test_274_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_274_B (renamed from geom_bottleneck/tests/data/test_274_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_275_A (renamed from geom_bottleneck/tests/data/test_275_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_275_B (renamed from geom_bottleneck/tests/data/test_275_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_276_A (renamed from geom_bottleneck/tests/data/test_276_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_276_B (renamed from geom_bottleneck/tests/data/test_276_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_277_A (renamed from geom_bottleneck/tests/data/test_277_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_277_B (renamed from geom_bottleneck/tests/data/test_277_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_278_A (renamed from geom_bottleneck/tests/data/test_278_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_278_B (renamed from geom_bottleneck/tests/data/test_278_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_279_A (renamed from geom_bottleneck/tests/data/test_279_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_279_B (renamed from geom_bottleneck/tests/data/test_279_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_280_A (renamed from geom_bottleneck/tests/data/test_280_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_280_B (renamed from geom_bottleneck/tests/data/test_280_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_281_A (renamed from geom_bottleneck/tests/data/test_281_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_281_B (renamed from geom_bottleneck/tests/data/test_281_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_282_A (renamed from geom_bottleneck/tests/data/test_282_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_282_B (renamed from geom_bottleneck/tests/data/test_282_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_283_A (renamed from geom_bottleneck/tests/data/test_283_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_283_B (renamed from geom_bottleneck/tests/data/test_283_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_284_A (renamed from geom_bottleneck/tests/data/test_284_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_284_B (renamed from geom_bottleneck/tests/data/test_284_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_285_A (renamed from geom_bottleneck/tests/data/test_285_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_285_B (renamed from geom_bottleneck/tests/data/test_285_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_286_A (renamed from geom_bottleneck/tests/data/test_286_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_286_B (renamed from geom_bottleneck/tests/data/test_286_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_287_A (renamed from geom_bottleneck/tests/data/test_287_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_287_B (renamed from geom_bottleneck/tests/data/test_287_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_288_A (renamed from geom_bottleneck/tests/data/test_288_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_288_B (renamed from geom_bottleneck/tests/data/test_288_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_289_A (renamed from geom_bottleneck/tests/data/test_289_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_289_B (renamed from geom_bottleneck/tests/data/test_289_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_290_A (renamed from geom_bottleneck/tests/data/test_290_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_290_B (renamed from geom_bottleneck/tests/data/test_290_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_291_A (renamed from geom_bottleneck/tests/data/test_291_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_291_B (renamed from geom_bottleneck/tests/data/test_291_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_292_A (renamed from geom_bottleneck/tests/data/test_292_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_292_B (renamed from geom_bottleneck/tests/data/test_292_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_293_A (renamed from geom_bottleneck/tests/data/test_293_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_293_B (renamed from geom_bottleneck/tests/data/test_293_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_294_A (renamed from geom_bottleneck/tests/data/test_294_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_294_B (renamed from geom_bottleneck/tests/data/test_294_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_295_A (renamed from geom_bottleneck/tests/data/test_295_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_295_B (renamed from geom_bottleneck/tests/data/test_295_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_296_A (renamed from geom_bottleneck/tests/data/test_296_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_296_B (renamed from geom_bottleneck/tests/data/test_296_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_297_A (renamed from geom_bottleneck/tests/data/test_297_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_297_B (renamed from geom_bottleneck/tests/data/test_297_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_298_A (renamed from geom_bottleneck/tests/data/test_298_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_298_B (renamed from geom_bottleneck/tests/data/test_298_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_299_A (renamed from geom_bottleneck/tests/data/test_299_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_299_B (renamed from geom_bottleneck/tests/data/test_299_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_300_A (renamed from geom_bottleneck/tests/data/test_300_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_300_B (renamed from geom_bottleneck/tests/data/test_300_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_301_A (renamed from geom_bottleneck/tests/data/test_301_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_301_B (renamed from geom_bottleneck/tests/data/test_301_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_302_A (renamed from geom_bottleneck/tests/data/test_302_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_302_B (renamed from geom_bottleneck/tests/data/test_302_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_303_A (renamed from geom_bottleneck/tests/data/test_303_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_303_B (renamed from geom_bottleneck/tests/data/test_303_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_304_A (renamed from geom_bottleneck/tests/data/test_304_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_304_B (renamed from geom_bottleneck/tests/data/test_304_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_305_A (renamed from geom_bottleneck/tests/data/test_305_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_305_B (renamed from geom_bottleneck/tests/data/test_305_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_306_A (renamed from geom_bottleneck/tests/data/test_306_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_306_B (renamed from geom_bottleneck/tests/data/test_306_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_307_A (renamed from geom_bottleneck/tests/data/test_307_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_307_B (renamed from geom_bottleneck/tests/data/test_307_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_308_A (renamed from geom_bottleneck/tests/data/test_308_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_308_B (renamed from geom_bottleneck/tests/data/test_308_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_309_A (renamed from geom_bottleneck/tests/data/test_309_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_309_B (renamed from geom_bottleneck/tests/data/test_309_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_310_A (renamed from geom_bottleneck/tests/data/test_310_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_310_B (renamed from geom_bottleneck/tests/data/test_310_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_311_A (renamed from geom_bottleneck/tests/data/test_311_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_311_B (renamed from geom_bottleneck/tests/data/test_311_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_312_A (renamed from geom_bottleneck/tests/data/test_312_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_312_B (renamed from geom_bottleneck/tests/data/test_312_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_313_A (renamed from geom_bottleneck/tests/data/test_313_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_313_B (renamed from geom_bottleneck/tests/data/test_313_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_314_A (renamed from geom_bottleneck/tests/data/test_314_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_314_B (renamed from geom_bottleneck/tests/data/test_314_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_315_A (renamed from geom_bottleneck/tests/data/test_315_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_315_B (renamed from geom_bottleneck/tests/data/test_315_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_316_A (renamed from geom_bottleneck/tests/data/test_316_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_316_B (renamed from geom_bottleneck/tests/data/test_316_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_317_A (renamed from geom_bottleneck/tests/data/test_317_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_317_B (renamed from geom_bottleneck/tests/data/test_317_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_318_A (renamed from geom_bottleneck/tests/data/test_318_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_318_B (renamed from geom_bottleneck/tests/data/test_318_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_319_A (renamed from geom_bottleneck/tests/data/test_319_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_319_B (renamed from geom_bottleneck/tests/data/test_319_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_320_A (renamed from geom_bottleneck/tests/data/test_320_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_320_B (renamed from geom_bottleneck/tests/data/test_320_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_321_A (renamed from geom_bottleneck/tests/data/test_321_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_321_B (renamed from geom_bottleneck/tests/data/test_321_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_322_A (renamed from geom_bottleneck/tests/data/test_322_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_322_B (renamed from geom_bottleneck/tests/data/test_322_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_323_A (renamed from geom_bottleneck/tests/data/test_323_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_323_B (renamed from geom_bottleneck/tests/data/test_323_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_324_A (renamed from geom_bottleneck/tests/data/test_324_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_324_B (renamed from geom_bottleneck/tests/data/test_324_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_325_A (renamed from geom_bottleneck/tests/data/test_325_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_325_B (renamed from geom_bottleneck/tests/data/test_325_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_326_A (renamed from geom_bottleneck/tests/data/test_326_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_326_B (renamed from geom_bottleneck/tests/data/test_326_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_327_A (renamed from geom_bottleneck/tests/data/test_327_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_327_B (renamed from geom_bottleneck/tests/data/test_327_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_328_A (renamed from geom_bottleneck/tests/data/test_328_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_328_B (renamed from geom_bottleneck/tests/data/test_328_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_329_A (renamed from geom_bottleneck/tests/data/test_329_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_329_B (renamed from geom_bottleneck/tests/data/test_329_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_330_A (renamed from geom_bottleneck/tests/data/test_330_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_330_B (renamed from geom_bottleneck/tests/data/test_330_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_331_A (renamed from geom_bottleneck/tests/data/test_331_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_331_B (renamed from geom_bottleneck/tests/data/test_331_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_332_A (renamed from geom_bottleneck/tests/data/test_332_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_332_B (renamed from geom_bottleneck/tests/data/test_332_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_333_A (renamed from geom_bottleneck/tests/data/test_333_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_333_B (renamed from geom_bottleneck/tests/data/test_333_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_334_A (renamed from geom_bottleneck/tests/data/test_334_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_334_B (renamed from geom_bottleneck/tests/data/test_334_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_335_A (renamed from geom_bottleneck/tests/data/test_335_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_335_B (renamed from geom_bottleneck/tests/data/test_335_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_336_A (renamed from geom_bottleneck/tests/data/test_336_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_336_B (renamed from geom_bottleneck/tests/data/test_336_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_337_A (renamed from geom_bottleneck/tests/data/test_337_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_337_B (renamed from geom_bottleneck/tests/data/test_337_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_338_A (renamed from geom_bottleneck/tests/data/test_338_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_338_B (renamed from geom_bottleneck/tests/data/test_338_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_339_A (renamed from geom_bottleneck/tests/data/test_339_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_339_B (renamed from geom_bottleneck/tests/data/test_339_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_340_A (renamed from geom_bottleneck/tests/data/test_340_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_340_B (renamed from geom_bottleneck/tests/data/test_340_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_341_A (renamed from geom_bottleneck/tests/data/test_341_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_341_B (renamed from geom_bottleneck/tests/data/test_341_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_342_A (renamed from geom_bottleneck/tests/data/test_342_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_342_B (renamed from geom_bottleneck/tests/data/test_342_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_343_A (renamed from geom_bottleneck/tests/data/test_343_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_343_B (renamed from geom_bottleneck/tests/data/test_343_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_344_A (renamed from geom_bottleneck/tests/data/test_344_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_344_B (renamed from geom_bottleneck/tests/data/test_344_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_345_A (renamed from geom_bottleneck/tests/data/test_345_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_345_B (renamed from geom_bottleneck/tests/data/test_345_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_346_A (renamed from geom_bottleneck/tests/data/test_346_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_346_B (renamed from geom_bottleneck/tests/data/test_346_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_347_A (renamed from geom_bottleneck/tests/data/test_347_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_347_B (renamed from geom_bottleneck/tests/data/test_347_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_348_A (renamed from geom_bottleneck/tests/data/test_348_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_348_B (renamed from geom_bottleneck/tests/data/test_348_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_349_A (renamed from geom_bottleneck/tests/data/test_349_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_349_B (renamed from geom_bottleneck/tests/data/test_349_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_350_A (renamed from geom_bottleneck/tests/data/test_350_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_350_B (renamed from geom_bottleneck/tests/data/test_350_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_351_A (renamed from geom_bottleneck/tests/data/test_351_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_351_B (renamed from geom_bottleneck/tests/data/test_351_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_352_A (renamed from geom_bottleneck/tests/data/test_352_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_352_B (renamed from geom_bottleneck/tests/data/test_352_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_353_A (renamed from geom_bottleneck/tests/data/test_353_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_353_B (renamed from geom_bottleneck/tests/data/test_353_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_354_A (renamed from geom_bottleneck/tests/data/test_354_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_354_B (renamed from geom_bottleneck/tests/data/test_354_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_355_A (renamed from geom_bottleneck/tests/data/test_355_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_355_B (renamed from geom_bottleneck/tests/data/test_355_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_356_A (renamed from geom_bottleneck/tests/data/test_356_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_356_B (renamed from geom_bottleneck/tests/data/test_356_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_357_A (renamed from geom_bottleneck/tests/data/test_357_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_357_B (renamed from geom_bottleneck/tests/data/test_357_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_358_A (renamed from geom_bottleneck/tests/data/test_358_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_358_B (renamed from geom_bottleneck/tests/data/test_358_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_359_A (renamed from geom_bottleneck/tests/data/test_359_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_359_B (renamed from geom_bottleneck/tests/data/test_359_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_360_A (renamed from geom_bottleneck/tests/data/test_360_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_360_B (renamed from geom_bottleneck/tests/data/test_360_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_361_A (renamed from geom_bottleneck/tests/data/test_361_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_361_B (renamed from geom_bottleneck/tests/data/test_361_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_362_A (renamed from geom_bottleneck/tests/data/test_362_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_362_B (renamed from geom_bottleneck/tests/data/test_362_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_363_A (renamed from geom_bottleneck/tests/data/test_363_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_363_B (renamed from geom_bottleneck/tests/data/test_363_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_364_A (renamed from geom_bottleneck/tests/data/test_364_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_364_B (renamed from geom_bottleneck/tests/data/test_364_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_365_A (renamed from geom_bottleneck/tests/data/test_365_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_365_B (renamed from geom_bottleneck/tests/data/test_365_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_366_A (renamed from geom_bottleneck/tests/data/test_366_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_366_B (renamed from geom_bottleneck/tests/data/test_366_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_367_A (renamed from geom_bottleneck/tests/data/test_367_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_367_B (renamed from geom_bottleneck/tests/data/test_367_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_368_A (renamed from geom_bottleneck/tests/data/test_368_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_368_B (renamed from geom_bottleneck/tests/data/test_368_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_369_A (renamed from geom_bottleneck/tests/data/test_369_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_369_B (renamed from geom_bottleneck/tests/data/test_369_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_370_A (renamed from geom_bottleneck/tests/data/test_370_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_370_B (renamed from geom_bottleneck/tests/data/test_370_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_371_A (renamed from geom_bottleneck/tests/data/test_371_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_371_B (renamed from geom_bottleneck/tests/data/test_371_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_372_A (renamed from geom_bottleneck/tests/data/test_372_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_372_B (renamed from geom_bottleneck/tests/data/test_372_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_373_A (renamed from geom_bottleneck/tests/data/test_373_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_373_B (renamed from geom_bottleneck/tests/data/test_373_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_374_A (renamed from geom_bottleneck/tests/data/test_374_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_374_B (renamed from geom_bottleneck/tests/data/test_374_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_375_A (renamed from geom_bottleneck/tests/data/test_375_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_375_B (renamed from geom_bottleneck/tests/data/test_375_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_376_A (renamed from geom_bottleneck/tests/data/test_376_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_376_B (renamed from geom_bottleneck/tests/data/test_376_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_377_A (renamed from geom_bottleneck/tests/data/test_377_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_377_B (renamed from geom_bottleneck/tests/data/test_377_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_378_A (renamed from geom_bottleneck/tests/data/test_378_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_378_B (renamed from geom_bottleneck/tests/data/test_378_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_379_A (renamed from geom_bottleneck/tests/data/test_379_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_379_B (renamed from geom_bottleneck/tests/data/test_379_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_380_A (renamed from geom_bottleneck/tests/data/test_380_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_380_B (renamed from geom_bottleneck/tests/data/test_380_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_381_A (renamed from geom_bottleneck/tests/data/test_381_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_381_B (renamed from geom_bottleneck/tests/data/test_381_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_382_A (renamed from geom_bottleneck/tests/data/test_382_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_382_B (renamed from geom_bottleneck/tests/data/test_382_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_383_A (renamed from geom_bottleneck/tests/data/test_383_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_383_B (renamed from geom_bottleneck/tests/data/test_383_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_384_A (renamed from geom_bottleneck/tests/data/test_384_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_384_B (renamed from geom_bottleneck/tests/data/test_384_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_385_A (renamed from geom_bottleneck/tests/data/test_385_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_385_B (renamed from geom_bottleneck/tests/data/test_385_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_386_A (renamed from geom_bottleneck/tests/data/test_386_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_386_B (renamed from geom_bottleneck/tests/data/test_386_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_387_A (renamed from geom_bottleneck/tests/data/test_387_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_387_B (renamed from geom_bottleneck/tests/data/test_387_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_388_A (renamed from geom_bottleneck/tests/data/test_388_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_388_B (renamed from geom_bottleneck/tests/data/test_388_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_389_A (renamed from geom_bottleneck/tests/data/test_389_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_389_B (renamed from geom_bottleneck/tests/data/test_389_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_390_A (renamed from geom_bottleneck/tests/data/test_390_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_390_B (renamed from geom_bottleneck/tests/data/test_390_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_391_A (renamed from geom_bottleneck/tests/data/test_391_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_391_B (renamed from geom_bottleneck/tests/data/test_391_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_392_A (renamed from geom_bottleneck/tests/data/test_392_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_392_B (renamed from geom_bottleneck/tests/data/test_392_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_393_A (renamed from geom_bottleneck/tests/data/test_393_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_393_B (renamed from geom_bottleneck/tests/data/test_393_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_394_A (renamed from geom_bottleneck/tests/data/test_394_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_394_B (renamed from geom_bottleneck/tests/data/test_394_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_395_A (renamed from geom_bottleneck/tests/data/test_395_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_395_B (renamed from geom_bottleneck/tests/data/test_395_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_396_A (renamed from geom_bottleneck/tests/data/test_396_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_396_B (renamed from geom_bottleneck/tests/data/test_396_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_397_A (renamed from geom_bottleneck/tests/data/test_397_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_397_B (renamed from geom_bottleneck/tests/data/test_397_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_398_A (renamed from geom_bottleneck/tests/data/test_398_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_398_B (renamed from geom_bottleneck/tests/data/test_398_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_399_A (renamed from geom_bottleneck/tests/data/test_399_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_399_B (renamed from geom_bottleneck/tests/data/test_399_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_400_A (renamed from geom_bottleneck/tests/data/test_400_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_400_B (renamed from geom_bottleneck/tests/data/test_400_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_401_A (renamed from geom_bottleneck/tests/data/test_401_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_401_B (renamed from geom_bottleneck/tests/data/test_401_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_402_A (renamed from geom_bottleneck/tests/data/test_402_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_402_B (renamed from geom_bottleneck/tests/data/test_402_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_403_A (renamed from geom_bottleneck/tests/data/test_403_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_403_B (renamed from geom_bottleneck/tests/data/test_403_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_404_A (renamed from geom_bottleneck/tests/data/test_404_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_404_B (renamed from geom_bottleneck/tests/data/test_404_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_405_A (renamed from geom_bottleneck/tests/data/test_405_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_405_B (renamed from geom_bottleneck/tests/data/test_405_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_406_A (renamed from geom_bottleneck/tests/data/test_406_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_406_B (renamed from geom_bottleneck/tests/data/test_406_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_407_A (renamed from geom_bottleneck/tests/data/test_407_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_407_B (renamed from geom_bottleneck/tests/data/test_407_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_408_A (renamed from geom_bottleneck/tests/data/test_408_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_408_B (renamed from geom_bottleneck/tests/data/test_408_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_409_A (renamed from geom_bottleneck/tests/data/test_409_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_409_B (renamed from geom_bottleneck/tests/data/test_409_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_410_A (renamed from geom_bottleneck/tests/data/test_410_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_410_B (renamed from geom_bottleneck/tests/data/test_410_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_411_A (renamed from geom_bottleneck/tests/data/test_411_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_411_B (renamed from geom_bottleneck/tests/data/test_411_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_412_A (renamed from geom_bottleneck/tests/data/test_412_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_412_B (renamed from geom_bottleneck/tests/data/test_412_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_413_A (renamed from geom_bottleneck/tests/data/test_413_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_413_B (renamed from geom_bottleneck/tests/data/test_413_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_414_A (renamed from geom_bottleneck/tests/data/test_414_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_414_B (renamed from geom_bottleneck/tests/data/test_414_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_415_A (renamed from geom_bottleneck/tests/data/test_415_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_415_B (renamed from geom_bottleneck/tests/data/test_415_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_416_A (renamed from geom_bottleneck/tests/data/test_416_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_416_B (renamed from geom_bottleneck/tests/data/test_416_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_417_A (renamed from geom_bottleneck/tests/data/test_417_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_417_B (renamed from geom_bottleneck/tests/data/test_417_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_418_A (renamed from geom_bottleneck/tests/data/test_418_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_418_B (renamed from geom_bottleneck/tests/data/test_418_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_419_A (renamed from geom_bottleneck/tests/data/test_419_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_419_B (renamed from geom_bottleneck/tests/data/test_419_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_420_A (renamed from geom_bottleneck/tests/data/test_420_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_420_B (renamed from geom_bottleneck/tests/data/test_420_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_421_A (renamed from geom_bottleneck/tests/data/test_421_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_421_B (renamed from geom_bottleneck/tests/data/test_421_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_422_A (renamed from geom_bottleneck/tests/data/test_422_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_422_B (renamed from geom_bottleneck/tests/data/test_422_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_423_A (renamed from geom_bottleneck/tests/data/test_423_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_423_B (renamed from geom_bottleneck/tests/data/test_423_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_424_A (renamed from geom_bottleneck/tests/data/test_424_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_424_B (renamed from geom_bottleneck/tests/data/test_424_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_425_A (renamed from geom_bottleneck/tests/data/test_425_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_425_B (renamed from geom_bottleneck/tests/data/test_425_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_426_A (renamed from geom_bottleneck/tests/data/test_426_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_426_B (renamed from geom_bottleneck/tests/data/test_426_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_427_A (renamed from geom_bottleneck/tests/data/test_427_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_427_B (renamed from geom_bottleneck/tests/data/test_427_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_428_A (renamed from geom_bottleneck/tests/data/test_428_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_428_B (renamed from geom_bottleneck/tests/data/test_428_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_429_A (renamed from geom_bottleneck/tests/data/test_429_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_429_B (renamed from geom_bottleneck/tests/data/test_429_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_430_A (renamed from geom_bottleneck/tests/data/test_430_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_430_B (renamed from geom_bottleneck/tests/data/test_430_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_431_A (renamed from geom_bottleneck/tests/data/test_431_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_431_B (renamed from geom_bottleneck/tests/data/test_431_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_432_A (renamed from geom_bottleneck/tests/data/test_432_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_432_B (renamed from geom_bottleneck/tests/data/test_432_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_433_A (renamed from geom_bottleneck/tests/data/test_433_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_433_B (renamed from geom_bottleneck/tests/data/test_433_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_434_A (renamed from geom_bottleneck/tests/data/test_434_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_434_B (renamed from geom_bottleneck/tests/data/test_434_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_435_A (renamed from geom_bottleneck/tests/data/test_435_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_435_B (renamed from geom_bottleneck/tests/data/test_435_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_436_A (renamed from geom_bottleneck/tests/data/test_436_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_436_B (renamed from geom_bottleneck/tests/data/test_436_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_437_A (renamed from geom_bottleneck/tests/data/test_437_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_437_B (renamed from geom_bottleneck/tests/data/test_437_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_438_A (renamed from geom_bottleneck/tests/data/test_438_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_438_B (renamed from geom_bottleneck/tests/data/test_438_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_439_A (renamed from geom_bottleneck/tests/data/test_439_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_439_B (renamed from geom_bottleneck/tests/data/test_439_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_440_A (renamed from geom_bottleneck/tests/data/test_440_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_440_B (renamed from geom_bottleneck/tests/data/test_440_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_441_A (renamed from geom_bottleneck/tests/data/test_441_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_441_B (renamed from geom_bottleneck/tests/data/test_441_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_442_A (renamed from geom_bottleneck/tests/data/test_442_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_442_B (renamed from geom_bottleneck/tests/data/test_442_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_443_A (renamed from geom_bottleneck/tests/data/test_443_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_443_B (renamed from geom_bottleneck/tests/data/test_443_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_444_A (renamed from geom_bottleneck/tests/data/test_444_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_444_B (renamed from geom_bottleneck/tests/data/test_444_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_445_A (renamed from geom_bottleneck/tests/data/test_445_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_445_B (renamed from geom_bottleneck/tests/data/test_445_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_446_A (renamed from geom_bottleneck/tests/data/test_446_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_446_B (renamed from geom_bottleneck/tests/data/test_446_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_447_A (renamed from geom_bottleneck/tests/data/test_447_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_447_B (renamed from geom_bottleneck/tests/data/test_447_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_448_A (renamed from geom_bottleneck/tests/data/test_448_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_448_B (renamed from geom_bottleneck/tests/data/test_448_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_449_A (renamed from geom_bottleneck/tests/data/test_449_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_449_B (renamed from geom_bottleneck/tests/data/test_449_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_450_A (renamed from geom_bottleneck/tests/data/test_450_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_450_B (renamed from geom_bottleneck/tests/data/test_450_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_451_A (renamed from geom_bottleneck/tests/data/test_451_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_451_B (renamed from geom_bottleneck/tests/data/test_451_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_452_A (renamed from geom_bottleneck/tests/data/test_452_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_452_B (renamed from geom_bottleneck/tests/data/test_452_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_453_A (renamed from geom_bottleneck/tests/data/test_453_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_453_B (renamed from geom_bottleneck/tests/data/test_453_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_454_A (renamed from geom_bottleneck/tests/data/test_454_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_454_B (renamed from geom_bottleneck/tests/data/test_454_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_455_A (renamed from geom_bottleneck/tests/data/test_455_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_455_B (renamed from geom_bottleneck/tests/data/test_455_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_456_A (renamed from geom_bottleneck/tests/data/test_456_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_456_B (renamed from geom_bottleneck/tests/data/test_456_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_457_A (renamed from geom_bottleneck/tests/data/test_457_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_457_B (renamed from geom_bottleneck/tests/data/test_457_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_458_A (renamed from geom_bottleneck/tests/data/test_458_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_458_B (renamed from geom_bottleneck/tests/data/test_458_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_459_A (renamed from geom_bottleneck/tests/data/test_459_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_459_B (renamed from geom_bottleneck/tests/data/test_459_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_460_A (renamed from geom_bottleneck/tests/data/test_460_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_460_B (renamed from geom_bottleneck/tests/data/test_460_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_461_A (renamed from geom_bottleneck/tests/data/test_461_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_461_B (renamed from geom_bottleneck/tests/data/test_461_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_462_A (renamed from geom_bottleneck/tests/data/test_462_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_462_B (renamed from geom_bottleneck/tests/data/test_462_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_463_A (renamed from geom_bottleneck/tests/data/test_463_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_463_B (renamed from geom_bottleneck/tests/data/test_463_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_464_A (renamed from geom_bottleneck/tests/data/test_464_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_464_B (renamed from geom_bottleneck/tests/data/test_464_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_465_A (renamed from geom_bottleneck/tests/data/test_465_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_465_B (renamed from geom_bottleneck/tests/data/test_465_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_466_A (renamed from geom_bottleneck/tests/data/test_466_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_466_B (renamed from geom_bottleneck/tests/data/test_466_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_467_A (renamed from geom_bottleneck/tests/data/test_467_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_467_B (renamed from geom_bottleneck/tests/data/test_467_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_468_A (renamed from geom_bottleneck/tests/data/test_468_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_468_B (renamed from geom_bottleneck/tests/data/test_468_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_469_A (renamed from geom_bottleneck/tests/data/test_469_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_469_B (renamed from geom_bottleneck/tests/data/test_469_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_470_A (renamed from geom_bottleneck/tests/data/test_470_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_470_B (renamed from geom_bottleneck/tests/data/test_470_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_471_A (renamed from geom_bottleneck/tests/data/test_471_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_471_B (renamed from geom_bottleneck/tests/data/test_471_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_472_A (renamed from geom_bottleneck/tests/data/test_472_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_472_B (renamed from geom_bottleneck/tests/data/test_472_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_473_A (renamed from geom_bottleneck/tests/data/test_473_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_473_B (renamed from geom_bottleneck/tests/data/test_473_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_474_A (renamed from geom_bottleneck/tests/data/test_474_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_474_B (renamed from geom_bottleneck/tests/data/test_474_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_475_A (renamed from geom_bottleneck/tests/data/test_475_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_475_B (renamed from geom_bottleneck/tests/data/test_475_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_476_A (renamed from geom_bottleneck/tests/data/test_476_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_476_B (renamed from geom_bottleneck/tests/data/test_476_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_477_A (renamed from geom_bottleneck/tests/data/test_477_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_477_B (renamed from geom_bottleneck/tests/data/test_477_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_478_A (renamed from geom_bottleneck/tests/data/test_478_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_478_B (renamed from geom_bottleneck/tests/data/test_478_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_479_A (renamed from geom_bottleneck/tests/data/test_479_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_479_B (renamed from geom_bottleneck/tests/data/test_479_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_480_A (renamed from geom_bottleneck/tests/data/test_480_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_480_B (renamed from geom_bottleneck/tests/data/test_480_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_481_A (renamed from geom_bottleneck/tests/data/test_481_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_481_B (renamed from geom_bottleneck/tests/data/test_481_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_482_A (renamed from geom_bottleneck/tests/data/test_482_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_482_B (renamed from geom_bottleneck/tests/data/test_482_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_483_A (renamed from geom_bottleneck/tests/data/test_483_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_483_B (renamed from geom_bottleneck/tests/data/test_483_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_484_A (renamed from geom_bottleneck/tests/data/test_484_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_484_B (renamed from geom_bottleneck/tests/data/test_484_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_485_A (renamed from geom_bottleneck/tests/data/test_485_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_485_B (renamed from geom_bottleneck/tests/data/test_485_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_486_A (renamed from geom_bottleneck/tests/data/test_486_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_486_B (renamed from geom_bottleneck/tests/data/test_486_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_487_A (renamed from geom_bottleneck/tests/data/test_487_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_487_B (renamed from geom_bottleneck/tests/data/test_487_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_488_A (renamed from geom_bottleneck/tests/data/test_488_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_488_B (renamed from geom_bottleneck/tests/data/test_488_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_489_A (renamed from geom_bottleneck/tests/data/test_489_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_489_B (renamed from geom_bottleneck/tests/data/test_489_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_490_A (renamed from geom_bottleneck/tests/data/test_490_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_490_B (renamed from geom_bottleneck/tests/data/test_490_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_491_A (renamed from geom_bottleneck/tests/data/test_491_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_491_B (renamed from geom_bottleneck/tests/data/test_491_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_492_A (renamed from geom_bottleneck/tests/data/test_492_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_492_B (renamed from geom_bottleneck/tests/data/test_492_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_493_A (renamed from geom_bottleneck/tests/data/test_493_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_493_B (renamed from geom_bottleneck/tests/data/test_493_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_494_A (renamed from geom_bottleneck/tests/data/test_494_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_494_B (renamed from geom_bottleneck/tests/data/test_494_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_495_A (renamed from geom_bottleneck/tests/data/test_495_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_495_B (renamed from geom_bottleneck/tests/data/test_495_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_496_A (renamed from geom_bottleneck/tests/data/test_496_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_496_B (renamed from geom_bottleneck/tests/data/test_496_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_497_A (renamed from geom_bottleneck/tests/data/test_497_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_497_B (renamed from geom_bottleneck/tests/data/test_497_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_498_A (renamed from geom_bottleneck/tests/data/test_498_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_498_B (renamed from geom_bottleneck/tests/data/test_498_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_499_A (renamed from geom_bottleneck/tests/data/test_499_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_499_B (renamed from geom_bottleneck/tests/data/test_499_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_500_A (renamed from geom_bottleneck/tests/data/test_500_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_500_B (renamed from geom_bottleneck/tests/data/test_500_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_501_A (renamed from geom_bottleneck/tests/data/test_501_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_501_B (renamed from geom_bottleneck/tests/data/test_501_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_502_A (renamed from geom_bottleneck/tests/data/test_502_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_502_B (renamed from geom_bottleneck/tests/data/test_502_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_503_A (renamed from geom_bottleneck/tests/data/test_503_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_503_B (renamed from geom_bottleneck/tests/data/test_503_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_504_A (renamed from geom_bottleneck/tests/data/test_504_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_504_B (renamed from geom_bottleneck/tests/data/test_504_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_505_A (renamed from geom_bottleneck/tests/data/test_505_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_505_B (renamed from geom_bottleneck/tests/data/test_505_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_506_A (renamed from geom_bottleneck/tests/data/test_506_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_506_B (renamed from geom_bottleneck/tests/data/test_506_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_507_A (renamed from geom_bottleneck/tests/data/test_507_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_507_B (renamed from geom_bottleneck/tests/data/test_507_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_508_A (renamed from geom_bottleneck/tests/data/test_508_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_508_B (renamed from geom_bottleneck/tests/data/test_508_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_509_A (renamed from geom_bottleneck/tests/data/test_509_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_509_B (renamed from geom_bottleneck/tests/data/test_509_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_510_A (renamed from geom_bottleneck/tests/data/test_510_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_510_B (renamed from geom_bottleneck/tests/data/test_510_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_511_A (renamed from geom_bottleneck/tests/data/test_511_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_511_B (renamed from geom_bottleneck/tests/data/test_511_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_512_A (renamed from geom_bottleneck/tests/data/test_512_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_512_B (renamed from geom_bottleneck/tests/data/test_512_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_513_A (renamed from geom_bottleneck/tests/data/test_513_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_513_B (renamed from geom_bottleneck/tests/data/test_513_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_514_A (renamed from geom_bottleneck/tests/data/test_514_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_514_B (renamed from geom_bottleneck/tests/data/test_514_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_515_A (renamed from geom_bottleneck/tests/data/test_515_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_515_B (renamed from geom_bottleneck/tests/data/test_515_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_516_A (renamed from geom_bottleneck/tests/data/test_516_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_516_B (renamed from geom_bottleneck/tests/data/test_516_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_517_A (renamed from geom_bottleneck/tests/data/test_517_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_517_B (renamed from geom_bottleneck/tests/data/test_517_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_518_A (renamed from geom_bottleneck/tests/data/test_518_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_518_B (renamed from geom_bottleneck/tests/data/test_518_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_519_A (renamed from geom_bottleneck/tests/data/test_519_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_519_B (renamed from geom_bottleneck/tests/data/test_519_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_520_A (renamed from geom_bottleneck/tests/data/test_520_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_520_B (renamed from geom_bottleneck/tests/data/test_520_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_521_A (renamed from geom_bottleneck/tests/data/test_521_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_521_B (renamed from geom_bottleneck/tests/data/test_521_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_522_A (renamed from geom_bottleneck/tests/data/test_522_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_522_B (renamed from geom_bottleneck/tests/data/test_522_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_523_A (renamed from geom_bottleneck/tests/data/test_523_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_523_B (renamed from geom_bottleneck/tests/data/test_523_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_524_A (renamed from geom_bottleneck/tests/data/test_524_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_524_B (renamed from geom_bottleneck/tests/data/test_524_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_525_A (renamed from geom_bottleneck/tests/data/test_525_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_525_B (renamed from geom_bottleneck/tests/data/test_525_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_526_A (renamed from geom_bottleneck/tests/data/test_526_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_526_B (renamed from geom_bottleneck/tests/data/test_526_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_527_A (renamed from geom_bottleneck/tests/data/test_527_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_527_B (renamed from geom_bottleneck/tests/data/test_527_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_528_A (renamed from geom_bottleneck/tests/data/test_528_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_528_B (renamed from geom_bottleneck/tests/data/test_528_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_529_A (renamed from geom_bottleneck/tests/data/test_529_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_529_B (renamed from geom_bottleneck/tests/data/test_529_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_530_A (renamed from geom_bottleneck/tests/data/test_530_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_530_B (renamed from geom_bottleneck/tests/data/test_530_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_531_A (renamed from geom_bottleneck/tests/data/test_531_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_531_B (renamed from geom_bottleneck/tests/data/test_531_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_532_A (renamed from geom_bottleneck/tests/data/test_532_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_532_B (renamed from geom_bottleneck/tests/data/test_532_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_533_A (renamed from geom_bottleneck/tests/data/test_533_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_533_B (renamed from geom_bottleneck/tests/data/test_533_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_534_A (renamed from geom_bottleneck/tests/data/test_534_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_534_B (renamed from geom_bottleneck/tests/data/test_534_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_535_A (renamed from geom_bottleneck/tests/data/test_535_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_535_B (renamed from geom_bottleneck/tests/data/test_535_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_536_A (renamed from geom_bottleneck/tests/data/test_536_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_536_B (renamed from geom_bottleneck/tests/data/test_536_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_537_A (renamed from geom_bottleneck/tests/data/test_537_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_537_B (renamed from geom_bottleneck/tests/data/test_537_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_538_A (renamed from geom_bottleneck/tests/data/test_538_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_538_B (renamed from geom_bottleneck/tests/data/test_538_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_539_A (renamed from geom_bottleneck/tests/data/test_539_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_539_B (renamed from geom_bottleneck/tests/data/test_539_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_540_A (renamed from geom_bottleneck/tests/data/test_540_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_540_B (renamed from geom_bottleneck/tests/data/test_540_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_541_A (renamed from geom_bottleneck/tests/data/test_541_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_541_B (renamed from geom_bottleneck/tests/data/test_541_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_542_A (renamed from geom_bottleneck/tests/data/test_542_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_542_B (renamed from geom_bottleneck/tests/data/test_542_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_543_A (renamed from geom_bottleneck/tests/data/test_543_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_543_B (renamed from geom_bottleneck/tests/data/test_543_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_544_A (renamed from geom_bottleneck/tests/data/test_544_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_544_B (renamed from geom_bottleneck/tests/data/test_544_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_545_A (renamed from geom_bottleneck/tests/data/test_545_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_545_B (renamed from geom_bottleneck/tests/data/test_545_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_546_A (renamed from geom_bottleneck/tests/data/test_546_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_546_B (renamed from geom_bottleneck/tests/data/test_546_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_547_A (renamed from geom_bottleneck/tests/data/test_547_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_547_B (renamed from geom_bottleneck/tests/data/test_547_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_548_A (renamed from geom_bottleneck/tests/data/test_548_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_548_B (renamed from geom_bottleneck/tests/data/test_548_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_549_A (renamed from geom_bottleneck/tests/data/test_549_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_549_B (renamed from geom_bottleneck/tests/data/test_549_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_550_A (renamed from geom_bottleneck/tests/data/test_550_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_550_B (renamed from geom_bottleneck/tests/data/test_550_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_551_A (renamed from geom_bottleneck/tests/data/test_551_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_551_B (renamed from geom_bottleneck/tests/data/test_551_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_552_A (renamed from geom_bottleneck/tests/data/test_552_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_552_B (renamed from geom_bottleneck/tests/data/test_552_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_553_A (renamed from geom_bottleneck/tests/data/test_553_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_553_B (renamed from geom_bottleneck/tests/data/test_553_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_554_A (renamed from geom_bottleneck/tests/data/test_554_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_554_B (renamed from geom_bottleneck/tests/data/test_554_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_555_A (renamed from geom_bottleneck/tests/data/test_555_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_555_B (renamed from geom_bottleneck/tests/data/test_555_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_556_A (renamed from geom_bottleneck/tests/data/test_556_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_556_B (renamed from geom_bottleneck/tests/data/test_556_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_557_A (renamed from geom_bottleneck/tests/data/test_557_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_557_B (renamed from geom_bottleneck/tests/data/test_557_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_558_A (renamed from geom_bottleneck/tests/data/test_558_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_558_B (renamed from geom_bottleneck/tests/data/test_558_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_559_A (renamed from geom_bottleneck/tests/data/test_559_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_559_B (renamed from geom_bottleneck/tests/data/test_559_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_560_A (renamed from geom_bottleneck/tests/data/test_560_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_560_B (renamed from geom_bottleneck/tests/data/test_560_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_561_A (renamed from geom_bottleneck/tests/data/test_561_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_561_B (renamed from geom_bottleneck/tests/data/test_561_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_562_A (renamed from geom_bottleneck/tests/data/test_562_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_562_B (renamed from geom_bottleneck/tests/data/test_562_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_563_A (renamed from geom_bottleneck/tests/data/test_563_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_563_B (renamed from geom_bottleneck/tests/data/test_563_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_564_A (renamed from geom_bottleneck/tests/data/test_564_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_564_B (renamed from geom_bottleneck/tests/data/test_564_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_565_A (renamed from geom_bottleneck/tests/data/test_565_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_565_B (renamed from geom_bottleneck/tests/data/test_565_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_566_A (renamed from geom_bottleneck/tests/data/test_566_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_566_B (renamed from geom_bottleneck/tests/data/test_566_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_567_A (renamed from geom_bottleneck/tests/data/test_567_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_567_B (renamed from geom_bottleneck/tests/data/test_567_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_568_A (renamed from geom_bottleneck/tests/data/test_568_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_568_B (renamed from geom_bottleneck/tests/data/test_568_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_569_A (renamed from geom_bottleneck/tests/data/test_569_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_569_B (renamed from geom_bottleneck/tests/data/test_569_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_570_A (renamed from geom_bottleneck/tests/data/test_570_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_570_B (renamed from geom_bottleneck/tests/data/test_570_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_571_A (renamed from geom_bottleneck/tests/data/test_571_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_571_B (renamed from geom_bottleneck/tests/data/test_571_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_572_A (renamed from geom_bottleneck/tests/data/test_572_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_572_B (renamed from geom_bottleneck/tests/data/test_572_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_573_A (renamed from geom_bottleneck/tests/data/test_573_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_573_B (renamed from geom_bottleneck/tests/data/test_573_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_574_A (renamed from geom_bottleneck/tests/data/test_574_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_574_B (renamed from geom_bottleneck/tests/data/test_574_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_575_A (renamed from geom_bottleneck/tests/data/test_575_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_575_B (renamed from geom_bottleneck/tests/data/test_575_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_576_A (renamed from geom_bottleneck/tests/data/test_576_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_576_B (renamed from geom_bottleneck/tests/data/test_576_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_577_A (renamed from geom_bottleneck/tests/data/test_577_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_577_B (renamed from geom_bottleneck/tests/data/test_577_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_578_A (renamed from geom_bottleneck/tests/data/test_578_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_578_B (renamed from geom_bottleneck/tests/data/test_578_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_579_A (renamed from geom_bottleneck/tests/data/test_579_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_579_B (renamed from geom_bottleneck/tests/data/test_579_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_580_A (renamed from geom_bottleneck/tests/data/test_580_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_580_B (renamed from geom_bottleneck/tests/data/test_580_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_581_A (renamed from geom_bottleneck/tests/data/test_581_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_581_B (renamed from geom_bottleneck/tests/data/test_581_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_582_A (renamed from geom_bottleneck/tests/data/test_582_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_582_B (renamed from geom_bottleneck/tests/data/test_582_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_583_A (renamed from geom_bottleneck/tests/data/test_583_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_583_B (renamed from geom_bottleneck/tests/data/test_583_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_584_A (renamed from geom_bottleneck/tests/data/test_584_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_584_B (renamed from geom_bottleneck/tests/data/test_584_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_585_A (renamed from geom_bottleneck/tests/data/test_585_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_585_B (renamed from geom_bottleneck/tests/data/test_585_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_586_A (renamed from geom_bottleneck/tests/data/test_586_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_586_B (renamed from geom_bottleneck/tests/data/test_586_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_587_A (renamed from geom_bottleneck/tests/data/test_587_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_587_B (renamed from geom_bottleneck/tests/data/test_587_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_588_A (renamed from geom_bottleneck/tests/data/test_588_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_588_B (renamed from geom_bottleneck/tests/data/test_588_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_589_A (renamed from geom_bottleneck/tests/data/test_589_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_589_B (renamed from geom_bottleneck/tests/data/test_589_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_590_A (renamed from geom_bottleneck/tests/data/test_590_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_590_B (renamed from geom_bottleneck/tests/data/test_590_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_591_A (renamed from geom_bottleneck/tests/data/test_591_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_591_B (renamed from geom_bottleneck/tests/data/test_591_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_592_A (renamed from geom_bottleneck/tests/data/test_592_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_592_B (renamed from geom_bottleneck/tests/data/test_592_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_593_A (renamed from geom_bottleneck/tests/data/test_593_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_593_B (renamed from geom_bottleneck/tests/data/test_593_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_594_A (renamed from geom_bottleneck/tests/data/test_594_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_594_B (renamed from geom_bottleneck/tests/data/test_594_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_595_A (renamed from geom_bottleneck/tests/data/test_595_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_595_B (renamed from geom_bottleneck/tests/data/test_595_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_596_A (renamed from geom_bottleneck/tests/data/test_596_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_596_B (renamed from geom_bottleneck/tests/data/test_596_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_597_A (renamed from geom_bottleneck/tests/data/test_597_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_597_B (renamed from geom_bottleneck/tests/data/test_597_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_598_A (renamed from geom_bottleneck/tests/data/test_598_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_598_B (renamed from geom_bottleneck/tests/data/test_598_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_599_A (renamed from geom_bottleneck/tests/data/test_599_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_599_B (renamed from geom_bottleneck/tests/data/test_599_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_600_A (renamed from geom_bottleneck/tests/data/test_600_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_600_B (renamed from geom_bottleneck/tests/data/test_600_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_601_A (renamed from geom_bottleneck/tests/data/test_601_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_601_B (renamed from geom_bottleneck/tests/data/test_601_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_602_A (renamed from geom_bottleneck/tests/data/test_602_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_602_B (renamed from geom_bottleneck/tests/data/test_602_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_603_A (renamed from geom_bottleneck/tests/data/test_603_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_603_B (renamed from geom_bottleneck/tests/data/test_603_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_604_A (renamed from geom_bottleneck/tests/data/test_604_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_604_B (renamed from geom_bottleneck/tests/data/test_604_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_605_A (renamed from geom_bottleneck/tests/data/test_605_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_605_B (renamed from geom_bottleneck/tests/data/test_605_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_606_A (renamed from geom_bottleneck/tests/data/test_606_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_606_B (renamed from geom_bottleneck/tests/data/test_606_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_607_A (renamed from geom_bottleneck/tests/data/test_607_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_607_B (renamed from geom_bottleneck/tests/data/test_607_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_608_A (renamed from geom_bottleneck/tests/data/test_608_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_608_B (renamed from geom_bottleneck/tests/data/test_608_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_609_A (renamed from geom_bottleneck/tests/data/test_609_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_609_B (renamed from geom_bottleneck/tests/data/test_609_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_610_A (renamed from geom_bottleneck/tests/data/test_610_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_610_B (renamed from geom_bottleneck/tests/data/test_610_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_611_A (renamed from geom_bottleneck/tests/data/test_611_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_611_B (renamed from geom_bottleneck/tests/data/test_611_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_612_A (renamed from geom_bottleneck/tests/data/test_612_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_612_B (renamed from geom_bottleneck/tests/data/test_612_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_613_A (renamed from geom_bottleneck/tests/data/test_613_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_613_B (renamed from geom_bottleneck/tests/data/test_613_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_614_A (renamed from geom_bottleneck/tests/data/test_614_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_614_B (renamed from geom_bottleneck/tests/data/test_614_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_615_A (renamed from geom_bottleneck/tests/data/test_615_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_615_B (renamed from geom_bottleneck/tests/data/test_615_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_616_A (renamed from geom_bottleneck/tests/data/test_616_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_616_B (renamed from geom_bottleneck/tests/data/test_616_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_617_A (renamed from geom_bottleneck/tests/data/test_617_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_617_B (renamed from geom_bottleneck/tests/data/test_617_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_618_A (renamed from geom_bottleneck/tests/data/test_618_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_618_B (renamed from geom_bottleneck/tests/data/test_618_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_619_A (renamed from geom_bottleneck/tests/data/test_619_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_619_B (renamed from geom_bottleneck/tests/data/test_619_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_620_A (renamed from geom_bottleneck/tests/data/test_620_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_620_B (renamed from geom_bottleneck/tests/data/test_620_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_621_A (renamed from geom_bottleneck/tests/data/test_621_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_621_B (renamed from geom_bottleneck/tests/data/test_621_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_622_A (renamed from geom_bottleneck/tests/data/test_622_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_622_B (renamed from geom_bottleneck/tests/data/test_622_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_623_A (renamed from geom_bottleneck/tests/data/test_623_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_623_B (renamed from geom_bottleneck/tests/data/test_623_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_624_A (renamed from geom_bottleneck/tests/data/test_624_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_624_B (renamed from geom_bottleneck/tests/data/test_624_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_625_A (renamed from geom_bottleneck/tests/data/test_625_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_625_B (renamed from geom_bottleneck/tests/data/test_625_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_626_A (renamed from geom_bottleneck/tests/data/test_626_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_626_B (renamed from geom_bottleneck/tests/data/test_626_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_627_A (renamed from geom_bottleneck/tests/data/test_627_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_627_B (renamed from geom_bottleneck/tests/data/test_627_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_628_A (renamed from geom_bottleneck/tests/data/test_628_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_628_B (renamed from geom_bottleneck/tests/data/test_628_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_629_A (renamed from geom_bottleneck/tests/data/test_629_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_629_B (renamed from geom_bottleneck/tests/data/test_629_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_630_A (renamed from geom_bottleneck/tests/data/test_630_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_630_B (renamed from geom_bottleneck/tests/data/test_630_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_631_A (renamed from geom_bottleneck/tests/data/test_631_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_631_B (renamed from geom_bottleneck/tests/data/test_631_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_632_A (renamed from geom_bottleneck/tests/data/test_632_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_632_B (renamed from geom_bottleneck/tests/data/test_632_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_633_A (renamed from geom_bottleneck/tests/data/test_633_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_633_B (renamed from geom_bottleneck/tests/data/test_633_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_634_A (renamed from geom_bottleneck/tests/data/test_634_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_634_B (renamed from geom_bottleneck/tests/data/test_634_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_635_A (renamed from geom_bottleneck/tests/data/test_635_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_635_B (renamed from geom_bottleneck/tests/data/test_635_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_636_A (renamed from geom_bottleneck/tests/data/test_636_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_636_B (renamed from geom_bottleneck/tests/data/test_636_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_637_A (renamed from geom_bottleneck/tests/data/test_637_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_637_B (renamed from geom_bottleneck/tests/data/test_637_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_638_A (renamed from geom_bottleneck/tests/data/test_638_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_638_B (renamed from geom_bottleneck/tests/data/test_638_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_639_A (renamed from geom_bottleneck/tests/data/test_639_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_639_B (renamed from geom_bottleneck/tests/data/test_639_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_640_A (renamed from geom_bottleneck/tests/data/test_640_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_640_B (renamed from geom_bottleneck/tests/data/test_640_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_641_A (renamed from geom_bottleneck/tests/data/test_641_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_641_B (renamed from geom_bottleneck/tests/data/test_641_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_642_A (renamed from geom_bottleneck/tests/data/test_642_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_642_B (renamed from geom_bottleneck/tests/data/test_642_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_643_A (renamed from geom_bottleneck/tests/data/test_643_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_643_B (renamed from geom_bottleneck/tests/data/test_643_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_644_A (renamed from geom_bottleneck/tests/data/test_644_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_644_B (renamed from geom_bottleneck/tests/data/test_644_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_645_A (renamed from geom_bottleneck/tests/data/test_645_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_645_B (renamed from geom_bottleneck/tests/data/test_645_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_646_A (renamed from geom_bottleneck/tests/data/test_646_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_646_B (renamed from geom_bottleneck/tests/data/test_646_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_647_A (renamed from geom_bottleneck/tests/data/test_647_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_647_B (renamed from geom_bottleneck/tests/data/test_647_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_648_A (renamed from geom_bottleneck/tests/data/test_648_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_648_B (renamed from geom_bottleneck/tests/data/test_648_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_649_A (renamed from geom_bottleneck/tests/data/test_649_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_649_B (renamed from geom_bottleneck/tests/data/test_649_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_650_A (renamed from geom_bottleneck/tests/data/test_650_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_650_B (renamed from geom_bottleneck/tests/data/test_650_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_651_A (renamed from geom_bottleneck/tests/data/test_651_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_651_B (renamed from geom_bottleneck/tests/data/test_651_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_652_A (renamed from geom_bottleneck/tests/data/test_652_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_652_B (renamed from geom_bottleneck/tests/data/test_652_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_653_A (renamed from geom_bottleneck/tests/data/test_653_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_653_B (renamed from geom_bottleneck/tests/data/test_653_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_654_A (renamed from geom_bottleneck/tests/data/test_654_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_654_B (renamed from geom_bottleneck/tests/data/test_654_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_655_A (renamed from geom_bottleneck/tests/data/test_655_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_655_B (renamed from geom_bottleneck/tests/data/test_655_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_656_A (renamed from geom_bottleneck/tests/data/test_656_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_656_B (renamed from geom_bottleneck/tests/data/test_656_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_657_A (renamed from geom_bottleneck/tests/data/test_657_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_657_B (renamed from geom_bottleneck/tests/data/test_657_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_658_A (renamed from geom_bottleneck/tests/data/test_658_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_658_B (renamed from geom_bottleneck/tests/data/test_658_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_659_A (renamed from geom_bottleneck/tests/data/test_659_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_659_B (renamed from geom_bottleneck/tests/data/test_659_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_660_A (renamed from geom_bottleneck/tests/data/test_660_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_660_B (renamed from geom_bottleneck/tests/data/test_660_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_661_A (renamed from geom_bottleneck/tests/data/test_661_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_661_B (renamed from geom_bottleneck/tests/data/test_661_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_662_A (renamed from geom_bottleneck/tests/data/test_662_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_662_B (renamed from geom_bottleneck/tests/data/test_662_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_663_A (renamed from geom_bottleneck/tests/data/test_663_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_663_B (renamed from geom_bottleneck/tests/data/test_663_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_664_A (renamed from geom_bottleneck/tests/data/test_664_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_664_B (renamed from geom_bottleneck/tests/data/test_664_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_665_A (renamed from geom_bottleneck/tests/data/test_665_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_665_B (renamed from geom_bottleneck/tests/data/test_665_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_666_A (renamed from geom_bottleneck/tests/data/test_666_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_666_B (renamed from geom_bottleneck/tests/data/test_666_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_667_A (renamed from geom_bottleneck/tests/data/test_667_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_667_B (renamed from geom_bottleneck/tests/data/test_667_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_668_A (renamed from geom_bottleneck/tests/data/test_668_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_668_B (renamed from geom_bottleneck/tests/data/test_668_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_669_A (renamed from geom_bottleneck/tests/data/test_669_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_669_B (renamed from geom_bottleneck/tests/data/test_669_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_670_A (renamed from geom_bottleneck/tests/data/test_670_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_670_B (renamed from geom_bottleneck/tests/data/test_670_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_671_A (renamed from geom_bottleneck/tests/data/test_671_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_671_B (renamed from geom_bottleneck/tests/data/test_671_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_672_A (renamed from geom_bottleneck/tests/data/test_672_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_672_B (renamed from geom_bottleneck/tests/data/test_672_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_673_A (renamed from geom_bottleneck/tests/data/test_673_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_673_B (renamed from geom_bottleneck/tests/data/test_673_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_674_A (renamed from geom_bottleneck/tests/data/test_674_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_674_B (renamed from geom_bottleneck/tests/data/test_674_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_675_A (renamed from geom_bottleneck/tests/data/test_675_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_675_B (renamed from geom_bottleneck/tests/data/test_675_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_676_A (renamed from geom_bottleneck/tests/data/test_676_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_676_B (renamed from geom_bottleneck/tests/data/test_676_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_677_A (renamed from geom_bottleneck/tests/data/test_677_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_677_B (renamed from geom_bottleneck/tests/data/test_677_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_678_A (renamed from geom_bottleneck/tests/data/test_678_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_678_B (renamed from geom_bottleneck/tests/data/test_678_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_679_A (renamed from geom_bottleneck/tests/data/test_679_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_679_B (renamed from geom_bottleneck/tests/data/test_679_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_680_A (renamed from geom_bottleneck/tests/data/test_680_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_680_B (renamed from geom_bottleneck/tests/data/test_680_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_681_A (renamed from geom_bottleneck/tests/data/test_681_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_681_B (renamed from geom_bottleneck/tests/data/test_681_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_682_A (renamed from geom_bottleneck/tests/data/test_682_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_682_B (renamed from geom_bottleneck/tests/data/test_682_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_683_A (renamed from geom_bottleneck/tests/data/test_683_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_683_B (renamed from geom_bottleneck/tests/data/test_683_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_684_A (renamed from geom_bottleneck/tests/data/test_684_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_684_B (renamed from geom_bottleneck/tests/data/test_684_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_685_A (renamed from geom_bottleneck/tests/data/test_685_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_685_B (renamed from geom_bottleneck/tests/data/test_685_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_686_A (renamed from geom_bottleneck/tests/data/test_686_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_686_B (renamed from geom_bottleneck/tests/data/test_686_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_687_A (renamed from geom_bottleneck/tests/data/test_687_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_687_B (renamed from geom_bottleneck/tests/data/test_687_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_688_A (renamed from geom_bottleneck/tests/data/test_688_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_688_B (renamed from geom_bottleneck/tests/data/test_688_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_689_A (renamed from geom_bottleneck/tests/data/test_689_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_689_B (renamed from geom_bottleneck/tests/data/test_689_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_690_A (renamed from geom_bottleneck/tests/data/test_690_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_690_B (renamed from geom_bottleneck/tests/data/test_690_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_691_A (renamed from geom_bottleneck/tests/data/test_691_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_691_B (renamed from geom_bottleneck/tests/data/test_691_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_692_A (renamed from geom_bottleneck/tests/data/test_692_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_692_B (renamed from geom_bottleneck/tests/data/test_692_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_693_A (renamed from geom_bottleneck/tests/data/test_693_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_693_B (renamed from geom_bottleneck/tests/data/test_693_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_694_A (renamed from geom_bottleneck/tests/data/test_694_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_694_B (renamed from geom_bottleneck/tests/data/test_694_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_695_A (renamed from geom_bottleneck/tests/data/test_695_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_695_B (renamed from geom_bottleneck/tests/data/test_695_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_696_A (renamed from geom_bottleneck/tests/data/test_696_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_696_B (renamed from geom_bottleneck/tests/data/test_696_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_697_A (renamed from geom_bottleneck/tests/data/test_697_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_697_B (renamed from geom_bottleneck/tests/data/test_697_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_698_A (renamed from geom_bottleneck/tests/data/test_698_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_698_B (renamed from geom_bottleneck/tests/data/test_698_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_699_A (renamed from geom_bottleneck/tests/data/test_699_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_699_B (renamed from geom_bottleneck/tests/data/test_699_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_700_A (renamed from geom_bottleneck/tests/data/test_700_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_700_B (renamed from geom_bottleneck/tests/data/test_700_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_701_A (renamed from geom_bottleneck/tests/data/test_701_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_701_B (renamed from geom_bottleneck/tests/data/test_701_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_702_A (renamed from geom_bottleneck/tests/data/test_702_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_702_B (renamed from geom_bottleneck/tests/data/test_702_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_703_A (renamed from geom_bottleneck/tests/data/test_703_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_703_B (renamed from geom_bottleneck/tests/data/test_703_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_704_A (renamed from geom_bottleneck/tests/data/test_704_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_704_B (renamed from geom_bottleneck/tests/data/test_704_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_705_A (renamed from geom_bottleneck/tests/data/test_705_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_705_B (renamed from geom_bottleneck/tests/data/test_705_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_706_A (renamed from geom_bottleneck/tests/data/test_706_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_706_B (renamed from geom_bottleneck/tests/data/test_706_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_707_A (renamed from geom_bottleneck/tests/data/test_707_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_707_B (renamed from geom_bottleneck/tests/data/test_707_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_708_A (renamed from geom_bottleneck/tests/data/test_708_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_708_B (renamed from geom_bottleneck/tests/data/test_708_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_709_A (renamed from geom_bottleneck/tests/data/test_709_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_709_B (renamed from geom_bottleneck/tests/data/test_709_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_710_A (renamed from geom_bottleneck/tests/data/test_710_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_710_B (renamed from geom_bottleneck/tests/data/test_710_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_711_A (renamed from geom_bottleneck/tests/data/test_711_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_711_B (renamed from geom_bottleneck/tests/data/test_711_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_712_A (renamed from geom_bottleneck/tests/data/test_712_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_712_B (renamed from geom_bottleneck/tests/data/test_712_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_713_A (renamed from geom_bottleneck/tests/data/test_713_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_713_B (renamed from geom_bottleneck/tests/data/test_713_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_714_A (renamed from geom_bottleneck/tests/data/test_714_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_714_B (renamed from geom_bottleneck/tests/data/test_714_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_715_A (renamed from geom_bottleneck/tests/data/test_715_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_715_B (renamed from geom_bottleneck/tests/data/test_715_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_716_A (renamed from geom_bottleneck/tests/data/test_716_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_716_B (renamed from geom_bottleneck/tests/data/test_716_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_717_A (renamed from geom_bottleneck/tests/data/test_717_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_717_B (renamed from geom_bottleneck/tests/data/test_717_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_718_A (renamed from geom_bottleneck/tests/data/test_718_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_718_B (renamed from geom_bottleneck/tests/data/test_718_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_719_A (renamed from geom_bottleneck/tests/data/test_719_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_719_B (renamed from geom_bottleneck/tests/data/test_719_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_720_A (renamed from geom_bottleneck/tests/data/test_720_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_720_B (renamed from geom_bottleneck/tests/data/test_720_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_721_A (renamed from geom_bottleneck/tests/data/test_721_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_721_B (renamed from geom_bottleneck/tests/data/test_721_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_722_A (renamed from geom_bottleneck/tests/data/test_722_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_722_B (renamed from geom_bottleneck/tests/data/test_722_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_723_A (renamed from geom_bottleneck/tests/data/test_723_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_723_B (renamed from geom_bottleneck/tests/data/test_723_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_724_A (renamed from geom_bottleneck/tests/data/test_724_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_724_B (renamed from geom_bottleneck/tests/data/test_724_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_725_A (renamed from geom_bottleneck/tests/data/test_725_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_725_B (renamed from geom_bottleneck/tests/data/test_725_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_726_A (renamed from geom_bottleneck/tests/data/test_726_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_726_B (renamed from geom_bottleneck/tests/data/test_726_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_727_A (renamed from geom_bottleneck/tests/data/test_727_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_727_B (renamed from geom_bottleneck/tests/data/test_727_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_728_A (renamed from geom_bottleneck/tests/data/test_728_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_728_B (renamed from geom_bottleneck/tests/data/test_728_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_729_A (renamed from geom_bottleneck/tests/data/test_729_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_729_B (renamed from geom_bottleneck/tests/data/test_729_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_730_A (renamed from geom_bottleneck/tests/data/test_730_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_730_B (renamed from geom_bottleneck/tests/data/test_730_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_731_A (renamed from geom_bottleneck/tests/data/test_731_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_731_B (renamed from geom_bottleneck/tests/data/test_731_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_732_A (renamed from geom_bottleneck/tests/data/test_732_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_732_B (renamed from geom_bottleneck/tests/data/test_732_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_733_A (renamed from geom_bottleneck/tests/data/test_733_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_733_B (renamed from geom_bottleneck/tests/data/test_733_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_734_A (renamed from geom_bottleneck/tests/data/test_734_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_734_B (renamed from geom_bottleneck/tests/data/test_734_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_735_A (renamed from geom_bottleneck/tests/data/test_735_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_735_B (renamed from geom_bottleneck/tests/data/test_735_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_736_A (renamed from geom_bottleneck/tests/data/test_736_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_736_B (renamed from geom_bottleneck/tests/data/test_736_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_737_A (renamed from geom_bottleneck/tests/data/test_737_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_737_B (renamed from geom_bottleneck/tests/data/test_737_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_738_A (renamed from geom_bottleneck/tests/data/test_738_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_738_B (renamed from geom_bottleneck/tests/data/test_738_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_739_A (renamed from geom_bottleneck/tests/data/test_739_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_739_B (renamed from geom_bottleneck/tests/data/test_739_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_740_A (renamed from geom_bottleneck/tests/data/test_740_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_740_B (renamed from geom_bottleneck/tests/data/test_740_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_741_A (renamed from geom_bottleneck/tests/data/test_741_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_741_B (renamed from geom_bottleneck/tests/data/test_741_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_742_A (renamed from geom_bottleneck/tests/data/test_742_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_742_B (renamed from geom_bottleneck/tests/data/test_742_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_743_A (renamed from geom_bottleneck/tests/data/test_743_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_743_B (renamed from geom_bottleneck/tests/data/test_743_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_744_A (renamed from geom_bottleneck/tests/data/test_744_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_744_B (renamed from geom_bottleneck/tests/data/test_744_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_745_A (renamed from geom_bottleneck/tests/data/test_745_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_745_B (renamed from geom_bottleneck/tests/data/test_745_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_746_A (renamed from geom_bottleneck/tests/data/test_746_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_746_B (renamed from geom_bottleneck/tests/data/test_746_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_747_A (renamed from geom_bottleneck/tests/data/test_747_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_747_B (renamed from geom_bottleneck/tests/data/test_747_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_748_A (renamed from geom_bottleneck/tests/data/test_748_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_748_B (renamed from geom_bottleneck/tests/data/test_748_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_749_A (renamed from geom_bottleneck/tests/data/test_749_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_749_B (renamed from geom_bottleneck/tests/data/test_749_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_750_A (renamed from geom_bottleneck/tests/data/test_750_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_750_B (renamed from geom_bottleneck/tests/data/test_750_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_751_A (renamed from geom_bottleneck/tests/data/test_751_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_751_B (renamed from geom_bottleneck/tests/data/test_751_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_752_A (renamed from geom_bottleneck/tests/data/test_752_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_752_B (renamed from geom_bottleneck/tests/data/test_752_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_753_A (renamed from geom_bottleneck/tests/data/test_753_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_753_B (renamed from geom_bottleneck/tests/data/test_753_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_754_A (renamed from geom_bottleneck/tests/data/test_754_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_754_B (renamed from geom_bottleneck/tests/data/test_754_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_755_A (renamed from geom_bottleneck/tests/data/test_755_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_755_B (renamed from geom_bottleneck/tests/data/test_755_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_756_A (renamed from geom_bottleneck/tests/data/test_756_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_756_B (renamed from geom_bottleneck/tests/data/test_756_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_757_A (renamed from geom_bottleneck/tests/data/test_757_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_757_B (renamed from geom_bottleneck/tests/data/test_757_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_758_A (renamed from geom_bottleneck/tests/data/test_758_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_758_B (renamed from geom_bottleneck/tests/data/test_758_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_759_A (renamed from geom_bottleneck/tests/data/test_759_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_759_B (renamed from geom_bottleneck/tests/data/test_759_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_760_A (renamed from geom_bottleneck/tests/data/test_760_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_760_B (renamed from geom_bottleneck/tests/data/test_760_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_761_A (renamed from geom_bottleneck/tests/data/test_761_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_761_B (renamed from geom_bottleneck/tests/data/test_761_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_762_A (renamed from geom_bottleneck/tests/data/test_762_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_762_B (renamed from geom_bottleneck/tests/data/test_762_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_763_A (renamed from geom_bottleneck/tests/data/test_763_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_763_B (renamed from geom_bottleneck/tests/data/test_763_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_764_A (renamed from geom_bottleneck/tests/data/test_764_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_764_B (renamed from geom_bottleneck/tests/data/test_764_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_765_A (renamed from geom_bottleneck/tests/data/test_765_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_765_B (renamed from geom_bottleneck/tests/data/test_765_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_766_A (renamed from geom_bottleneck/tests/data/test_766_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_766_B (renamed from geom_bottleneck/tests/data/test_766_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_767_A (renamed from geom_bottleneck/tests/data/test_767_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_767_B (renamed from geom_bottleneck/tests/data/test_767_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_768_A (renamed from geom_bottleneck/tests/data/test_768_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_768_B (renamed from geom_bottleneck/tests/data/test_768_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_769_A (renamed from geom_bottleneck/tests/data/test_769_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_769_B (renamed from geom_bottleneck/tests/data/test_769_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_770_A (renamed from geom_bottleneck/tests/data/test_770_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_770_B (renamed from geom_bottleneck/tests/data/test_770_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_771_A (renamed from geom_bottleneck/tests/data/test_771_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_771_B (renamed from geom_bottleneck/tests/data/test_771_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_772_A (renamed from geom_bottleneck/tests/data/test_772_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_772_B (renamed from geom_bottleneck/tests/data/test_772_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_773_A (renamed from geom_bottleneck/tests/data/test_773_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_773_B (renamed from geom_bottleneck/tests/data/test_773_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_774_A (renamed from geom_bottleneck/tests/data/test_774_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_774_B (renamed from geom_bottleneck/tests/data/test_774_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_775_A (renamed from geom_bottleneck/tests/data/test_775_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_775_B (renamed from geom_bottleneck/tests/data/test_775_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_776_A (renamed from geom_bottleneck/tests/data/test_776_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_776_B (renamed from geom_bottleneck/tests/data/test_776_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_777_A (renamed from geom_bottleneck/tests/data/test_777_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_777_B (renamed from geom_bottleneck/tests/data/test_777_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_778_A (renamed from geom_bottleneck/tests/data/test_778_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_778_B (renamed from geom_bottleneck/tests/data/test_778_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_779_A (renamed from geom_bottleneck/tests/data/test_779_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_779_B (renamed from geom_bottleneck/tests/data/test_779_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_780_A (renamed from geom_bottleneck/tests/data/test_780_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_780_B (renamed from geom_bottleneck/tests/data/test_780_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_781_A (renamed from geom_bottleneck/tests/data/test_781_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_781_B (renamed from geom_bottleneck/tests/data/test_781_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_782_A (renamed from geom_bottleneck/tests/data/test_782_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_782_B (renamed from geom_bottleneck/tests/data/test_782_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_783_A (renamed from geom_bottleneck/tests/data/test_783_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_783_B (renamed from geom_bottleneck/tests/data/test_783_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_784_A (renamed from geom_bottleneck/tests/data/test_784_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_784_B (renamed from geom_bottleneck/tests/data/test_784_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_785_A (renamed from geom_bottleneck/tests/data/test_785_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_785_B (renamed from geom_bottleneck/tests/data/test_785_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_786_A (renamed from geom_bottleneck/tests/data/test_786_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_786_B (renamed from geom_bottleneck/tests/data/test_786_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_787_A (renamed from geom_bottleneck/tests/data/test_787_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_787_B (renamed from geom_bottleneck/tests/data/test_787_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_788_A (renamed from geom_bottleneck/tests/data/test_788_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_788_B (renamed from geom_bottleneck/tests/data/test_788_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_789_A (renamed from geom_bottleneck/tests/data/test_789_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_789_B (renamed from geom_bottleneck/tests/data/test_789_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_790_A (renamed from geom_bottleneck/tests/data/test_790_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_790_B (renamed from geom_bottleneck/tests/data/test_790_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_791_A (renamed from geom_bottleneck/tests/data/test_791_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_791_B (renamed from geom_bottleneck/tests/data/test_791_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_792_A (renamed from geom_bottleneck/tests/data/test_792_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_792_B (renamed from geom_bottleneck/tests/data/test_792_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_793_A (renamed from geom_bottleneck/tests/data/test_793_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_793_B (renamed from geom_bottleneck/tests/data/test_793_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_794_A (renamed from geom_bottleneck/tests/data/test_794_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_794_B (renamed from geom_bottleneck/tests/data/test_794_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_795_A (renamed from geom_bottleneck/tests/data/test_795_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_795_B (renamed from geom_bottleneck/tests/data/test_795_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_796_A (renamed from geom_bottleneck/tests/data/test_796_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_796_B (renamed from geom_bottleneck/tests/data/test_796_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_797_A (renamed from geom_bottleneck/tests/data/test_797_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_797_B (renamed from geom_bottleneck/tests/data/test_797_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_798_A (renamed from geom_bottleneck/tests/data/test_798_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_798_B (renamed from geom_bottleneck/tests/data/test_798_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_799_A (renamed from geom_bottleneck/tests/data/test_799_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_799_B (renamed from geom_bottleneck/tests/data/test_799_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_800_A (renamed from geom_bottleneck/tests/data/test_800_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_800_B (renamed from geom_bottleneck/tests/data/test_800_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_801_A (renamed from geom_bottleneck/tests/data/test_801_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_801_B (renamed from geom_bottleneck/tests/data/test_801_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_802_A (renamed from geom_bottleneck/tests/data/test_802_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_802_B (renamed from geom_bottleneck/tests/data/test_802_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_803_A (renamed from geom_bottleneck/tests/data/test_803_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_803_B (renamed from geom_bottleneck/tests/data/test_803_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_804_A (renamed from geom_bottleneck/tests/data/test_804_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_804_B (renamed from geom_bottleneck/tests/data/test_804_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_805_A (renamed from geom_bottleneck/tests/data/test_805_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_805_B (renamed from geom_bottleneck/tests/data/test_805_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_806_A (renamed from geom_bottleneck/tests/data/test_806_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_806_B (renamed from geom_bottleneck/tests/data/test_806_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_807_A (renamed from geom_bottleneck/tests/data/test_807_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_807_B (renamed from geom_bottleneck/tests/data/test_807_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_808_A (renamed from geom_bottleneck/tests/data/test_808_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_808_B (renamed from geom_bottleneck/tests/data/test_808_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_809_A (renamed from geom_bottleneck/tests/data/test_809_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_809_B (renamed from geom_bottleneck/tests/data/test_809_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_810_A (renamed from geom_bottleneck/tests/data/test_810_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_810_B (renamed from geom_bottleneck/tests/data/test_810_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_811_A (renamed from geom_bottleneck/tests/data/test_811_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_811_B (renamed from geom_bottleneck/tests/data/test_811_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_812_A (renamed from geom_bottleneck/tests/data/test_812_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_812_B (renamed from geom_bottleneck/tests/data/test_812_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_813_A (renamed from geom_bottleneck/tests/data/test_813_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_813_B (renamed from geom_bottleneck/tests/data/test_813_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_814_A (renamed from geom_bottleneck/tests/data/test_814_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_814_B (renamed from geom_bottleneck/tests/data/test_814_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_815_A (renamed from geom_bottleneck/tests/data/test_815_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_815_B (renamed from geom_bottleneck/tests/data/test_815_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_816_A (renamed from geom_bottleneck/tests/data/test_816_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_816_B (renamed from geom_bottleneck/tests/data/test_816_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_817_A (renamed from geom_bottleneck/tests/data/test_817_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_817_B (renamed from geom_bottleneck/tests/data/test_817_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_818_A (renamed from geom_bottleneck/tests/data/test_818_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_818_B (renamed from geom_bottleneck/tests/data/test_818_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_819_A (renamed from geom_bottleneck/tests/data/test_819_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_819_B (renamed from geom_bottleneck/tests/data/test_819_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_820_A (renamed from geom_bottleneck/tests/data/test_820_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_820_B (renamed from geom_bottleneck/tests/data/test_820_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_821_A (renamed from geom_bottleneck/tests/data/test_821_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_821_B (renamed from geom_bottleneck/tests/data/test_821_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_822_A (renamed from geom_bottleneck/tests/data/test_822_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_822_B (renamed from geom_bottleneck/tests/data/test_822_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_823_A (renamed from geom_bottleneck/tests/data/test_823_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_823_B (renamed from geom_bottleneck/tests/data/test_823_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_824_A (renamed from geom_bottleneck/tests/data/test_824_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_824_B (renamed from geom_bottleneck/tests/data/test_824_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_825_A (renamed from geom_bottleneck/tests/data/test_825_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_825_B (renamed from geom_bottleneck/tests/data/test_825_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_826_A (renamed from geom_bottleneck/tests/data/test_826_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_826_B (renamed from geom_bottleneck/tests/data/test_826_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_827_A (renamed from geom_bottleneck/tests/data/test_827_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_827_B (renamed from geom_bottleneck/tests/data/test_827_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_828_A (renamed from geom_bottleneck/tests/data/test_828_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_828_B (renamed from geom_bottleneck/tests/data/test_828_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_829_A (renamed from geom_bottleneck/tests/data/test_829_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_829_B (renamed from geom_bottleneck/tests/data/test_829_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_830_A (renamed from geom_bottleneck/tests/data/test_830_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_830_B (renamed from geom_bottleneck/tests/data/test_830_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_831_A (renamed from geom_bottleneck/tests/data/test_831_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_831_B (renamed from geom_bottleneck/tests/data/test_831_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_832_A (renamed from geom_bottleneck/tests/data/test_832_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_832_B (renamed from geom_bottleneck/tests/data/test_832_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_833_A (renamed from geom_bottleneck/tests/data/test_833_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_833_B (renamed from geom_bottleneck/tests/data/test_833_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_834_A (renamed from geom_bottleneck/tests/data/test_834_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_834_B (renamed from geom_bottleneck/tests/data/test_834_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_835_A (renamed from geom_bottleneck/tests/data/test_835_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_835_B (renamed from geom_bottleneck/tests/data/test_835_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_836_A (renamed from geom_bottleneck/tests/data/test_836_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_836_B (renamed from geom_bottleneck/tests/data/test_836_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_837_A (renamed from geom_bottleneck/tests/data/test_837_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_837_B (renamed from geom_bottleneck/tests/data/test_837_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_838_A (renamed from geom_bottleneck/tests/data/test_838_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_838_B (renamed from geom_bottleneck/tests/data/test_838_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_839_A (renamed from geom_bottleneck/tests/data/test_839_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_839_B (renamed from geom_bottleneck/tests/data/test_839_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_840_A (renamed from geom_bottleneck/tests/data/test_840_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_840_B (renamed from geom_bottleneck/tests/data/test_840_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_841_A (renamed from geom_bottleneck/tests/data/test_841_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_841_B (renamed from geom_bottleneck/tests/data/test_841_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_842_A (renamed from geom_bottleneck/tests/data/test_842_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_842_B (renamed from geom_bottleneck/tests/data/test_842_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_843_A (renamed from geom_bottleneck/tests/data/test_843_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_843_B (renamed from geom_bottleneck/tests/data/test_843_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_844_A (renamed from geom_bottleneck/tests/data/test_844_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_844_B (renamed from geom_bottleneck/tests/data/test_844_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_845_A (renamed from geom_bottleneck/tests/data/test_845_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_845_B (renamed from geom_bottleneck/tests/data/test_845_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_846_A (renamed from geom_bottleneck/tests/data/test_846_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_846_B (renamed from geom_bottleneck/tests/data/test_846_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_847_A (renamed from geom_bottleneck/tests/data/test_847_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_847_B (renamed from geom_bottleneck/tests/data/test_847_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_848_A (renamed from geom_bottleneck/tests/data/test_848_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_848_B (renamed from geom_bottleneck/tests/data/test_848_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_849_A (renamed from geom_bottleneck/tests/data/test_849_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_849_B (renamed from geom_bottleneck/tests/data/test_849_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_850_A (renamed from geom_bottleneck/tests/data/test_850_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_850_B (renamed from geom_bottleneck/tests/data/test_850_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_851_A (renamed from geom_bottleneck/tests/data/test_851_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_851_B (renamed from geom_bottleneck/tests/data/test_851_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_852_A (renamed from geom_bottleneck/tests/data/test_852_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_852_B (renamed from geom_bottleneck/tests/data/test_852_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_853_A (renamed from geom_bottleneck/tests/data/test_853_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_853_B (renamed from geom_bottleneck/tests/data/test_853_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_854_A (renamed from geom_bottleneck/tests/data/test_854_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_854_B (renamed from geom_bottleneck/tests/data/test_854_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_855_A (renamed from geom_bottleneck/tests/data/test_855_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_855_B (renamed from geom_bottleneck/tests/data/test_855_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_856_A (renamed from geom_bottleneck/tests/data/test_856_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_856_B (renamed from geom_bottleneck/tests/data/test_856_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_857_A (renamed from geom_bottleneck/tests/data/test_857_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_857_B (renamed from geom_bottleneck/tests/data/test_857_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_858_A (renamed from geom_bottleneck/tests/data/test_858_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_858_B (renamed from geom_bottleneck/tests/data/test_858_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_859_A (renamed from geom_bottleneck/tests/data/test_859_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_859_B (renamed from geom_bottleneck/tests/data/test_859_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_860_A (renamed from geom_bottleneck/tests/data/test_860_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_860_B (renamed from geom_bottleneck/tests/data/test_860_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_861_A (renamed from geom_bottleneck/tests/data/test_861_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_861_B (renamed from geom_bottleneck/tests/data/test_861_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_862_A (renamed from geom_bottleneck/tests/data/test_862_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_862_B (renamed from geom_bottleneck/tests/data/test_862_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_863_A (renamed from geom_bottleneck/tests/data/test_863_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_863_B (renamed from geom_bottleneck/tests/data/test_863_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_864_A (renamed from geom_bottleneck/tests/data/test_864_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_864_B (renamed from geom_bottleneck/tests/data/test_864_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_865_A (renamed from geom_bottleneck/tests/data/test_865_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_865_B (renamed from geom_bottleneck/tests/data/test_865_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_866_A (renamed from geom_bottleneck/tests/data/test_866_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_866_B (renamed from geom_bottleneck/tests/data/test_866_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_867_A (renamed from geom_bottleneck/tests/data/test_867_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_867_B (renamed from geom_bottleneck/tests/data/test_867_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_868_A (renamed from geom_bottleneck/tests/data/test_868_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_868_B (renamed from geom_bottleneck/tests/data/test_868_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_869_A (renamed from geom_bottleneck/tests/data/test_869_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_869_B (renamed from geom_bottleneck/tests/data/test_869_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_870_A (renamed from geom_bottleneck/tests/data/test_870_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_870_B (renamed from geom_bottleneck/tests/data/test_870_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_871_A (renamed from geom_bottleneck/tests/data/test_871_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_871_B (renamed from geom_bottleneck/tests/data/test_871_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_872_A (renamed from geom_bottleneck/tests/data/test_872_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_872_B (renamed from geom_bottleneck/tests/data/test_872_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_873_A (renamed from geom_bottleneck/tests/data/test_873_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_873_B (renamed from geom_bottleneck/tests/data/test_873_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_874_A (renamed from geom_bottleneck/tests/data/test_874_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_874_B (renamed from geom_bottleneck/tests/data/test_874_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_875_A (renamed from geom_bottleneck/tests/data/test_875_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_875_B (renamed from geom_bottleneck/tests/data/test_875_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_876_A (renamed from geom_bottleneck/tests/data/test_876_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_876_B (renamed from geom_bottleneck/tests/data/test_876_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_877_A (renamed from geom_bottleneck/tests/data/test_877_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_877_B (renamed from geom_bottleneck/tests/data/test_877_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_878_A (renamed from geom_bottleneck/tests/data/test_878_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_878_B (renamed from geom_bottleneck/tests/data/test_878_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_879_A (renamed from geom_bottleneck/tests/data/test_879_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_879_B (renamed from geom_bottleneck/tests/data/test_879_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_list.txt (renamed from geom_bottleneck/tests/data/test_list.txt) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/test_list.txt.bak (renamed from geom_bottleneck/tests/data/test_list.txt.bak) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_100_A (renamed from geom_bottleneck/tests/data/ws_tests/test_100_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_100_A.pd.dipha (renamed from geom_bottleneck/tests/data/ws_tests/test_100_A.pd.dipha) | bin | 2424 -> 2424 bytes | |||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_100_B (renamed from geom_bottleneck/tests/data/ws_tests/test_100_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_100_B.pd.dipha (renamed from geom_bottleneck/tests/data/ws_tests/test_100_B.pd.dipha) | bin | 2424 -> 2424 bytes | |||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_200_A (renamed from geom_bottleneck/tests/data/ws_tests/test_200_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_200_B (renamed from geom_bottleneck/tests/data/ws_tests/test_200_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_5000_A (renamed from geom_bottleneck/tests/data/ws_tests/test_5000_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_5000_B (renamed from geom_bottleneck/tests/data/ws_tests/test_5000_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_5_A (renamed from geom_bottleneck/tests/data/ws_tests/test_5_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_5_A.pd.dipha (renamed from geom_bottleneck/tests/data/ws_tests/test_5_A.pd.dipha) | bin | 144 -> 144 bytes | |||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_5_B (renamed from geom_bottleneck/tests/data/ws_tests/test_5_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_5_B.pd.dipha (renamed from geom_bottleneck/tests/data/ws_tests/test_5_B.pd.dipha) | bin | 144 -> 144 bytes | |||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_diag1_A (renamed from geom_bottleneck/tests/data/ws_tests/test_diag1_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_diag1_A.pd.dipha (renamed from geom_bottleneck/tests/data/ws_tests/test_diag1_A.pd.dipha) | bin | 48 -> 48 bytes | |||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_diag1_B (renamed from geom_bottleneck/tests/data/ws_tests/test_diag1_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_diag1_B.pd.dipha (renamed from geom_bottleneck/tests/data/ws_tests/test_diag1_B.pd.dipha) | bin | 48 -> 48 bytes | |||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_diag2_A (renamed from geom_bottleneck/tests/data/ws_tests/test_diag2_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_diag2_A.pd.dipha (renamed from geom_bottleneck/tests/data/ws_tests/test_diag2_A.pd.dipha) | bin | 48 -> 48 bytes | |||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_diag2_B (renamed from geom_bottleneck/tests/data/ws_tests/test_diag2_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_diag2_B.pd.dipha (renamed from geom_bottleneck/tests/data/ws_tests/test_diag2_B.pd.dipha) | bin | 48 -> 48 bytes | |||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_diag3_A (renamed from geom_bottleneck/tests/data/ws_tests/test_diag3_A) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_diag3_A.pd.dipha (renamed from geom_bottleneck/tests/data/ws_tests/test_diag3_A.pd.dipha) | bin | 5304 -> 5304 bytes | |||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_diag3_B (renamed from geom_bottleneck/tests/data/ws_tests/test_diag3_B) | 0 | ||||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_diag3_B.pd.dipha (renamed from geom_bottleneck/tests/data/ws_tests/test_diag3_B.pd.dipha) | bin | 4656 -> 4656 bytes | |||
-rw-r--r-- | bottleneck/tests/data/ws_tests/test_list.txt (renamed from geom_bottleneck/tests/data/ws_tests/test_list.txt) | 0 | ||||
-rw-r--r-- | bottleneck/tests/test_hera_bottleneck.cpp (renamed from geom_bottleneck/tests/test_hera_bottleneck.cpp) | 0 | ||||
-rw-r--r-- | bottleneck/tests/tests_main.cpp (renamed from geom_bottleneck/tests/tests_main.cpp) | 0 | ||||
-rw-r--r-- | geom_matching/.gitignore | 31 | ||||
-rw-r--r-- | matching/CMakeLists.txt | 56 | ||||
-rw-r--r-- | matching/README.md | 69 | ||||
-rw-r--r-- | matching/example/matching_dist.cpp | 393 | ||||
-rw-r--r-- | matching/example/module_example.cpp | 68 | ||||
-rw-r--r-- | matching/include/bifiltration.h | 140 | ||||
-rw-r--r-- | matching/include/bifiltration.hpp | 421 | ||||
-rw-r--r-- | matching/include/box.h | 59 | ||||
-rw-r--r-- | matching/include/box.hpp | 52 | ||||
-rw-r--r-- | matching/include/catch/catch.hpp | 13359 | ||||
-rw-r--r-- | matching/include/cell_with_value.h | 141 | ||||
-rw-r--r-- | matching/include/cell_with_value.hpp | 224 | ||||
-rw-r--r-- | matching/include/common_defs.h | 10 | ||||
-rw-r--r-- | matching/include/common_util.h | 188 | ||||
-rw-r--r-- | matching/include/common_util.hpp | 96 | ||||
-rw-r--r-- | matching/include/dual_box.h | 83 | ||||
-rw-r--r-- | matching/include/dual_box.hpp | 190 | ||||
-rw-r--r-- | matching/include/dual_point.h | 107 | ||||
-rw-r--r-- | matching/include/dual_point.hpp | 299 | ||||
-rw-r--r-- | matching/include/matching_distance.h | 290 | ||||
-rw-r--r-- | matching/include/matching_distance.hpp | 812 | ||||
-rw-r--r-- | matching/include/opts/opts.h | 499 | ||||
-rw-r--r-- | matching/include/persistence_module.h | 111 | ||||
-rw-r--r-- | matching/include/persistence_module.hpp | 202 | ||||
-rw-r--r-- | matching/include/phat/algorithms/chunk_reduction.h | 223 | ||||
-rw-r--r-- | matching/include/phat/algorithms/row_reduction.h | 56 | ||||
-rw-r--r-- | matching/include/phat/algorithms/spectral_sequence_reduction.h | 80 | ||||
-rw-r--r-- | matching/include/phat/algorithms/standard_reduction.h | 47 | ||||
-rw-r--r-- | matching/include/phat/algorithms/twist_reduction.h | 51 | ||||
-rw-r--r-- | matching/include/phat/boundary_matrix.h | 343 | ||||
-rw-r--r-- | matching/include/phat/compute_persistence_pairs.h | 137 | ||||
-rw-r--r-- | matching/include/phat/helpers/dualize.h | 74 | ||||
-rw-r--r-- | matching/include/phat/helpers/misc.h | 78 | ||||
-rw-r--r-- | matching/include/phat/helpers/thread_local_storage.h | 52 | ||||
-rw-r--r-- | matching/include/phat/persistence_pairs.h | 155 | ||||
-rw-r--r-- | matching/include/phat/representations/abstract_pivot_column.h | 102 | ||||
-rw-r--r-- | matching/include/phat/representations/bit_tree_pivot_column.h | 165 | ||||
-rw-r--r-- | matching/include/phat/representations/full_pivot_column.h | 100 | ||||
-rw-r--r-- | matching/include/phat/representations/heap_pivot_column.h | 126 | ||||
-rw-r--r-- | matching/include/phat/representations/sparse_pivot_column.h | 79 | ||||
-rw-r--r-- | matching/include/phat/representations/vector_heap.h | 170 | ||||
-rw-r--r-- | matching/include/phat/representations/vector_list.h | 101 | ||||
-rw-r--r-- | matching/include/phat/representations/vector_set.h | 99 | ||||
-rw-r--r-- | matching/include/phat/representations/vector_vector.h | 107 | ||||
-rw-r--r-- | matching/include/simplex.h | 163 | ||||
-rw-r--r-- | matching/include/simplex.hpp | 79 | ||||
-rw-r--r-- | matching/include/spdlog/async.h | 87 | ||||
-rw-r--r-- | matching/include/spdlog/async_logger.h | 73 | ||||
-rw-r--r-- | matching/include/spdlog/common.h | 243 | ||||
-rw-r--r-- | matching/include/spdlog/details/async_logger_impl.h | 110 | ||||
-rw-r--r-- | matching/include/spdlog/details/circular_q.h | 72 | ||||
-rw-r--r-- | matching/include/spdlog/details/console_globals.h | 74 | ||||
-rw-r--r-- | matching/include/spdlog/details/file_helper.h | 152 | ||||
-rw-r--r-- | matching/include/spdlog/details/fmt_helper.h | 122 | ||||
-rw-r--r-- | matching/include/spdlog/details/log_msg.h | 55 | ||||
-rw-r--r-- | matching/include/spdlog/details/logger_impl.h | 441 | ||||
-rw-r--r-- | matching/include/spdlog/details/mpmc_blocking_q.h | 121 | ||||
-rw-r--r-- | matching/include/spdlog/details/null_mutex.h | 45 | ||||
-rw-r--r-- | matching/include/spdlog/details/os.h | 421 | ||||
-rw-r--r-- | matching/include/spdlog/details/pattern_formatter.h | 1336 | ||||
-rw-r--r-- | matching/include/spdlog/details/periodic_worker.h | 71 | ||||
-rw-r--r-- | matching/include/spdlog/details/registry.h | 285 | ||||
-rw-r--r-- | matching/include/spdlog/details/thread_pool.h | 238 | ||||
-rw-r--r-- | matching/include/spdlog/fmt/bin_to_hex.h | 172 | ||||
-rw-r--r-- | matching/include/spdlog/fmt/bundled/LICENSE.rst | 23 | ||||
-rw-r--r-- | matching/include/spdlog/fmt/bundled/chrono.h | 452 | ||||
-rw-r--r-- | matching/include/spdlog/fmt/bundled/color.h | 577 | ||||
-rw-r--r-- | matching/include/spdlog/fmt/bundled/core.h | 1502 | ||||
-rw-r--r-- | matching/include/spdlog/fmt/bundled/format-inl.h | 972 | ||||
-rw-r--r-- | matching/include/spdlog/fmt/bundled/format.h | 3555 | ||||
-rw-r--r-- | matching/include/spdlog/fmt/bundled/locale.h | 77 | ||||
-rw-r--r-- | matching/include/spdlog/fmt/bundled/ostream.h | 153 | ||||
-rw-r--r-- | matching/include/spdlog/fmt/bundled/posix.h | 324 | ||||
-rw-r--r-- | matching/include/spdlog/fmt/bundled/printf.h | 855 | ||||
-rw-r--r-- | matching/include/spdlog/fmt/bundled/ranges.h | 308 | ||||
-rw-r--r-- | matching/include/spdlog/fmt/bundled/time.h | 160 | ||||
-rw-r--r-- | matching/include/spdlog/fmt/fmt.h | 25 | ||||
-rw-r--r-- | matching/include/spdlog/fmt/ostr.h | 18 | ||||
-rw-r--r-- | matching/include/spdlog/formatter.h | 20 | ||||
-rw-r--r-- | matching/include/spdlog/logger.h | 188 | ||||
-rw-r--r-- | matching/include/spdlog/sinks/android_sink.h | 121 | ||||
-rw-r--r-- | matching/include/spdlog/sinks/ansicolor_sink.h | 161 | ||||
-rw-r--r-- | matching/include/spdlog/sinks/base_sink.h | 69 | ||||
-rw-r--r-- | matching/include/spdlog/sinks/basic_file_sink.h | 75 | ||||
-rw-r--r-- | matching/include/spdlog/sinks/daily_file_sink.h | 141 | ||||
-rw-r--r-- | matching/include/spdlog/sinks/dist_sink.h | 94 | ||||
-rw-r--r-- | matching/include/spdlog/sinks/msvc_sink.h | 54 | ||||
-rw-r--r-- | matching/include/spdlog/sinks/null_sink.h | 49 | ||||
-rw-r--r-- | matching/include/spdlog/sinks/ostream_sink.h | 57 | ||||
-rw-r--r-- | matching/include/spdlog/sinks/rotating_file_sink.h | 164 | ||||
-rw-r--r-- | matching/include/spdlog/sinks/sink.h | 59 | ||||
-rw-r--r-- | matching/include/spdlog/sinks/stdout_color_sinks.h | 56 | ||||
-rw-r--r-- | matching/include/spdlog/sinks/stdout_sinks.h | 102 | ||||
-rw-r--r-- | matching/include/spdlog/sinks/syslog_sink.h | 94 | ||||
-rw-r--r-- | matching/include/spdlog/sinks/wincolor_sink.h | 143 | ||||
-rw-r--r-- | matching/include/spdlog/spdlog.h | 366 | ||||
-rw-r--r-- | matching/include/spdlog/tweakme.h | 145 | ||||
-rw-r--r-- | matching/include/spdlog/version.h | 12 | ||||
-rw-r--r-- | matching/tests/prism_1.bif | 28 | ||||
-rw-r--r-- | matching/tests/prism_2.bif | 29 | ||||
-rw-r--r-- | matching/tests/test_bifiltration.cpp | 36 | ||||
l--------- | matching/tests/test_bifiltration_1.txt | 1 | ||||
l--------- | matching/tests/test_bifiltration_full_triangle_rene.txt | 1 | ||||
-rw-r--r-- | matching/tests/test_common.cpp | 156 | ||||
-rw-r--r-- | matching/tests/test_list.txt | 1 | ||||
-rw-r--r-- | matching/tests/test_matching_distance.cpp | 168 | ||||
-rw-r--r-- | matching/tests/test_module.cpp | 114 | ||||
-rw-r--r-- | matching/tests/tests_main.cpp | 2 | ||||
-rw-r--r-- | wasserstein/CMakeLists.txt (renamed from geom_matching/wasserstein/CMakeLists.txt) | 0 | ||||
-rw-r--r-- | wasserstein/README (renamed from geom_matching/README) | 0 | ||||
-rw-r--r-- | wasserstein/example/wasserstein_dist.cpp (renamed from geom_matching/wasserstein/example/wasserstein_dist.cpp) | 0 | ||||
-rw-r--r-- | wasserstein/example/wasserstein_dist_dipha.cpp (renamed from geom_matching/wasserstein/example/wasserstein_dist_dipha.cpp) | 0 | ||||
-rw-r--r-- | wasserstein/example/wasserstein_dist_point_cloud.cpp (renamed from geom_matching/wasserstein/example/wasserstein_dist_point_cloud.cpp) | 0 | ||||
-rw-r--r-- | wasserstein/include/auction_oracle.h (renamed from geom_matching/wasserstein/include/auction_oracle.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/auction_oracle_base.h (renamed from geom_matching/wasserstein/include/auction_oracle_base.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/auction_oracle_base.hpp (renamed from geom_matching/wasserstein/include/auction_oracle_base.hpp) | 0 | ||||
-rw-r--r-- | wasserstein/include/auction_oracle_kdtree_pure_geom.h (renamed from geom_matching/wasserstein/include/auction_oracle_kdtree_pure_geom.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/auction_oracle_kdtree_pure_geom.hpp (renamed from geom_matching/wasserstein/include/auction_oracle_kdtree_pure_geom.hpp) | 0 | ||||
-rw-r--r-- | wasserstein/include/auction_oracle_kdtree_restricted.h (renamed from geom_matching/wasserstein/include/auction_oracle_kdtree_restricted.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/auction_oracle_kdtree_restricted.hpp (renamed from geom_matching/wasserstein/include/auction_oracle_kdtree_restricted.hpp) | 0 | ||||
-rw-r--r-- | wasserstein/include/auction_oracle_kdtree_single_diag.h (renamed from geom_matching/wasserstein/include/auction_oracle_kdtree_single_diag.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/auction_oracle_kdtree_single_diag.hpp (renamed from geom_matching/wasserstein/include/auction_oracle_kdtree_single_diag.hpp) | 0 | ||||
-rw-r--r-- | wasserstein/include/auction_oracle_lazy_heap.h (renamed from geom_matching/wasserstein/include/auction_oracle_lazy_heap.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/auction_oracle_lazy_heap.hpp (renamed from geom_matching/wasserstein/include/auction_oracle_lazy_heap.hpp) | 0 | ||||
-rw-r--r-- | wasserstein/include/auction_oracle_stupid_sparse_restricted.h (renamed from geom_matching/wasserstein/include/auction_oracle_stupid_sparse_restricted.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/auction_oracle_stupid_sparse_restricted.hpp (renamed from geom_matching/wasserstein/include/auction_oracle_stupid_sparse_restricted.hpp) | 0 | ||||
-rw-r--r-- | wasserstein/include/auction_runner_fr.h (renamed from geom_matching/wasserstein/include/auction_runner_fr.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/auction_runner_fr.hpp (renamed from geom_matching/wasserstein/include/auction_runner_fr.hpp) | 0 | ||||
-rw-r--r-- | wasserstein/include/auction_runner_gs.h (renamed from geom_matching/wasserstein/include/auction_runner_gs.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/auction_runner_gs.hpp (renamed from geom_matching/wasserstein/include/auction_runner_gs.hpp) | 0 | ||||
-rw-r--r-- | wasserstein/include/auction_runner_gs_single_diag.h (renamed from geom_matching/wasserstein/include/auction_runner_gs_single_diag.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/auction_runner_gs_single_diag.hpp (renamed from geom_matching/wasserstein/include/auction_runner_gs_single_diag.hpp) | 0 | ||||
-rw-r--r-- | wasserstein/include/auction_runner_jac.h (renamed from geom_matching/wasserstein/include/auction_runner_jac.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/auction_runner_jac.hpp (renamed from geom_matching/wasserstein/include/auction_runner_jac.hpp) | 0 | ||||
-rw-r--r-- | wasserstein/include/basic_defs_ws.h (renamed from geom_matching/wasserstein/include/basic_defs_ws.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/basic_defs_ws.hpp (renamed from geom_matching/wasserstein/include/basic_defs_ws.hpp) | 0 | ||||
-rw-r--r-- | wasserstein/include/catch/catch.hpp (renamed from geom_matching/wasserstein/include/catch/catch.hpp) | 0 | ||||
-rw-r--r-- | wasserstein/include/def_debug_ws.h (renamed from geom_matching/wasserstein/include/def_debug_ws.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/diagonal_heap.h (renamed from geom_matching/wasserstein/include/diagonal_heap.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/diagram_reader.h (renamed from geom_matching/wasserstein/include/diagram_reader.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/dnn/geometry/euclidean-dynamic.h (renamed from geom_matching/wasserstein/include/dnn/geometry/euclidean-dynamic.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/dnn/geometry/euclidean-fixed.h (renamed from geom_matching/wasserstein/include/dnn/geometry/euclidean-fixed.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/dnn/local/kd-tree.h (renamed from geom_matching/wasserstein/include/dnn/local/kd-tree.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/dnn/local/kd-tree.hpp (renamed from geom_matching/wasserstein/include/dnn/local/kd-tree.hpp) | 0 | ||||
-rw-r--r-- | wasserstein/include/dnn/local/search-functors.h (renamed from geom_matching/wasserstein/include/dnn/local/search-functors.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/dnn/parallel/tbb.h (renamed from geom_matching/wasserstein/include/dnn/parallel/tbb.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/dnn/parallel/utils.h (renamed from geom_matching/wasserstein/include/dnn/parallel/utils.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/dnn/utils.h (renamed from geom_matching/wasserstein/include/dnn/utils.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/hera_infinity.h (renamed from geom_matching/wasserstein/include/hera_infinity.h) | 0 | ||||
-rwxr-xr-x | wasserstein/include/opts/opts.h (renamed from geom_matching/wasserstein/include/opts/opts.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/async_logger.h (renamed from geom_matching/wasserstein/include/spdlog/async_logger.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/common.h (renamed from geom_matching/wasserstein/include/spdlog/common.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/details/async_log_helper.h (renamed from geom_matching/wasserstein/include/spdlog/details/async_log_helper.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/details/async_logger_impl.h (renamed from geom_matching/wasserstein/include/spdlog/details/async_logger_impl.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/details/file_helper.h (renamed from geom_matching/wasserstein/include/spdlog/details/file_helper.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/details/log_msg.h (renamed from geom_matching/wasserstein/include/spdlog/details/log_msg.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/details/logger_impl.h (renamed from geom_matching/wasserstein/include/spdlog/details/logger_impl.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/details/mpmc_bounded_q.h (renamed from geom_matching/wasserstein/include/spdlog/details/mpmc_bounded_q.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/details/null_mutex.h (renamed from geom_matching/wasserstein/include/spdlog/details/null_mutex.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/details/os.h (renamed from geom_matching/wasserstein/include/spdlog/details/os.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/details/pattern_formatter_impl.h (renamed from geom_matching/wasserstein/include/spdlog/details/pattern_formatter_impl.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/details/registry.h (renamed from geom_matching/wasserstein/include/spdlog/details/registry.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/details/spdlog_impl.h (renamed from geom_matching/wasserstein/include/spdlog/details/spdlog_impl.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/fmt/bundled/format.cc (renamed from geom_matching/wasserstein/include/spdlog/fmt/bundled/format.cc) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/fmt/bundled/format.h (renamed from geom_matching/wasserstein/include/spdlog/fmt/bundled/format.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/fmt/bundled/ostream.cc (renamed from geom_matching/wasserstein/include/spdlog/fmt/bundled/ostream.cc) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/fmt/bundled/ostream.h (renamed from geom_matching/wasserstein/include/spdlog/fmt/bundled/ostream.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/fmt/bundled/posix.cc (renamed from geom_matching/wasserstein/include/spdlog/fmt/bundled/posix.cc) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/fmt/bundled/posix.h (renamed from geom_matching/wasserstein/include/spdlog/fmt/bundled/posix.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/fmt/bundled/time.h (renamed from geom_matching/wasserstein/include/spdlog/fmt/bundled/time.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/fmt/fmt.h (renamed from geom_matching/wasserstein/include/spdlog/fmt/fmt.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/fmt/ostr.h (renamed from geom_matching/wasserstein/include/spdlog/fmt/ostr.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/formatter.h (renamed from geom_matching/wasserstein/include/spdlog/formatter.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/logger.h (renamed from geom_matching/wasserstein/include/spdlog/logger.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/sinks/android_sink.h (renamed from geom_matching/wasserstein/include/spdlog/sinks/android_sink.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/sinks/ansicolor_sink.h (renamed from geom_matching/wasserstein/include/spdlog/sinks/ansicolor_sink.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/sinks/base_sink.h (renamed from geom_matching/wasserstein/include/spdlog/sinks/base_sink.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/sinks/dist_sink.h (renamed from geom_matching/wasserstein/include/spdlog/sinks/dist_sink.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/sinks/file_sinks.h (renamed from geom_matching/wasserstein/include/spdlog/sinks/file_sinks.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/sinks/msvc_sink.h (renamed from geom_matching/wasserstein/include/spdlog/sinks/msvc_sink.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/sinks/null_sink.h (renamed from geom_matching/wasserstein/include/spdlog/sinks/null_sink.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/sinks/ostream_sink.h (renamed from geom_matching/wasserstein/include/spdlog/sinks/ostream_sink.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/sinks/sink.h (renamed from geom_matching/wasserstein/include/spdlog/sinks/sink.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/sinks/stdout_sinks.h (renamed from geom_matching/wasserstein/include/spdlog/sinks/stdout_sinks.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/sinks/syslog_sink.h (renamed from geom_matching/wasserstein/include/spdlog/sinks/syslog_sink.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/sinks/wincolor_sink.h (renamed from geom_matching/wasserstein/include/spdlog/sinks/wincolor_sink.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/spdlog.h (renamed from geom_matching/wasserstein/include/spdlog/spdlog.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/spdlog/tweakme.h (renamed from geom_matching/wasserstein/include/spdlog/tweakme.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/wasserstein.h (renamed from geom_matching/wasserstein/include/wasserstein.h) | 0 | ||||
-rw-r--r-- | wasserstein/include/wasserstein_pure_geom.hpp (renamed from geom_matching/wasserstein/include/wasserstein_pure_geom.hpp) | 0 | ||||
-rw-r--r-- | wasserstein/tests/data/test_100_A (renamed from geom_matching/wasserstein/tests/data/test_100_A) | 0 | ||||
-rw-r--r-- | wasserstein/tests/data/test_100_A.pd.dipha (renamed from geom_matching/wasserstein/tests/data/test_100_A.pd.dipha) | bin | 2424 -> 2424 bytes | |||
-rw-r--r-- | wasserstein/tests/data/test_100_B (renamed from geom_matching/wasserstein/tests/data/test_100_B) | 0 | ||||
-rw-r--r-- | wasserstein/tests/data/test_100_B.pd.dipha (renamed from geom_matching/wasserstein/tests/data/test_100_B.pd.dipha) | bin | 2424 -> 2424 bytes | |||
-rw-r--r-- | wasserstein/tests/data/test_200_A (renamed from geom_matching/wasserstein/tests/data/test_200_A) | 0 | ||||
-rw-r--r-- | wasserstein/tests/data/test_200_B (renamed from geom_matching/wasserstein/tests/data/test_200_B) | 0 | ||||
-rw-r--r-- | wasserstein/tests/data/test_5000_A (renamed from geom_matching/wasserstein/tests/data/test_5000_A) | 0 | ||||
-rw-r--r-- | wasserstein/tests/data/test_5000_B (renamed from geom_matching/wasserstein/tests/data/test_5000_B) | 0 | ||||
-rw-r--r-- | wasserstein/tests/data/test_5_A (renamed from geom_matching/wasserstein/tests/data/test_5_A) | 0 | ||||
-rw-r--r-- | wasserstein/tests/data/test_5_A.pd.dipha (renamed from geom_matching/wasserstein/tests/data/test_5_A.pd.dipha) | bin | 144 -> 144 bytes | |||
-rw-r--r-- | wasserstein/tests/data/test_5_B (renamed from geom_matching/wasserstein/tests/data/test_5_B) | 0 | ||||
-rw-r--r-- | wasserstein/tests/data/test_5_B.pd.dipha (renamed from geom_matching/wasserstein/tests/data/test_5_B.pd.dipha) | bin | 144 -> 144 bytes | |||
-rw-r--r-- | wasserstein/tests/data/test_diag1_A (renamed from geom_matching/wasserstein/tests/data/test_diag1_A) | 0 | ||||
-rw-r--r-- | wasserstein/tests/data/test_diag1_A.pd.dipha (renamed from geom_matching/wasserstein/tests/data/test_diag1_A.pd.dipha) | bin | 48 -> 48 bytes | |||
-rw-r--r-- | wasserstein/tests/data/test_diag1_B (renamed from geom_matching/wasserstein/tests/data/test_diag1_B) | 0 | ||||
-rw-r--r-- | wasserstein/tests/data/test_diag1_B.pd.dipha (renamed from geom_matching/wasserstein/tests/data/test_diag1_B.pd.dipha) | bin | 48 -> 48 bytes | |||
-rw-r--r-- | wasserstein/tests/data/test_diag2_A (renamed from geom_matching/wasserstein/tests/data/test_diag2_A) | 0 | ||||
-rw-r--r-- | wasserstein/tests/data/test_diag2_A.pd.dipha (renamed from geom_matching/wasserstein/tests/data/test_diag2_A.pd.dipha) | bin | 48 -> 48 bytes | |||
-rw-r--r-- | wasserstein/tests/data/test_diag2_B (renamed from geom_matching/wasserstein/tests/data/test_diag2_B) | 0 | ||||
-rw-r--r-- | wasserstein/tests/data/test_diag2_B.pd.dipha (renamed from geom_matching/wasserstein/tests/data/test_diag2_B.pd.dipha) | bin | 48 -> 48 bytes | |||
-rw-r--r-- | wasserstein/tests/data/test_diag3_A (renamed from geom_matching/wasserstein/tests/data/test_diag3_A) | 0 | ||||
-rw-r--r-- | wasserstein/tests/data/test_diag3_A.pd.dipha (renamed from geom_matching/wasserstein/tests/data/test_diag3_A.pd.dipha) | bin | 5304 -> 5304 bytes | |||
-rw-r--r-- | wasserstein/tests/data/test_diag3_B (renamed from geom_matching/wasserstein/tests/data/test_diag3_B) | 0 | ||||
-rw-r--r-- | wasserstein/tests/data/test_diag3_B.pd.dipha (renamed from geom_matching/wasserstein/tests/data/test_diag3_B.pd.dipha) | bin | 4656 -> 4656 bytes | |||
-rw-r--r-- | wasserstein/tests/data/test_list.txt (renamed from geom_matching/wasserstein/tests/data/test_list.txt) | 0 | ||||
-rw-r--r-- | wasserstein/tests/test_hera_wasserstein.cpp (renamed from geom_matching/wasserstein/tests/test_hera_wasserstein.cpp) | 0 | ||||
-rw-r--r-- | wasserstein/tests/test_hera_wasserstein_pure_geom.cpp (renamed from geom_matching/wasserstein/tests/test_hera_wasserstein_pure_geom.cpp) | 0 | ||||
-rw-r--r-- | wasserstein/tests/tests_main.cpp (renamed from geom_matching/wasserstein/tests/tests_main.cpp) | 0 | ||||
-rw-r--r-- | wasserstein/tests/tests_reader.h (renamed from geom_matching/wasserstein/tests/tests_reader.h) | 0 |
1864 files changed, 36294 insertions, 36 deletions
diff --git a/geom_bottleneck/.gitignore b/.gitignore index 3d0a40b..8d53708 100644 --- a/geom_bottleneck/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /*.cfg /build +build/ *.gitattributes *.opensdf *.sdf @@ -1,5 +1,6 @@ This repository contains software to compute bottleneck and Wasserstein -distances between persistence diagrams. +distances between persistence diagrams, and matching distance +between 2-parameter persistence modules and (1-critical) bi-filtrations. The software is licensed under BSD license, see license.txt file. @@ -9,13 +10,14 @@ you probably do not need to worry about that. See README files in subdirectories for usage and building. If you use Hera in your project, we would appreciate if you -cite the corresponding paper: +cite the corresponding paper. + +Bottleneck or Wasserstein distance: + Michael Kerber, Dmitriy Morozov, and Arnur Nigmetov, "Geometry Helps to Compare Persistence Diagrams.", Journal of Experimental Algorithmics, vol. 22, 2017, pp. 1--20. (conference version: ALENEX 2016). -The BibTeX is below: - @article{jea_hera, title={Geometry helps to compare persistence diagrams}, @@ -26,3 +28,8 @@ The BibTeX is below: year={2017}, publisher={ACM New York, NY, USA} } + +Matching distance: + +Michael Kerber, Arnur Nigmetov, "Efficient Approximation of the Matching +Distance for 2-parameter persistence.", SoCG 2020 diff --git a/geom_bottleneck/CMakeLists.txt b/bottleneck/CMakeLists.txt index 7a820ac..7a820ac 100644 --- a/geom_bottleneck/CMakeLists.txt +++ b/bottleneck/CMakeLists.txt diff --git a/geom_bottleneck/README b/bottleneck/README index 8b368af..c04390b 100644 --- a/geom_bottleneck/README +++ b/bottleneck/README @@ -1,6 +1,6 @@ Accompanying paper: M. Kerber, D. Morozov, A. Nigmetov. Geometry Helps To Compare Persistence Diagrams (ALENEX 2016, http://www.geometrie.tugraz.at/nigmetov/geom_dist.pdf) -Bug reports can be sent to "nigmetov EMAIL SIGN tugraz DOT at". +Bug reports can be sent to "anigmetov EMAIL SIGN lbl DOT gov". # Dependencies diff --git a/geom_bottleneck/example/CMakeLists.txt b/bottleneck/example/CMakeLists.txt index 3ae8536..3ae8536 100644 --- a/geom_bottleneck/example/CMakeLists.txt +++ b/bottleneck/example/CMakeLists.txt diff --git a/geom_bottleneck/example/bottleneck_dist.cpp b/bottleneck/example/bottleneck_dist.cpp index 8966789..8966789 100644 --- a/geom_bottleneck/example/bottleneck_dist.cpp +++ b/bottleneck/example/bottleneck_dist.cpp diff --git a/geom_bottleneck/include/basic_defs_bt.h b/bottleneck/include/basic_defs_bt.h index 172e0f7..172e0f7 100644 --- a/geom_bottleneck/include/basic_defs_bt.h +++ b/bottleneck/include/basic_defs_bt.h diff --git a/geom_bottleneck/include/bottleneck.h b/bottleneck/include/bottleneck.h index 64da2c8..64da2c8 100644 --- a/geom_bottleneck/include/bottleneck.h +++ b/bottleneck/include/bottleneck.h diff --git a/geom_bottleneck/include/bottleneck_detail.h b/bottleneck/include/bottleneck_detail.h index 7241c9a..7241c9a 100644 --- a/geom_bottleneck/include/bottleneck_detail.h +++ b/bottleneck/include/bottleneck_detail.h diff --git a/geom_bottleneck/include/bottleneck_detail.hpp b/bottleneck/include/bottleneck_detail.hpp index 8f51d07..8f51d07 100644 --- a/geom_bottleneck/include/bottleneck_detail.hpp +++ b/bottleneck/include/bottleneck_detail.hpp diff --git a/geom_bottleneck/include/bound_match.h b/bottleneck/include/bound_match.h index 99543f9..99543f9 100644 --- a/geom_bottleneck/include/bound_match.h +++ b/bottleneck/include/bound_match.h diff --git a/geom_bottleneck/include/bound_match.hpp b/bottleneck/include/bound_match.hpp index b95628f..b95628f 100644 --- a/geom_bottleneck/include/bound_match.hpp +++ b/bottleneck/include/bound_match.hpp diff --git a/geom_bottleneck/include/catch/catch.hpp b/bottleneck/include/catch/catch.hpp index f7681f4..f7681f4 100644 --- a/geom_bottleneck/include/catch/catch.hpp +++ b/bottleneck/include/catch/catch.hpp diff --git a/geom_bottleneck/include/def_debug_bt.h b/bottleneck/include/def_debug_bt.h index 21557e7..21557e7 100644 --- a/geom_bottleneck/include/def_debug_bt.h +++ b/bottleneck/include/def_debug_bt.h diff --git a/geom_bottleneck/include/diagram_reader.h b/bottleneck/include/diagram_reader.h index 08d9e2b..08d9e2b 100644 --- a/geom_bottleneck/include/diagram_reader.h +++ b/bottleneck/include/diagram_reader.h diff --git a/geom_bottleneck/include/diagram_traits.h b/bottleneck/include/diagram_traits.h index c8d4862..c8d4862 100644 --- a/geom_bottleneck/include/diagram_traits.h +++ b/bottleneck/include/diagram_traits.h diff --git a/geom_bottleneck/include/dnn/geometry/euclidean-fixed.h b/bottleneck/include/dnn/geometry/euclidean-fixed.h index f45b980..f45b980 100644 --- a/geom_bottleneck/include/dnn/geometry/euclidean-fixed.h +++ b/bottleneck/include/dnn/geometry/euclidean-fixed.h diff --git a/geom_bottleneck/include/dnn/local/kd-tree.h b/bottleneck/include/dnn/local/kd-tree.h index c1aed2b..c1aed2b 100644 --- a/geom_bottleneck/include/dnn/local/kd-tree.h +++ b/bottleneck/include/dnn/local/kd-tree.h diff --git a/geom_bottleneck/include/dnn/local/kd-tree.hpp b/bottleneck/include/dnn/local/kd-tree.hpp index 5b84eb0..5b84eb0 100644 --- a/geom_bottleneck/include/dnn/local/kd-tree.hpp +++ b/bottleneck/include/dnn/local/kd-tree.hpp diff --git a/geom_bottleneck/include/dnn/local/search-functors.h b/bottleneck/include/dnn/local/search-functors.h index 63ad11d..63ad11d 100644 --- a/geom_bottleneck/include/dnn/local/search-functors.h +++ b/bottleneck/include/dnn/local/search-functors.h diff --git a/geom_bottleneck/include/dnn/parallel/tbb.h b/bottleneck/include/dnn/parallel/tbb.h index 1462a9c..1462a9c 100644 --- a/geom_bottleneck/include/dnn/parallel/tbb.h +++ b/bottleneck/include/dnn/parallel/tbb.h diff --git a/geom_bottleneck/include/dnn/parallel/utils.h b/bottleneck/include/dnn/parallel/utils.h index 9809e77..9809e77 100644 --- a/geom_bottleneck/include/dnn/parallel/utils.h +++ b/bottleneck/include/dnn/parallel/utils.h diff --git a/geom_bottleneck/include/dnn/utils.h b/bottleneck/include/dnn/utils.h index f4ce632..f4ce632 100644 --- a/geom_bottleneck/include/dnn/utils.h +++ b/bottleneck/include/dnn/utils.h diff --git a/geom_bottleneck/include/neighb_oracle.h b/bottleneck/include/neighb_oracle.h index 91ebc0e..91ebc0e 100644 --- a/geom_bottleneck/include/neighb_oracle.h +++ b/bottleneck/include/neighb_oracle.h diff --git a/geom_bottleneck/tests/data/test_001_A b/bottleneck/tests/data/test_001_A index 8d04f96..8d04f96 100644 --- a/geom_bottleneck/tests/data/test_001_A +++ b/bottleneck/tests/data/test_001_A diff --git a/geom_bottleneck/tests/data/test_001_B b/bottleneck/tests/data/test_001_B index 9290688..9290688 100644 --- a/geom_bottleneck/tests/data/test_001_B +++ b/bottleneck/tests/data/test_001_B diff --git a/geom_bottleneck/tests/data/test_002_A b/bottleneck/tests/data/test_002_A index 8d04f96..8d04f96 100644 --- a/geom_bottleneck/tests/data/test_002_A +++ b/bottleneck/tests/data/test_002_A diff --git a/geom_bottleneck/tests/data/test_002_B b/bottleneck/tests/data/test_002_B index a4cec9b..a4cec9b 100644 --- a/geom_bottleneck/tests/data/test_002_B +++ b/bottleneck/tests/data/test_002_B diff --git a/geom_bottleneck/tests/data/test_003_A b/bottleneck/tests/data/test_003_A index fdf0acd..fdf0acd 100644 --- a/geom_bottleneck/tests/data/test_003_A +++ b/bottleneck/tests/data/test_003_A diff --git a/geom_bottleneck/tests/data/test_003_B b/bottleneck/tests/data/test_003_B index ac429f9..ac429f9 100644 --- a/geom_bottleneck/tests/data/test_003_B +++ b/bottleneck/tests/data/test_003_B diff --git a/geom_bottleneck/tests/data/test_004_A b/bottleneck/tests/data/test_004_A index fdf0acd..fdf0acd 100644 --- a/geom_bottleneck/tests/data/test_004_A +++ b/bottleneck/tests/data/test_004_A diff --git a/geom_bottleneck/tests/data/test_004_B b/bottleneck/tests/data/test_004_B index 5769823..5769823 100644 --- a/geom_bottleneck/tests/data/test_004_B +++ b/bottleneck/tests/data/test_004_B diff --git a/geom_bottleneck/tests/data/test_005_A b/bottleneck/tests/data/test_005_A index e28367d..e28367d 100644 --- a/geom_bottleneck/tests/data/test_005_A +++ b/bottleneck/tests/data/test_005_A diff --git a/geom_bottleneck/tests/data/test_005_B b/bottleneck/tests/data/test_005_B index 7f6032b..7f6032b 100644 --- a/geom_bottleneck/tests/data/test_005_B +++ b/bottleneck/tests/data/test_005_B diff --git a/geom_bottleneck/tests/data/test_006_A b/bottleneck/tests/data/test_006_A index b5184a5..b5184a5 100644 --- a/geom_bottleneck/tests/data/test_006_A +++ b/bottleneck/tests/data/test_006_A diff --git a/geom_bottleneck/tests/data/test_006_B b/bottleneck/tests/data/test_006_B index 0d07369..0d07369 100644 --- a/geom_bottleneck/tests/data/test_006_B +++ b/bottleneck/tests/data/test_006_B diff --git a/geom_bottleneck/tests/data/test_007_A b/bottleneck/tests/data/test_007_A index e69de29..e69de29 100644 --- a/geom_bottleneck/tests/data/test_007_A +++ b/bottleneck/tests/data/test_007_A diff --git a/geom_bottleneck/tests/data/test_007_B b/bottleneck/tests/data/test_007_B index e69de29..e69de29 100644 --- a/geom_bottleneck/tests/data/test_007_B +++ b/bottleneck/tests/data/test_007_B diff --git a/geom_bottleneck/tests/data/test_008_A b/bottleneck/tests/data/test_008_A index 50b3df6..50b3df6 100644 --- a/geom_bottleneck/tests/data/test_008_A +++ b/bottleneck/tests/data/test_008_A diff --git a/geom_bottleneck/tests/data/test_008_B b/bottleneck/tests/data/test_008_B index 1935b11..1935b11 100644 --- a/geom_bottleneck/tests/data/test_008_B +++ b/bottleneck/tests/data/test_008_B diff --git a/geom_bottleneck/tests/data/test_009_A b/bottleneck/tests/data/test_009_A index a1b859e..a1b859e 100644 --- a/geom_bottleneck/tests/data/test_009_A +++ b/bottleneck/tests/data/test_009_A diff --git a/geom_bottleneck/tests/data/test_009_B b/bottleneck/tests/data/test_009_B index b5befbc..b5befbc 100644 --- a/geom_bottleneck/tests/data/test_009_B +++ b/bottleneck/tests/data/test_009_B diff --git a/geom_bottleneck/tests/data/test_010_A b/bottleneck/tests/data/test_010_A index 8d126f0..8d126f0 100644 --- a/geom_bottleneck/tests/data/test_010_A +++ b/bottleneck/tests/data/test_010_A diff --git a/geom_bottleneck/tests/data/test_010_B b/bottleneck/tests/data/test_010_B index 852799d..852799d 100644 --- a/geom_bottleneck/tests/data/test_010_B +++ b/bottleneck/tests/data/test_010_B diff --git a/geom_bottleneck/tests/data/test_011_A b/bottleneck/tests/data/test_011_A index 164b71d..164b71d 100644 --- a/geom_bottleneck/tests/data/test_011_A +++ b/bottleneck/tests/data/test_011_A diff --git a/geom_bottleneck/tests/data/test_011_B b/bottleneck/tests/data/test_011_B index 761943d..761943d 100644 --- a/geom_bottleneck/tests/data/test_011_B +++ b/bottleneck/tests/data/test_011_B diff --git a/geom_bottleneck/tests/data/test_012_A b/bottleneck/tests/data/test_012_A index 094c6e0..094c6e0 100644 --- a/geom_bottleneck/tests/data/test_012_A +++ b/bottleneck/tests/data/test_012_A diff --git a/geom_bottleneck/tests/data/test_012_B b/bottleneck/tests/data/test_012_B index 5f6e43c..5f6e43c 100644 --- a/geom_bottleneck/tests/data/test_012_B +++ b/bottleneck/tests/data/test_012_B diff --git a/geom_bottleneck/tests/data/test_013_A b/bottleneck/tests/data/test_013_A index 51cff1c..51cff1c 100644 --- a/geom_bottleneck/tests/data/test_013_A +++ b/bottleneck/tests/data/test_013_A diff --git a/geom_bottleneck/tests/data/test_013_B b/bottleneck/tests/data/test_013_B index be62ed3..be62ed3 100644 --- a/geom_bottleneck/tests/data/test_013_B +++ b/bottleneck/tests/data/test_013_B diff --git a/geom_bottleneck/tests/data/test_014_A b/bottleneck/tests/data/test_014_A index f7f90ff..f7f90ff 100644 --- a/geom_bottleneck/tests/data/test_014_A +++ b/bottleneck/tests/data/test_014_A diff --git a/geom_bottleneck/tests/data/test_014_B b/bottleneck/tests/data/test_014_B index a167a4f..a167a4f 100644 --- a/geom_bottleneck/tests/data/test_014_B +++ b/bottleneck/tests/data/test_014_B diff --git a/geom_bottleneck/tests/data/test_015_A b/bottleneck/tests/data/test_015_A index a167a4f..a167a4f 100644 --- a/geom_bottleneck/tests/data/test_015_A +++ b/bottleneck/tests/data/test_015_A diff --git a/geom_bottleneck/tests/data/test_015_B b/bottleneck/tests/data/test_015_B index a167a4f..a167a4f 100644 --- a/geom_bottleneck/tests/data/test_015_B +++ b/bottleneck/tests/data/test_015_B diff --git a/geom_bottleneck/tests/data/test_016_A b/bottleneck/tests/data/test_016_A index 151d4b1..151d4b1 100644 --- a/geom_bottleneck/tests/data/test_016_A +++ b/bottleneck/tests/data/test_016_A diff --git a/geom_bottleneck/tests/data/test_016_B b/bottleneck/tests/data/test_016_B index bb8655a..bb8655a 100644 --- a/geom_bottleneck/tests/data/test_016_B +++ b/bottleneck/tests/data/test_016_B diff --git a/geom_bottleneck/tests/data/test_100_A b/bottleneck/tests/data/test_100_A index e02a950..e02a950 100644 --- a/geom_bottleneck/tests/data/test_100_A +++ b/bottleneck/tests/data/test_100_A diff --git a/geom_bottleneck/tests/data/test_100_B b/bottleneck/tests/data/test_100_B index f757173..f757173 100644 --- a/geom_bottleneck/tests/data/test_100_B +++ b/bottleneck/tests/data/test_100_B diff --git a/geom_bottleneck/tests/data/test_101_A b/bottleneck/tests/data/test_101_A index 5fe22b1..5fe22b1 100644 --- a/geom_bottleneck/tests/data/test_101_A +++ b/bottleneck/tests/data/test_101_A diff --git a/geom_bottleneck/tests/data/test_101_B b/bottleneck/tests/data/test_101_B index ea19ef6..ea19ef6 100644 --- a/geom_bottleneck/tests/data/test_101_B +++ b/bottleneck/tests/data/test_101_B diff --git a/geom_bottleneck/tests/data/test_102_A b/bottleneck/tests/data/test_102_A index 1cd65e9..1cd65e9 100644 --- a/geom_bottleneck/tests/data/test_102_A +++ b/bottleneck/tests/data/test_102_A diff --git a/geom_bottleneck/tests/data/test_102_B b/bottleneck/tests/data/test_102_B index 3ffa9cb..3ffa9cb 100644 --- a/geom_bottleneck/tests/data/test_102_B +++ b/bottleneck/tests/data/test_102_B diff --git a/geom_bottleneck/tests/data/test_103_A b/bottleneck/tests/data/test_103_A index d4c86c9..d4c86c9 100644 --- a/geom_bottleneck/tests/data/test_103_A +++ b/bottleneck/tests/data/test_103_A diff --git a/geom_bottleneck/tests/data/test_103_B b/bottleneck/tests/data/test_103_B index c9a898a..c9a898a 100644 --- a/geom_bottleneck/tests/data/test_103_B +++ b/bottleneck/tests/data/test_103_B diff --git a/geom_bottleneck/tests/data/test_104_A b/bottleneck/tests/data/test_104_A index 373ae44..373ae44 100644 --- a/geom_bottleneck/tests/data/test_104_A +++ b/bottleneck/tests/data/test_104_A diff --git a/geom_bottleneck/tests/data/test_104_B b/bottleneck/tests/data/test_104_B index e382a3b..e382a3b 100644 --- a/geom_bottleneck/tests/data/test_104_B +++ b/bottleneck/tests/data/test_104_B diff --git a/geom_bottleneck/tests/data/test_105_A b/bottleneck/tests/data/test_105_A index 21b1cc4..21b1cc4 100644 --- a/geom_bottleneck/tests/data/test_105_A +++ b/bottleneck/tests/data/test_105_A diff --git a/geom_bottleneck/tests/data/test_105_B b/bottleneck/tests/data/test_105_B index 3ab6543..3ab6543 100644 --- a/geom_bottleneck/tests/data/test_105_B +++ b/bottleneck/tests/data/test_105_B diff --git a/geom_bottleneck/tests/data/test_106_A b/bottleneck/tests/data/test_106_A index 8d3ffb8..8d3ffb8 100644 --- a/geom_bottleneck/tests/data/test_106_A +++ b/bottleneck/tests/data/test_106_A diff --git a/geom_bottleneck/tests/data/test_106_B b/bottleneck/tests/data/test_106_B index 760ada5..760ada5 100644 --- a/geom_bottleneck/tests/data/test_106_B +++ b/bottleneck/tests/data/test_106_B diff --git a/geom_bottleneck/tests/data/test_107_A b/bottleneck/tests/data/test_107_A index 79a621d..79a621d 100644 --- a/geom_bottleneck/tests/data/test_107_A +++ b/bottleneck/tests/data/test_107_A diff --git a/geom_bottleneck/tests/data/test_107_B b/bottleneck/tests/data/test_107_B index 43e4294..43e4294 100644 --- a/geom_bottleneck/tests/data/test_107_B +++ b/bottleneck/tests/data/test_107_B diff --git a/geom_bottleneck/tests/data/test_108_A b/bottleneck/tests/data/test_108_A index c2035e5..c2035e5 100644 --- a/geom_bottleneck/tests/data/test_108_A +++ b/bottleneck/tests/data/test_108_A diff --git a/geom_bottleneck/tests/data/test_108_B b/bottleneck/tests/data/test_108_B index 618c2c8..618c2c8 100644 --- a/geom_bottleneck/tests/data/test_108_B +++ b/bottleneck/tests/data/test_108_B diff --git a/geom_bottleneck/tests/data/test_109_A b/bottleneck/tests/data/test_109_A index d16f551..d16f551 100644 --- a/geom_bottleneck/tests/data/test_109_A +++ b/bottleneck/tests/data/test_109_A diff --git a/geom_bottleneck/tests/data/test_109_B b/bottleneck/tests/data/test_109_B index 02f9518..02f9518 100644 --- a/geom_bottleneck/tests/data/test_109_B +++ b/bottleneck/tests/data/test_109_B diff --git a/geom_bottleneck/tests/data/test_110_A b/bottleneck/tests/data/test_110_A index f013fd8..f013fd8 100644 --- a/geom_bottleneck/tests/data/test_110_A +++ b/bottleneck/tests/data/test_110_A diff --git a/geom_bottleneck/tests/data/test_110_B b/bottleneck/tests/data/test_110_B index f443b07..f443b07 100644 --- a/geom_bottleneck/tests/data/test_110_B +++ b/bottleneck/tests/data/test_110_B diff --git a/geom_bottleneck/tests/data/test_111_A b/bottleneck/tests/data/test_111_A index fcadd44..fcadd44 100644 --- a/geom_bottleneck/tests/data/test_111_A +++ b/bottleneck/tests/data/test_111_A diff --git a/geom_bottleneck/tests/data/test_111_B b/bottleneck/tests/data/test_111_B index 569a5d5..569a5d5 100644 --- a/geom_bottleneck/tests/data/test_111_B +++ b/bottleneck/tests/data/test_111_B diff --git a/geom_bottleneck/tests/data/test_112_A b/bottleneck/tests/data/test_112_A index 7d421ec..7d421ec 100644 --- a/geom_bottleneck/tests/data/test_112_A +++ b/bottleneck/tests/data/test_112_A diff --git a/geom_bottleneck/tests/data/test_112_B b/bottleneck/tests/data/test_112_B index ec7a9a1..ec7a9a1 100644 --- a/geom_bottleneck/tests/data/test_112_B +++ b/bottleneck/tests/data/test_112_B diff --git a/geom_bottleneck/tests/data/test_113_A b/bottleneck/tests/data/test_113_A index c3b3312..c3b3312 100644 --- a/geom_bottleneck/tests/data/test_113_A +++ b/bottleneck/tests/data/test_113_A diff --git a/geom_bottleneck/tests/data/test_113_B b/bottleneck/tests/data/test_113_B index ca287ff..ca287ff 100644 --- a/geom_bottleneck/tests/data/test_113_B +++ b/bottleneck/tests/data/test_113_B diff --git a/geom_bottleneck/tests/data/test_114_A b/bottleneck/tests/data/test_114_A index 112e9d3..112e9d3 100644 --- a/geom_bottleneck/tests/data/test_114_A +++ b/bottleneck/tests/data/test_114_A diff --git a/geom_bottleneck/tests/data/test_114_B b/bottleneck/tests/data/test_114_B index dabf69d..dabf69d 100644 --- a/geom_bottleneck/tests/data/test_114_B +++ b/bottleneck/tests/data/test_114_B diff --git a/geom_bottleneck/tests/data/test_115_A b/bottleneck/tests/data/test_115_A index c467eae..c467eae 100644 --- a/geom_bottleneck/tests/data/test_115_A +++ b/bottleneck/tests/data/test_115_A diff --git a/geom_bottleneck/tests/data/test_115_B b/bottleneck/tests/data/test_115_B index e14dd59..e14dd59 100644 --- a/geom_bottleneck/tests/data/test_115_B +++ b/bottleneck/tests/data/test_115_B diff --git a/geom_bottleneck/tests/data/test_116_A b/bottleneck/tests/data/test_116_A index 1828c98..1828c98 100644 --- a/geom_bottleneck/tests/data/test_116_A +++ b/bottleneck/tests/data/test_116_A diff --git a/geom_bottleneck/tests/data/test_116_B b/bottleneck/tests/data/test_116_B index f63039f..f63039f 100644 --- a/geom_bottleneck/tests/data/test_116_B +++ b/bottleneck/tests/data/test_116_B diff --git a/geom_bottleneck/tests/data/test_117_A b/bottleneck/tests/data/test_117_A index 280d9bc..280d9bc 100644 --- a/geom_bottleneck/tests/data/test_117_A +++ b/bottleneck/tests/data/test_117_A diff --git a/geom_bottleneck/tests/data/test_117_B b/bottleneck/tests/data/test_117_B index 595260c..595260c 100644 --- a/geom_bottleneck/tests/data/test_117_B +++ b/bottleneck/tests/data/test_117_B diff --git a/geom_bottleneck/tests/data/test_118_A b/bottleneck/tests/data/test_118_A index 2ecae80..2ecae80 100644 --- a/geom_bottleneck/tests/data/test_118_A +++ b/bottleneck/tests/data/test_118_A diff --git a/geom_bottleneck/tests/data/test_118_B b/bottleneck/tests/data/test_118_B index 13fc15b..13fc15b 100644 --- a/geom_bottleneck/tests/data/test_118_B +++ b/bottleneck/tests/data/test_118_B diff --git a/geom_bottleneck/tests/data/test_119_A b/bottleneck/tests/data/test_119_A index db12f3c..db12f3c 100644 --- a/geom_bottleneck/tests/data/test_119_A +++ b/bottleneck/tests/data/test_119_A diff --git a/geom_bottleneck/tests/data/test_119_B b/bottleneck/tests/data/test_119_B index 79ccbdd..79ccbdd 100644 --- a/geom_bottleneck/tests/data/test_119_B +++ b/bottleneck/tests/data/test_119_B diff --git a/geom_bottleneck/tests/data/test_120_A b/bottleneck/tests/data/test_120_A index cd31ead..cd31ead 100644 --- a/geom_bottleneck/tests/data/test_120_A +++ b/bottleneck/tests/data/test_120_A diff --git a/geom_bottleneck/tests/data/test_120_B b/bottleneck/tests/data/test_120_B index 148cbca..148cbca 100644 --- a/geom_bottleneck/tests/data/test_120_B +++ b/bottleneck/tests/data/test_120_B diff --git a/geom_bottleneck/tests/data/test_121_A b/bottleneck/tests/data/test_121_A index 864cde5..864cde5 100644 --- a/geom_bottleneck/tests/data/test_121_A +++ b/bottleneck/tests/data/test_121_A diff --git a/geom_bottleneck/tests/data/test_121_B b/bottleneck/tests/data/test_121_B index cc2c1dc..cc2c1dc 100644 --- a/geom_bottleneck/tests/data/test_121_B +++ b/bottleneck/tests/data/test_121_B diff --git a/geom_bottleneck/tests/data/test_122_A b/bottleneck/tests/data/test_122_A index 681d074..681d074 100644 --- a/geom_bottleneck/tests/data/test_122_A +++ b/bottleneck/tests/data/test_122_A diff --git a/geom_bottleneck/tests/data/test_122_B b/bottleneck/tests/data/test_122_B index e8681e6..e8681e6 100644 --- a/geom_bottleneck/tests/data/test_122_B +++ b/bottleneck/tests/data/test_122_B diff --git a/geom_bottleneck/tests/data/test_123_A b/bottleneck/tests/data/test_123_A index 2c53b51..2c53b51 100644 --- a/geom_bottleneck/tests/data/test_123_A +++ b/bottleneck/tests/data/test_123_A diff --git a/geom_bottleneck/tests/data/test_123_B b/bottleneck/tests/data/test_123_B index 0acdfb7..0acdfb7 100644 --- a/geom_bottleneck/tests/data/test_123_B +++ b/bottleneck/tests/data/test_123_B diff --git a/geom_bottleneck/tests/data/test_124_A b/bottleneck/tests/data/test_124_A index f43cb9a..f43cb9a 100644 --- a/geom_bottleneck/tests/data/test_124_A +++ b/bottleneck/tests/data/test_124_A diff --git a/geom_bottleneck/tests/data/test_124_B b/bottleneck/tests/data/test_124_B index 51dd494..51dd494 100644 --- a/geom_bottleneck/tests/data/test_124_B +++ b/bottleneck/tests/data/test_124_B diff --git a/geom_bottleneck/tests/data/test_125_A b/bottleneck/tests/data/test_125_A index e0b6720..e0b6720 100644 --- a/geom_bottleneck/tests/data/test_125_A +++ b/bottleneck/tests/data/test_125_A diff --git a/geom_bottleneck/tests/data/test_125_B b/bottleneck/tests/data/test_125_B index cf4f98c..cf4f98c 100644 --- a/geom_bottleneck/tests/data/test_125_B +++ b/bottleneck/tests/data/test_125_B diff --git a/geom_bottleneck/tests/data/test_126_A b/bottleneck/tests/data/test_126_A index f504606..f504606 100644 --- a/geom_bottleneck/tests/data/test_126_A +++ b/bottleneck/tests/data/test_126_A diff --git a/geom_bottleneck/tests/data/test_126_B b/bottleneck/tests/data/test_126_B index f5b5fda..f5b5fda 100644 --- a/geom_bottleneck/tests/data/test_126_B +++ b/bottleneck/tests/data/test_126_B diff --git a/geom_bottleneck/tests/data/test_127_A b/bottleneck/tests/data/test_127_A index 20f8541..20f8541 100644 --- a/geom_bottleneck/tests/data/test_127_A +++ b/bottleneck/tests/data/test_127_A diff --git a/geom_bottleneck/tests/data/test_127_B b/bottleneck/tests/data/test_127_B index 36f6cf3..36f6cf3 100644 --- a/geom_bottleneck/tests/data/test_127_B +++ b/bottleneck/tests/data/test_127_B diff --git a/geom_bottleneck/tests/data/test_128_A b/bottleneck/tests/data/test_128_A index 9e2c50e..9e2c50e 100644 --- a/geom_bottleneck/tests/data/test_128_A +++ b/bottleneck/tests/data/test_128_A diff --git a/geom_bottleneck/tests/data/test_128_B b/bottleneck/tests/data/test_128_B index 0fdae08..0fdae08 100644 --- a/geom_bottleneck/tests/data/test_128_B +++ b/bottleneck/tests/data/test_128_B diff --git a/geom_bottleneck/tests/data/test_129_A b/bottleneck/tests/data/test_129_A index dc289de..dc289de 100644 --- a/geom_bottleneck/tests/data/test_129_A +++ b/bottleneck/tests/data/test_129_A diff --git a/geom_bottleneck/tests/data/test_129_B b/bottleneck/tests/data/test_129_B index 3216111..3216111 100644 --- a/geom_bottleneck/tests/data/test_129_B +++ b/bottleneck/tests/data/test_129_B diff --git a/geom_bottleneck/tests/data/test_130_A b/bottleneck/tests/data/test_130_A index db70054..db70054 100644 --- a/geom_bottleneck/tests/data/test_130_A +++ b/bottleneck/tests/data/test_130_A diff --git a/geom_bottleneck/tests/data/test_130_B b/bottleneck/tests/data/test_130_B index 80c5a30..80c5a30 100644 --- a/geom_bottleneck/tests/data/test_130_B +++ b/bottleneck/tests/data/test_130_B diff --git a/geom_bottleneck/tests/data/test_131_A b/bottleneck/tests/data/test_131_A index 720cdb3..720cdb3 100644 --- a/geom_bottleneck/tests/data/test_131_A +++ b/bottleneck/tests/data/test_131_A diff --git a/geom_bottleneck/tests/data/test_131_B b/bottleneck/tests/data/test_131_B index 55bb437..55bb437 100644 --- a/geom_bottleneck/tests/data/test_131_B +++ b/bottleneck/tests/data/test_131_B diff --git a/geom_bottleneck/tests/data/test_132_A b/bottleneck/tests/data/test_132_A index dec8f13..dec8f13 100644 --- a/geom_bottleneck/tests/data/test_132_A +++ b/bottleneck/tests/data/test_132_A diff --git a/geom_bottleneck/tests/data/test_132_B b/bottleneck/tests/data/test_132_B index 8844484..8844484 100644 --- a/geom_bottleneck/tests/data/test_132_B +++ b/bottleneck/tests/data/test_132_B diff --git a/geom_bottleneck/tests/data/test_133_A b/bottleneck/tests/data/test_133_A index b46cb4f..b46cb4f 100644 --- a/geom_bottleneck/tests/data/test_133_A +++ b/bottleneck/tests/data/test_133_A diff --git a/geom_bottleneck/tests/data/test_133_B b/bottleneck/tests/data/test_133_B index 7a5d26a..7a5d26a 100644 --- a/geom_bottleneck/tests/data/test_133_B +++ b/bottleneck/tests/data/test_133_B diff --git a/geom_bottleneck/tests/data/test_134_A b/bottleneck/tests/data/test_134_A index 4abd1e5..4abd1e5 100644 --- a/geom_bottleneck/tests/data/test_134_A +++ b/bottleneck/tests/data/test_134_A diff --git a/geom_bottleneck/tests/data/test_134_B b/bottleneck/tests/data/test_134_B index aed169c..aed169c 100644 --- a/geom_bottleneck/tests/data/test_134_B +++ b/bottleneck/tests/data/test_134_B diff --git a/geom_bottleneck/tests/data/test_135_A b/bottleneck/tests/data/test_135_A index bbe9e95..bbe9e95 100644 --- a/geom_bottleneck/tests/data/test_135_A +++ b/bottleneck/tests/data/test_135_A diff --git a/geom_bottleneck/tests/data/test_135_B b/bottleneck/tests/data/test_135_B index 3c84c03..3c84c03 100644 --- a/geom_bottleneck/tests/data/test_135_B +++ b/bottleneck/tests/data/test_135_B diff --git a/geom_bottleneck/tests/data/test_136_A b/bottleneck/tests/data/test_136_A index a68856e..a68856e 100644 --- a/geom_bottleneck/tests/data/test_136_A +++ b/bottleneck/tests/data/test_136_A diff --git a/geom_bottleneck/tests/data/test_136_B b/bottleneck/tests/data/test_136_B index c03df54..c03df54 100644 --- a/geom_bottleneck/tests/data/test_136_B +++ b/bottleneck/tests/data/test_136_B diff --git a/geom_bottleneck/tests/data/test_137_A b/bottleneck/tests/data/test_137_A index 179d357..179d357 100644 --- a/geom_bottleneck/tests/data/test_137_A +++ b/bottleneck/tests/data/test_137_A diff --git a/geom_bottleneck/tests/data/test_137_B b/bottleneck/tests/data/test_137_B index 42541ae..42541ae 100644 --- a/geom_bottleneck/tests/data/test_137_B +++ b/bottleneck/tests/data/test_137_B diff --git a/geom_bottleneck/tests/data/test_138_A b/bottleneck/tests/data/test_138_A index 9c39dfb..9c39dfb 100644 --- a/geom_bottleneck/tests/data/test_138_A +++ b/bottleneck/tests/data/test_138_A diff --git a/geom_bottleneck/tests/data/test_138_B b/bottleneck/tests/data/test_138_B index 826d759..826d759 100644 --- a/geom_bottleneck/tests/data/test_138_B +++ b/bottleneck/tests/data/test_138_B diff --git a/geom_bottleneck/tests/data/test_139_A b/bottleneck/tests/data/test_139_A index 7f74c9f..7f74c9f 100644 --- a/geom_bottleneck/tests/data/test_139_A +++ b/bottleneck/tests/data/test_139_A diff --git a/geom_bottleneck/tests/data/test_139_B b/bottleneck/tests/data/test_139_B index ba4ab64..ba4ab64 100644 --- a/geom_bottleneck/tests/data/test_139_B +++ b/bottleneck/tests/data/test_139_B diff --git a/geom_bottleneck/tests/data/test_140_A b/bottleneck/tests/data/test_140_A index fec44cc..fec44cc 100644 --- a/geom_bottleneck/tests/data/test_140_A +++ b/bottleneck/tests/data/test_140_A diff --git a/geom_bottleneck/tests/data/test_140_B b/bottleneck/tests/data/test_140_B index af8aa1c..af8aa1c 100644 --- a/geom_bottleneck/tests/data/test_140_B +++ b/bottleneck/tests/data/test_140_B diff --git a/geom_bottleneck/tests/data/test_141_A b/bottleneck/tests/data/test_141_A index db65086..db65086 100644 --- a/geom_bottleneck/tests/data/test_141_A +++ b/bottleneck/tests/data/test_141_A diff --git a/geom_bottleneck/tests/data/test_141_B b/bottleneck/tests/data/test_141_B index 022c192..022c192 100644 --- a/geom_bottleneck/tests/data/test_141_B +++ b/bottleneck/tests/data/test_141_B diff --git a/geom_bottleneck/tests/data/test_142_A b/bottleneck/tests/data/test_142_A index 10bbe2d..10bbe2d 100644 --- a/geom_bottleneck/tests/data/test_142_A +++ b/bottleneck/tests/data/test_142_A diff --git a/geom_bottleneck/tests/data/test_142_B b/bottleneck/tests/data/test_142_B index 82b6b28..82b6b28 100644 --- a/geom_bottleneck/tests/data/test_142_B +++ b/bottleneck/tests/data/test_142_B diff --git a/geom_bottleneck/tests/data/test_143_A b/bottleneck/tests/data/test_143_A index 1db8047..1db8047 100644 --- a/geom_bottleneck/tests/data/test_143_A +++ b/bottleneck/tests/data/test_143_A diff --git a/geom_bottleneck/tests/data/test_143_B b/bottleneck/tests/data/test_143_B index 5c5a6a7..5c5a6a7 100644 --- a/geom_bottleneck/tests/data/test_143_B +++ b/bottleneck/tests/data/test_143_B diff --git a/geom_bottleneck/tests/data/test_144_A b/bottleneck/tests/data/test_144_A index 594f4c4..594f4c4 100644 --- a/geom_bottleneck/tests/data/test_144_A +++ b/bottleneck/tests/data/test_144_A diff --git a/geom_bottleneck/tests/data/test_144_B b/bottleneck/tests/data/test_144_B index aa3cd6d..aa3cd6d 100644 --- a/geom_bottleneck/tests/data/test_144_B +++ b/bottleneck/tests/data/test_144_B diff --git a/geom_bottleneck/tests/data/test_145_A b/bottleneck/tests/data/test_145_A index 41ea529..41ea529 100644 --- a/geom_bottleneck/tests/data/test_145_A +++ b/bottleneck/tests/data/test_145_A diff --git a/geom_bottleneck/tests/data/test_145_B b/bottleneck/tests/data/test_145_B index 5bcbaf0..5bcbaf0 100644 --- a/geom_bottleneck/tests/data/test_145_B +++ b/bottleneck/tests/data/test_145_B diff --git a/geom_bottleneck/tests/data/test_146_A b/bottleneck/tests/data/test_146_A index 18c1b4a..18c1b4a 100644 --- a/geom_bottleneck/tests/data/test_146_A +++ b/bottleneck/tests/data/test_146_A diff --git a/geom_bottleneck/tests/data/test_146_B b/bottleneck/tests/data/test_146_B index 24e5821..24e5821 100644 --- a/geom_bottleneck/tests/data/test_146_B +++ b/bottleneck/tests/data/test_146_B diff --git a/geom_bottleneck/tests/data/test_147_A b/bottleneck/tests/data/test_147_A index bce747d..bce747d 100644 --- a/geom_bottleneck/tests/data/test_147_A +++ b/bottleneck/tests/data/test_147_A diff --git a/geom_bottleneck/tests/data/test_147_B b/bottleneck/tests/data/test_147_B index c545851..c545851 100644 --- a/geom_bottleneck/tests/data/test_147_B +++ b/bottleneck/tests/data/test_147_B diff --git a/geom_bottleneck/tests/data/test_148_A b/bottleneck/tests/data/test_148_A index cd7482f..cd7482f 100644 --- a/geom_bottleneck/tests/data/test_148_A +++ b/bottleneck/tests/data/test_148_A diff --git a/geom_bottleneck/tests/data/test_148_B b/bottleneck/tests/data/test_148_B index a761bd3..a761bd3 100644 --- a/geom_bottleneck/tests/data/test_148_B +++ b/bottleneck/tests/data/test_148_B diff --git a/geom_bottleneck/tests/data/test_149_A b/bottleneck/tests/data/test_149_A index 81fff07..81fff07 100644 --- a/geom_bottleneck/tests/data/test_149_A +++ b/bottleneck/tests/data/test_149_A diff --git a/geom_bottleneck/tests/data/test_149_B b/bottleneck/tests/data/test_149_B index 1acd048..1acd048 100644 --- a/geom_bottleneck/tests/data/test_149_B +++ b/bottleneck/tests/data/test_149_B diff --git a/geom_bottleneck/tests/data/test_150_A b/bottleneck/tests/data/test_150_A index 8f4862d..8f4862d 100644 --- a/geom_bottleneck/tests/data/test_150_A +++ b/bottleneck/tests/data/test_150_A diff --git a/geom_bottleneck/tests/data/test_150_B b/bottleneck/tests/data/test_150_B index d55101f..d55101f 100644 --- a/geom_bottleneck/tests/data/test_150_B +++ b/bottleneck/tests/data/test_150_B diff --git a/geom_bottleneck/tests/data/test_151_A b/bottleneck/tests/data/test_151_A index 1915b6a..1915b6a 100644 --- a/geom_bottleneck/tests/data/test_151_A +++ b/bottleneck/tests/data/test_151_A diff --git a/geom_bottleneck/tests/data/test_151_B b/bottleneck/tests/data/test_151_B index 065a2c7..065a2c7 100644 --- a/geom_bottleneck/tests/data/test_151_B +++ b/bottleneck/tests/data/test_151_B diff --git a/geom_bottleneck/tests/data/test_152_A b/bottleneck/tests/data/test_152_A index 43ed98e..43ed98e 100644 --- a/geom_bottleneck/tests/data/test_152_A +++ b/bottleneck/tests/data/test_152_A diff --git a/geom_bottleneck/tests/data/test_152_B b/bottleneck/tests/data/test_152_B index 5e179b7..5e179b7 100644 --- a/geom_bottleneck/tests/data/test_152_B +++ b/bottleneck/tests/data/test_152_B diff --git a/geom_bottleneck/tests/data/test_153_A b/bottleneck/tests/data/test_153_A index 16f5a34..16f5a34 100644 --- a/geom_bottleneck/tests/data/test_153_A +++ b/bottleneck/tests/data/test_153_A diff --git a/geom_bottleneck/tests/data/test_153_B b/bottleneck/tests/data/test_153_B index a82ae69..a82ae69 100644 --- a/geom_bottleneck/tests/data/test_153_B +++ b/bottleneck/tests/data/test_153_B diff --git a/geom_bottleneck/tests/data/test_154_A b/bottleneck/tests/data/test_154_A index 73246c1..73246c1 100644 --- a/geom_bottleneck/tests/data/test_154_A +++ b/bottleneck/tests/data/test_154_A diff --git a/geom_bottleneck/tests/data/test_154_B b/bottleneck/tests/data/test_154_B index 6650b45..6650b45 100644 --- a/geom_bottleneck/tests/data/test_154_B +++ b/bottleneck/tests/data/test_154_B diff --git a/geom_bottleneck/tests/data/test_155_A b/bottleneck/tests/data/test_155_A index 9ce2859..9ce2859 100644 --- a/geom_bottleneck/tests/data/test_155_A +++ b/bottleneck/tests/data/test_155_A diff --git a/geom_bottleneck/tests/data/test_155_B b/bottleneck/tests/data/test_155_B index c852368..c852368 100644 --- a/geom_bottleneck/tests/data/test_155_B +++ b/bottleneck/tests/data/test_155_B diff --git a/geom_bottleneck/tests/data/test_156_A b/bottleneck/tests/data/test_156_A index e79fcd1..e79fcd1 100644 --- a/geom_bottleneck/tests/data/test_156_A +++ b/bottleneck/tests/data/test_156_A diff --git a/geom_bottleneck/tests/data/test_156_B b/bottleneck/tests/data/test_156_B index 05cd916..05cd916 100644 --- a/geom_bottleneck/tests/data/test_156_B +++ b/bottleneck/tests/data/test_156_B diff --git a/geom_bottleneck/tests/data/test_157_A b/bottleneck/tests/data/test_157_A index 257f007..257f007 100644 --- a/geom_bottleneck/tests/data/test_157_A +++ b/bottleneck/tests/data/test_157_A diff --git a/geom_bottleneck/tests/data/test_157_B b/bottleneck/tests/data/test_157_B index da76a0c..da76a0c 100644 --- a/geom_bottleneck/tests/data/test_157_B +++ b/bottleneck/tests/data/test_157_B diff --git a/geom_bottleneck/tests/data/test_158_A b/bottleneck/tests/data/test_158_A index ec64dab..ec64dab 100644 --- a/geom_bottleneck/tests/data/test_158_A +++ b/bottleneck/tests/data/test_158_A diff --git a/geom_bottleneck/tests/data/test_158_B b/bottleneck/tests/data/test_158_B index 407c843..407c843 100644 --- a/geom_bottleneck/tests/data/test_158_B +++ b/bottleneck/tests/data/test_158_B diff --git a/geom_bottleneck/tests/data/test_159_A b/bottleneck/tests/data/test_159_A index bbf8d13..bbf8d13 100644 --- a/geom_bottleneck/tests/data/test_159_A +++ b/bottleneck/tests/data/test_159_A diff --git a/geom_bottleneck/tests/data/test_159_B b/bottleneck/tests/data/test_159_B index fbe6d45..fbe6d45 100644 --- a/geom_bottleneck/tests/data/test_159_B +++ b/bottleneck/tests/data/test_159_B diff --git a/geom_bottleneck/tests/data/test_160_A b/bottleneck/tests/data/test_160_A index c712c5a..c712c5a 100644 --- a/geom_bottleneck/tests/data/test_160_A +++ b/bottleneck/tests/data/test_160_A diff --git a/geom_bottleneck/tests/data/test_160_B b/bottleneck/tests/data/test_160_B index 90edf6f..90edf6f 100644 --- a/geom_bottleneck/tests/data/test_160_B +++ b/bottleneck/tests/data/test_160_B diff --git a/geom_bottleneck/tests/data/test_161_A b/bottleneck/tests/data/test_161_A index 4cbae18..4cbae18 100644 --- a/geom_bottleneck/tests/data/test_161_A +++ b/bottleneck/tests/data/test_161_A diff --git a/geom_bottleneck/tests/data/test_161_B b/bottleneck/tests/data/test_161_B index e166afb..e166afb 100644 --- a/geom_bottleneck/tests/data/test_161_B +++ b/bottleneck/tests/data/test_161_B diff --git a/geom_bottleneck/tests/data/test_162_A b/bottleneck/tests/data/test_162_A index e16e9a3..e16e9a3 100644 --- a/geom_bottleneck/tests/data/test_162_A +++ b/bottleneck/tests/data/test_162_A diff --git a/geom_bottleneck/tests/data/test_162_B b/bottleneck/tests/data/test_162_B index 78ab6a3..78ab6a3 100644 --- a/geom_bottleneck/tests/data/test_162_B +++ b/bottleneck/tests/data/test_162_B diff --git a/geom_bottleneck/tests/data/test_163_A b/bottleneck/tests/data/test_163_A index 6836e59..6836e59 100644 --- a/geom_bottleneck/tests/data/test_163_A +++ b/bottleneck/tests/data/test_163_A diff --git a/geom_bottleneck/tests/data/test_163_B b/bottleneck/tests/data/test_163_B index 9d9e6e2..9d9e6e2 100644 --- a/geom_bottleneck/tests/data/test_163_B +++ b/bottleneck/tests/data/test_163_B diff --git a/geom_bottleneck/tests/data/test_164_A b/bottleneck/tests/data/test_164_A index a4187bd..a4187bd 100644 --- a/geom_bottleneck/tests/data/test_164_A +++ b/bottleneck/tests/data/test_164_A diff --git a/geom_bottleneck/tests/data/test_164_B b/bottleneck/tests/data/test_164_B index 8597409..8597409 100644 --- a/geom_bottleneck/tests/data/test_164_B +++ b/bottleneck/tests/data/test_164_B diff --git a/geom_bottleneck/tests/data/test_165_A b/bottleneck/tests/data/test_165_A index 15b9f15..15b9f15 100644 --- a/geom_bottleneck/tests/data/test_165_A +++ b/bottleneck/tests/data/test_165_A diff --git a/geom_bottleneck/tests/data/test_165_B b/bottleneck/tests/data/test_165_B index 8056eab..8056eab 100644 --- a/geom_bottleneck/tests/data/test_165_B +++ b/bottleneck/tests/data/test_165_B diff --git a/geom_bottleneck/tests/data/test_166_A b/bottleneck/tests/data/test_166_A index 8257649..8257649 100644 --- a/geom_bottleneck/tests/data/test_166_A +++ b/bottleneck/tests/data/test_166_A diff --git a/geom_bottleneck/tests/data/test_166_B b/bottleneck/tests/data/test_166_B index 02499eb..02499eb 100644 --- a/geom_bottleneck/tests/data/test_166_B +++ b/bottleneck/tests/data/test_166_B diff --git a/geom_bottleneck/tests/data/test_167_A b/bottleneck/tests/data/test_167_A index 416f645..416f645 100644 --- a/geom_bottleneck/tests/data/test_167_A +++ b/bottleneck/tests/data/test_167_A diff --git a/geom_bottleneck/tests/data/test_167_B b/bottleneck/tests/data/test_167_B index 2ab78e5..2ab78e5 100644 --- a/geom_bottleneck/tests/data/test_167_B +++ b/bottleneck/tests/data/test_167_B diff --git a/geom_bottleneck/tests/data/test_168_A b/bottleneck/tests/data/test_168_A index 57f9e66..57f9e66 100644 --- a/geom_bottleneck/tests/data/test_168_A +++ b/bottleneck/tests/data/test_168_A diff --git a/geom_bottleneck/tests/data/test_168_B b/bottleneck/tests/data/test_168_B index 6d5d9c5..6d5d9c5 100644 --- a/geom_bottleneck/tests/data/test_168_B +++ b/bottleneck/tests/data/test_168_B diff --git a/geom_bottleneck/tests/data/test_169_A b/bottleneck/tests/data/test_169_A index 7db2396..7db2396 100644 --- a/geom_bottleneck/tests/data/test_169_A +++ b/bottleneck/tests/data/test_169_A diff --git a/geom_bottleneck/tests/data/test_169_B b/bottleneck/tests/data/test_169_B index 58d7cec..58d7cec 100644 --- a/geom_bottleneck/tests/data/test_169_B +++ b/bottleneck/tests/data/test_169_B diff --git a/geom_bottleneck/tests/data/test_170_A b/bottleneck/tests/data/test_170_A index 7d30592..7d30592 100644 --- a/geom_bottleneck/tests/data/test_170_A +++ b/bottleneck/tests/data/test_170_A diff --git a/geom_bottleneck/tests/data/test_170_B b/bottleneck/tests/data/test_170_B index 86d8ccc..86d8ccc 100644 --- a/geom_bottleneck/tests/data/test_170_B +++ b/bottleneck/tests/data/test_170_B diff --git a/geom_bottleneck/tests/data/test_171_A b/bottleneck/tests/data/test_171_A index 30ce17c..30ce17c 100644 --- a/geom_bottleneck/tests/data/test_171_A +++ b/bottleneck/tests/data/test_171_A diff --git a/geom_bottleneck/tests/data/test_171_B b/bottleneck/tests/data/test_171_B index 487dcb5..487dcb5 100644 --- a/geom_bottleneck/tests/data/test_171_B +++ b/bottleneck/tests/data/test_171_B diff --git a/geom_bottleneck/tests/data/test_172_A b/bottleneck/tests/data/test_172_A index 69232cf..69232cf 100644 --- a/geom_bottleneck/tests/data/test_172_A +++ b/bottleneck/tests/data/test_172_A diff --git a/geom_bottleneck/tests/data/test_172_B b/bottleneck/tests/data/test_172_B index 1ab31ab..1ab31ab 100644 --- a/geom_bottleneck/tests/data/test_172_B +++ b/bottleneck/tests/data/test_172_B diff --git a/geom_bottleneck/tests/data/test_173_A b/bottleneck/tests/data/test_173_A index d88d368..d88d368 100644 --- a/geom_bottleneck/tests/data/test_173_A +++ b/bottleneck/tests/data/test_173_A diff --git a/geom_bottleneck/tests/data/test_173_B b/bottleneck/tests/data/test_173_B index a331c9c..a331c9c 100644 --- a/geom_bottleneck/tests/data/test_173_B +++ b/bottleneck/tests/data/test_173_B diff --git a/geom_bottleneck/tests/data/test_174_A b/bottleneck/tests/data/test_174_A index a97b65b..a97b65b 100644 --- a/geom_bottleneck/tests/data/test_174_A +++ b/bottleneck/tests/data/test_174_A diff --git a/geom_bottleneck/tests/data/test_174_B b/bottleneck/tests/data/test_174_B index 98da402..98da402 100644 --- a/geom_bottleneck/tests/data/test_174_B +++ b/bottleneck/tests/data/test_174_B diff --git a/geom_bottleneck/tests/data/test_175_A b/bottleneck/tests/data/test_175_A index dc8bedd..dc8bedd 100644 --- a/geom_bottleneck/tests/data/test_175_A +++ b/bottleneck/tests/data/test_175_A diff --git a/geom_bottleneck/tests/data/test_175_B b/bottleneck/tests/data/test_175_B index b5bd41f..b5bd41f 100644 --- a/geom_bottleneck/tests/data/test_175_B +++ b/bottleneck/tests/data/test_175_B diff --git a/geom_bottleneck/tests/data/test_176_A b/bottleneck/tests/data/test_176_A index dff782a..dff782a 100644 --- a/geom_bottleneck/tests/data/test_176_A +++ b/bottleneck/tests/data/test_176_A diff --git a/geom_bottleneck/tests/data/test_176_B b/bottleneck/tests/data/test_176_B index 8724366..8724366 100644 --- a/geom_bottleneck/tests/data/test_176_B +++ b/bottleneck/tests/data/test_176_B diff --git a/geom_bottleneck/tests/data/test_177_A b/bottleneck/tests/data/test_177_A index 556caf8..556caf8 100644 --- a/geom_bottleneck/tests/data/test_177_A +++ b/bottleneck/tests/data/test_177_A diff --git a/geom_bottleneck/tests/data/test_177_B b/bottleneck/tests/data/test_177_B index 91583a5..91583a5 100644 --- a/geom_bottleneck/tests/data/test_177_B +++ b/bottleneck/tests/data/test_177_B diff --git a/geom_bottleneck/tests/data/test_178_A b/bottleneck/tests/data/test_178_A index e223edb..e223edb 100644 --- a/geom_bottleneck/tests/data/test_178_A +++ b/bottleneck/tests/data/test_178_A diff --git a/geom_bottleneck/tests/data/test_178_B b/bottleneck/tests/data/test_178_B index 2ab0b73..2ab0b73 100644 --- a/geom_bottleneck/tests/data/test_178_B +++ b/bottleneck/tests/data/test_178_B diff --git a/geom_bottleneck/tests/data/test_179_A b/bottleneck/tests/data/test_179_A index 7b11730..7b11730 100644 --- a/geom_bottleneck/tests/data/test_179_A +++ b/bottleneck/tests/data/test_179_A diff --git a/geom_bottleneck/tests/data/test_179_B b/bottleneck/tests/data/test_179_B index e160b9f..e160b9f 100644 --- a/geom_bottleneck/tests/data/test_179_B +++ b/bottleneck/tests/data/test_179_B diff --git a/geom_bottleneck/tests/data/test_180_A b/bottleneck/tests/data/test_180_A index a830fb1..a830fb1 100644 --- a/geom_bottleneck/tests/data/test_180_A +++ b/bottleneck/tests/data/test_180_A diff --git a/geom_bottleneck/tests/data/test_180_B b/bottleneck/tests/data/test_180_B index 0ed2108..0ed2108 100644 --- a/geom_bottleneck/tests/data/test_180_B +++ b/bottleneck/tests/data/test_180_B diff --git a/geom_bottleneck/tests/data/test_181_A b/bottleneck/tests/data/test_181_A index e29de9c..e29de9c 100644 --- a/geom_bottleneck/tests/data/test_181_A +++ b/bottleneck/tests/data/test_181_A diff --git a/geom_bottleneck/tests/data/test_181_B b/bottleneck/tests/data/test_181_B index dacaa51..dacaa51 100644 --- a/geom_bottleneck/tests/data/test_181_B +++ b/bottleneck/tests/data/test_181_B diff --git a/geom_bottleneck/tests/data/test_182_A b/bottleneck/tests/data/test_182_A index e545af0..e545af0 100644 --- a/geom_bottleneck/tests/data/test_182_A +++ b/bottleneck/tests/data/test_182_A diff --git a/geom_bottleneck/tests/data/test_182_B b/bottleneck/tests/data/test_182_B index ffee041..ffee041 100644 --- a/geom_bottleneck/tests/data/test_182_B +++ b/bottleneck/tests/data/test_182_B diff --git a/geom_bottleneck/tests/data/test_183_A b/bottleneck/tests/data/test_183_A index 0681b8d..0681b8d 100644 --- a/geom_bottleneck/tests/data/test_183_A +++ b/bottleneck/tests/data/test_183_A diff --git a/geom_bottleneck/tests/data/test_183_B b/bottleneck/tests/data/test_183_B index da3af74..da3af74 100644 --- a/geom_bottleneck/tests/data/test_183_B +++ b/bottleneck/tests/data/test_183_B diff --git a/geom_bottleneck/tests/data/test_184_A b/bottleneck/tests/data/test_184_A index a252760..a252760 100644 --- a/geom_bottleneck/tests/data/test_184_A +++ b/bottleneck/tests/data/test_184_A diff --git a/geom_bottleneck/tests/data/test_184_B b/bottleneck/tests/data/test_184_B index 788be62..788be62 100644 --- a/geom_bottleneck/tests/data/test_184_B +++ b/bottleneck/tests/data/test_184_B diff --git a/geom_bottleneck/tests/data/test_185_A b/bottleneck/tests/data/test_185_A index 8922d7a..8922d7a 100644 --- a/geom_bottleneck/tests/data/test_185_A +++ b/bottleneck/tests/data/test_185_A diff --git a/geom_bottleneck/tests/data/test_185_B b/bottleneck/tests/data/test_185_B index fc90091..fc90091 100644 --- a/geom_bottleneck/tests/data/test_185_B +++ b/bottleneck/tests/data/test_185_B diff --git a/geom_bottleneck/tests/data/test_186_A b/bottleneck/tests/data/test_186_A index 894dc49..894dc49 100644 --- a/geom_bottleneck/tests/data/test_186_A +++ b/bottleneck/tests/data/test_186_A diff --git a/geom_bottleneck/tests/data/test_186_B b/bottleneck/tests/data/test_186_B index c0b49c0..c0b49c0 100644 --- a/geom_bottleneck/tests/data/test_186_B +++ b/bottleneck/tests/data/test_186_B diff --git a/geom_bottleneck/tests/data/test_187_A b/bottleneck/tests/data/test_187_A index f2181af..f2181af 100644 --- a/geom_bottleneck/tests/data/test_187_A +++ b/bottleneck/tests/data/test_187_A diff --git a/geom_bottleneck/tests/data/test_187_B b/bottleneck/tests/data/test_187_B index ab13d0f..ab13d0f 100644 --- a/geom_bottleneck/tests/data/test_187_B +++ b/bottleneck/tests/data/test_187_B diff --git a/geom_bottleneck/tests/data/test_188_A b/bottleneck/tests/data/test_188_A index 8290582..8290582 100644 --- a/geom_bottleneck/tests/data/test_188_A +++ b/bottleneck/tests/data/test_188_A diff --git a/geom_bottleneck/tests/data/test_188_B b/bottleneck/tests/data/test_188_B index 6acfc2e..6acfc2e 100644 --- a/geom_bottleneck/tests/data/test_188_B +++ b/bottleneck/tests/data/test_188_B diff --git a/geom_bottleneck/tests/data/test_189_A b/bottleneck/tests/data/test_189_A index 468967c..468967c 100644 --- a/geom_bottleneck/tests/data/test_189_A +++ b/bottleneck/tests/data/test_189_A diff --git a/geom_bottleneck/tests/data/test_189_B b/bottleneck/tests/data/test_189_B index 299edf6..299edf6 100644 --- a/geom_bottleneck/tests/data/test_189_B +++ b/bottleneck/tests/data/test_189_B diff --git a/geom_bottleneck/tests/data/test_190_A b/bottleneck/tests/data/test_190_A index 01b3e3c..01b3e3c 100644 --- a/geom_bottleneck/tests/data/test_190_A +++ b/bottleneck/tests/data/test_190_A diff --git a/geom_bottleneck/tests/data/test_190_B b/bottleneck/tests/data/test_190_B index 26d2d2a..26d2d2a 100644 --- a/geom_bottleneck/tests/data/test_190_B +++ b/bottleneck/tests/data/test_190_B diff --git a/geom_bottleneck/tests/data/test_191_A b/bottleneck/tests/data/test_191_A index e89e4b8..e89e4b8 100644 --- a/geom_bottleneck/tests/data/test_191_A +++ b/bottleneck/tests/data/test_191_A diff --git a/geom_bottleneck/tests/data/test_191_B b/bottleneck/tests/data/test_191_B index 80022bc..80022bc 100644 --- a/geom_bottleneck/tests/data/test_191_B +++ b/bottleneck/tests/data/test_191_B diff --git a/geom_bottleneck/tests/data/test_192_A b/bottleneck/tests/data/test_192_A index 8e0e64f..8e0e64f 100644 --- a/geom_bottleneck/tests/data/test_192_A +++ b/bottleneck/tests/data/test_192_A diff --git a/geom_bottleneck/tests/data/test_192_B b/bottleneck/tests/data/test_192_B index dcfe162..dcfe162 100644 --- a/geom_bottleneck/tests/data/test_192_B +++ b/bottleneck/tests/data/test_192_B diff --git a/geom_bottleneck/tests/data/test_193_A b/bottleneck/tests/data/test_193_A index 6c2bcc8..6c2bcc8 100644 --- a/geom_bottleneck/tests/data/test_193_A +++ b/bottleneck/tests/data/test_193_A diff --git a/geom_bottleneck/tests/data/test_193_B b/bottleneck/tests/data/test_193_B index fb271c9..fb271c9 100644 --- a/geom_bottleneck/tests/data/test_193_B +++ b/bottleneck/tests/data/test_193_B diff --git a/geom_bottleneck/tests/data/test_194_A b/bottleneck/tests/data/test_194_A index 2de1094..2de1094 100644 --- a/geom_bottleneck/tests/data/test_194_A +++ b/bottleneck/tests/data/test_194_A diff --git a/geom_bottleneck/tests/data/test_194_B b/bottleneck/tests/data/test_194_B index 5879993..5879993 100644 --- a/geom_bottleneck/tests/data/test_194_B +++ b/bottleneck/tests/data/test_194_B diff --git a/geom_bottleneck/tests/data/test_195_A b/bottleneck/tests/data/test_195_A index d109838..d109838 100644 --- a/geom_bottleneck/tests/data/test_195_A +++ b/bottleneck/tests/data/test_195_A diff --git a/geom_bottleneck/tests/data/test_195_B b/bottleneck/tests/data/test_195_B index 6c66513..6c66513 100644 --- a/geom_bottleneck/tests/data/test_195_B +++ b/bottleneck/tests/data/test_195_B diff --git a/geom_bottleneck/tests/data/test_196_A b/bottleneck/tests/data/test_196_A index 4094acd..4094acd 100644 --- a/geom_bottleneck/tests/data/test_196_A +++ b/bottleneck/tests/data/test_196_A diff --git a/geom_bottleneck/tests/data/test_196_B b/bottleneck/tests/data/test_196_B index e5ed3ad..e5ed3ad 100644 --- a/geom_bottleneck/tests/data/test_196_B +++ b/bottleneck/tests/data/test_196_B diff --git a/geom_bottleneck/tests/data/test_197_A b/bottleneck/tests/data/test_197_A index 771897b..771897b 100644 --- a/geom_bottleneck/tests/data/test_197_A +++ b/bottleneck/tests/data/test_197_A diff --git a/geom_bottleneck/tests/data/test_197_B b/bottleneck/tests/data/test_197_B index 1cfe6aa..1cfe6aa 100644 --- a/geom_bottleneck/tests/data/test_197_B +++ b/bottleneck/tests/data/test_197_B diff --git a/geom_bottleneck/tests/data/test_198_A b/bottleneck/tests/data/test_198_A index 6966ac4..6966ac4 100644 --- a/geom_bottleneck/tests/data/test_198_A +++ b/bottleneck/tests/data/test_198_A diff --git a/geom_bottleneck/tests/data/test_198_B b/bottleneck/tests/data/test_198_B index 6e9d9d4..6e9d9d4 100644 --- a/geom_bottleneck/tests/data/test_198_B +++ b/bottleneck/tests/data/test_198_B diff --git a/geom_bottleneck/tests/data/test_199_A b/bottleneck/tests/data/test_199_A index 8556563..8556563 100644 --- a/geom_bottleneck/tests/data/test_199_A +++ b/bottleneck/tests/data/test_199_A diff --git a/geom_bottleneck/tests/data/test_199_B b/bottleneck/tests/data/test_199_B index a43e0df..a43e0df 100644 --- a/geom_bottleneck/tests/data/test_199_B +++ b/bottleneck/tests/data/test_199_B diff --git a/geom_bottleneck/tests/data/test_200_A b/bottleneck/tests/data/test_200_A index b0a7fbd..b0a7fbd 100644 --- a/geom_bottleneck/tests/data/test_200_A +++ b/bottleneck/tests/data/test_200_A diff --git a/geom_bottleneck/tests/data/test_200_B b/bottleneck/tests/data/test_200_B index fcbab9a..fcbab9a 100644 --- a/geom_bottleneck/tests/data/test_200_B +++ b/bottleneck/tests/data/test_200_B diff --git a/geom_bottleneck/tests/data/test_201_A b/bottleneck/tests/data/test_201_A index 07d880d..07d880d 100644 --- a/geom_bottleneck/tests/data/test_201_A +++ b/bottleneck/tests/data/test_201_A diff --git a/geom_bottleneck/tests/data/test_201_B b/bottleneck/tests/data/test_201_B index 70b22f4..70b22f4 100644 --- a/geom_bottleneck/tests/data/test_201_B +++ b/bottleneck/tests/data/test_201_B diff --git a/geom_bottleneck/tests/data/test_202_A b/bottleneck/tests/data/test_202_A index b8fe1b9..b8fe1b9 100644 --- a/geom_bottleneck/tests/data/test_202_A +++ b/bottleneck/tests/data/test_202_A diff --git a/geom_bottleneck/tests/data/test_202_B b/bottleneck/tests/data/test_202_B index ee6e2e0..ee6e2e0 100644 --- a/geom_bottleneck/tests/data/test_202_B +++ b/bottleneck/tests/data/test_202_B diff --git a/geom_bottleneck/tests/data/test_203_A b/bottleneck/tests/data/test_203_A index 71a1737..71a1737 100644 --- a/geom_bottleneck/tests/data/test_203_A +++ b/bottleneck/tests/data/test_203_A diff --git a/geom_bottleneck/tests/data/test_203_B b/bottleneck/tests/data/test_203_B index d217cda..d217cda 100644 --- a/geom_bottleneck/tests/data/test_203_B +++ b/bottleneck/tests/data/test_203_B diff --git a/geom_bottleneck/tests/data/test_204_A b/bottleneck/tests/data/test_204_A index 011da68..011da68 100644 --- a/geom_bottleneck/tests/data/test_204_A +++ b/bottleneck/tests/data/test_204_A diff --git a/geom_bottleneck/tests/data/test_204_B b/bottleneck/tests/data/test_204_B index c5d6236..c5d6236 100644 --- a/geom_bottleneck/tests/data/test_204_B +++ b/bottleneck/tests/data/test_204_B diff --git a/geom_bottleneck/tests/data/test_205_A b/bottleneck/tests/data/test_205_A index d082be1..d082be1 100644 --- a/geom_bottleneck/tests/data/test_205_A +++ b/bottleneck/tests/data/test_205_A diff --git a/geom_bottleneck/tests/data/test_205_B b/bottleneck/tests/data/test_205_B index 30a242c..30a242c 100644 --- a/geom_bottleneck/tests/data/test_205_B +++ b/bottleneck/tests/data/test_205_B diff --git a/geom_bottleneck/tests/data/test_206_A b/bottleneck/tests/data/test_206_A index 15ee45b..15ee45b 100644 --- a/geom_bottleneck/tests/data/test_206_A +++ b/bottleneck/tests/data/test_206_A diff --git a/geom_bottleneck/tests/data/test_206_B b/bottleneck/tests/data/test_206_B index f8c89ef..f8c89ef 100644 --- a/geom_bottleneck/tests/data/test_206_B +++ b/bottleneck/tests/data/test_206_B diff --git a/geom_bottleneck/tests/data/test_207_A b/bottleneck/tests/data/test_207_A index 2015b9e..2015b9e 100644 --- a/geom_bottleneck/tests/data/test_207_A +++ b/bottleneck/tests/data/test_207_A diff --git a/geom_bottleneck/tests/data/test_207_B b/bottleneck/tests/data/test_207_B index 036a8ca..036a8ca 100644 --- a/geom_bottleneck/tests/data/test_207_B +++ b/bottleneck/tests/data/test_207_B diff --git a/geom_bottleneck/tests/data/test_208_A b/bottleneck/tests/data/test_208_A index a1e6af4..a1e6af4 100644 --- a/geom_bottleneck/tests/data/test_208_A +++ b/bottleneck/tests/data/test_208_A diff --git a/geom_bottleneck/tests/data/test_208_B b/bottleneck/tests/data/test_208_B index f21e91b..f21e91b 100644 --- a/geom_bottleneck/tests/data/test_208_B +++ b/bottleneck/tests/data/test_208_B diff --git a/geom_bottleneck/tests/data/test_209_A b/bottleneck/tests/data/test_209_A index 545aae9..545aae9 100644 --- a/geom_bottleneck/tests/data/test_209_A +++ b/bottleneck/tests/data/test_209_A diff --git a/geom_bottleneck/tests/data/test_209_B b/bottleneck/tests/data/test_209_B index 2cf3171..2cf3171 100644 --- a/geom_bottleneck/tests/data/test_209_B +++ b/bottleneck/tests/data/test_209_B diff --git a/geom_bottleneck/tests/data/test_210_A b/bottleneck/tests/data/test_210_A index 799debc..799debc 100644 --- a/geom_bottleneck/tests/data/test_210_A +++ b/bottleneck/tests/data/test_210_A diff --git a/geom_bottleneck/tests/data/test_210_B b/bottleneck/tests/data/test_210_B index 7cb0519..7cb0519 100644 --- a/geom_bottleneck/tests/data/test_210_B +++ b/bottleneck/tests/data/test_210_B diff --git a/geom_bottleneck/tests/data/test_211_A b/bottleneck/tests/data/test_211_A index 6715acb..6715acb 100644 --- a/geom_bottleneck/tests/data/test_211_A +++ b/bottleneck/tests/data/test_211_A diff --git a/geom_bottleneck/tests/data/test_211_B b/bottleneck/tests/data/test_211_B index 9c7890f..9c7890f 100644 --- a/geom_bottleneck/tests/data/test_211_B +++ b/bottleneck/tests/data/test_211_B diff --git a/geom_bottleneck/tests/data/test_212_A b/bottleneck/tests/data/test_212_A index e3d327a..e3d327a 100644 --- a/geom_bottleneck/tests/data/test_212_A +++ b/bottleneck/tests/data/test_212_A diff --git a/geom_bottleneck/tests/data/test_212_B b/bottleneck/tests/data/test_212_B index ee57410..ee57410 100644 --- a/geom_bottleneck/tests/data/test_212_B +++ b/bottleneck/tests/data/test_212_B diff --git a/geom_bottleneck/tests/data/test_213_A b/bottleneck/tests/data/test_213_A index 4b904df..4b904df 100644 --- a/geom_bottleneck/tests/data/test_213_A +++ b/bottleneck/tests/data/test_213_A diff --git a/geom_bottleneck/tests/data/test_213_B b/bottleneck/tests/data/test_213_B index f5188b4..f5188b4 100644 --- a/geom_bottleneck/tests/data/test_213_B +++ b/bottleneck/tests/data/test_213_B diff --git a/geom_bottleneck/tests/data/test_214_A b/bottleneck/tests/data/test_214_A index 3914579..3914579 100644 --- a/geom_bottleneck/tests/data/test_214_A +++ b/bottleneck/tests/data/test_214_A diff --git a/geom_bottleneck/tests/data/test_214_B b/bottleneck/tests/data/test_214_B index f75c54f..f75c54f 100644 --- a/geom_bottleneck/tests/data/test_214_B +++ b/bottleneck/tests/data/test_214_B diff --git a/geom_bottleneck/tests/data/test_215_A b/bottleneck/tests/data/test_215_A index a8d6070..a8d6070 100644 --- a/geom_bottleneck/tests/data/test_215_A +++ b/bottleneck/tests/data/test_215_A diff --git a/geom_bottleneck/tests/data/test_215_B b/bottleneck/tests/data/test_215_B index d956b59..d956b59 100644 --- a/geom_bottleneck/tests/data/test_215_B +++ b/bottleneck/tests/data/test_215_B diff --git a/geom_bottleneck/tests/data/test_216_A b/bottleneck/tests/data/test_216_A index 67c5e86..67c5e86 100644 --- a/geom_bottleneck/tests/data/test_216_A +++ b/bottleneck/tests/data/test_216_A diff --git a/geom_bottleneck/tests/data/test_216_B b/bottleneck/tests/data/test_216_B index 802850d..802850d 100644 --- a/geom_bottleneck/tests/data/test_216_B +++ b/bottleneck/tests/data/test_216_B diff --git a/geom_bottleneck/tests/data/test_217_A b/bottleneck/tests/data/test_217_A index a37f46d..a37f46d 100644 --- a/geom_bottleneck/tests/data/test_217_A +++ b/bottleneck/tests/data/test_217_A diff --git a/geom_bottleneck/tests/data/test_217_B b/bottleneck/tests/data/test_217_B index 4cac64e..4cac64e 100644 --- a/geom_bottleneck/tests/data/test_217_B +++ b/bottleneck/tests/data/test_217_B diff --git a/geom_bottleneck/tests/data/test_218_A b/bottleneck/tests/data/test_218_A index 7ca83bc..7ca83bc 100644 --- a/geom_bottleneck/tests/data/test_218_A +++ b/bottleneck/tests/data/test_218_A diff --git a/geom_bottleneck/tests/data/test_218_B b/bottleneck/tests/data/test_218_B index 7c188f2..7c188f2 100644 --- a/geom_bottleneck/tests/data/test_218_B +++ b/bottleneck/tests/data/test_218_B diff --git a/geom_bottleneck/tests/data/test_219_A b/bottleneck/tests/data/test_219_A index 275bc18..275bc18 100644 --- a/geom_bottleneck/tests/data/test_219_A +++ b/bottleneck/tests/data/test_219_A diff --git a/geom_bottleneck/tests/data/test_219_B b/bottleneck/tests/data/test_219_B index be6ab2a..be6ab2a 100644 --- a/geom_bottleneck/tests/data/test_219_B +++ b/bottleneck/tests/data/test_219_B diff --git a/geom_bottleneck/tests/data/test_220_A b/bottleneck/tests/data/test_220_A index 3b9ea09..3b9ea09 100644 --- a/geom_bottleneck/tests/data/test_220_A +++ b/bottleneck/tests/data/test_220_A diff --git a/geom_bottleneck/tests/data/test_220_B b/bottleneck/tests/data/test_220_B index 8e97d15..8e97d15 100644 --- a/geom_bottleneck/tests/data/test_220_B +++ b/bottleneck/tests/data/test_220_B diff --git a/geom_bottleneck/tests/data/test_221_A b/bottleneck/tests/data/test_221_A index 2e229a8..2e229a8 100644 --- a/geom_bottleneck/tests/data/test_221_A +++ b/bottleneck/tests/data/test_221_A diff --git a/geom_bottleneck/tests/data/test_221_B b/bottleneck/tests/data/test_221_B index e3c3c1b..e3c3c1b 100644 --- a/geom_bottleneck/tests/data/test_221_B +++ b/bottleneck/tests/data/test_221_B diff --git a/geom_bottleneck/tests/data/test_222_A b/bottleneck/tests/data/test_222_A index fcb6c7f..fcb6c7f 100644 --- a/geom_bottleneck/tests/data/test_222_A +++ b/bottleneck/tests/data/test_222_A diff --git a/geom_bottleneck/tests/data/test_222_B b/bottleneck/tests/data/test_222_B index 512f188..512f188 100644 --- a/geom_bottleneck/tests/data/test_222_B +++ b/bottleneck/tests/data/test_222_B diff --git a/geom_bottleneck/tests/data/test_223_A b/bottleneck/tests/data/test_223_A index 6f6cef5..6f6cef5 100644 --- a/geom_bottleneck/tests/data/test_223_A +++ b/bottleneck/tests/data/test_223_A diff --git a/geom_bottleneck/tests/data/test_223_B b/bottleneck/tests/data/test_223_B index 07803f6..07803f6 100644 --- a/geom_bottleneck/tests/data/test_223_B +++ b/bottleneck/tests/data/test_223_B diff --git a/geom_bottleneck/tests/data/test_224_A b/bottleneck/tests/data/test_224_A index f33d061..f33d061 100644 --- a/geom_bottleneck/tests/data/test_224_A +++ b/bottleneck/tests/data/test_224_A diff --git a/geom_bottleneck/tests/data/test_224_B b/bottleneck/tests/data/test_224_B index 1b9ef36..1b9ef36 100644 --- a/geom_bottleneck/tests/data/test_224_B +++ b/bottleneck/tests/data/test_224_B diff --git a/geom_bottleneck/tests/data/test_225_A b/bottleneck/tests/data/test_225_A index cc0d576..cc0d576 100644 --- a/geom_bottleneck/tests/data/test_225_A +++ b/bottleneck/tests/data/test_225_A diff --git a/geom_bottleneck/tests/data/test_225_B b/bottleneck/tests/data/test_225_B index b810b48..b810b48 100644 --- a/geom_bottleneck/tests/data/test_225_B +++ b/bottleneck/tests/data/test_225_B diff --git a/geom_bottleneck/tests/data/test_226_A b/bottleneck/tests/data/test_226_A index e39728a..e39728a 100644 --- a/geom_bottleneck/tests/data/test_226_A +++ b/bottleneck/tests/data/test_226_A diff --git a/geom_bottleneck/tests/data/test_226_B b/bottleneck/tests/data/test_226_B index 601abce..601abce 100644 --- a/geom_bottleneck/tests/data/test_226_B +++ b/bottleneck/tests/data/test_226_B diff --git a/geom_bottleneck/tests/data/test_227_A b/bottleneck/tests/data/test_227_A index e98b204..e98b204 100644 --- a/geom_bottleneck/tests/data/test_227_A +++ b/bottleneck/tests/data/test_227_A diff --git a/geom_bottleneck/tests/data/test_227_B b/bottleneck/tests/data/test_227_B index 3d5a25e..3d5a25e 100644 --- a/geom_bottleneck/tests/data/test_227_B +++ b/bottleneck/tests/data/test_227_B diff --git a/geom_bottleneck/tests/data/test_228_A b/bottleneck/tests/data/test_228_A index a3edeae..a3edeae 100644 --- a/geom_bottleneck/tests/data/test_228_A +++ b/bottleneck/tests/data/test_228_A diff --git a/geom_bottleneck/tests/data/test_228_B b/bottleneck/tests/data/test_228_B index 64f78ac..64f78ac 100644 --- a/geom_bottleneck/tests/data/test_228_B +++ b/bottleneck/tests/data/test_228_B diff --git a/geom_bottleneck/tests/data/test_229_A b/bottleneck/tests/data/test_229_A index c832a04..c832a04 100644 --- a/geom_bottleneck/tests/data/test_229_A +++ b/bottleneck/tests/data/test_229_A diff --git a/geom_bottleneck/tests/data/test_229_B b/bottleneck/tests/data/test_229_B index 0f232d0..0f232d0 100644 --- a/geom_bottleneck/tests/data/test_229_B +++ b/bottleneck/tests/data/test_229_B diff --git a/geom_bottleneck/tests/data/test_230_A b/bottleneck/tests/data/test_230_A index 11d75a8..11d75a8 100644 --- a/geom_bottleneck/tests/data/test_230_A +++ b/bottleneck/tests/data/test_230_A diff --git a/geom_bottleneck/tests/data/test_230_B b/bottleneck/tests/data/test_230_B index f30b9d0..f30b9d0 100644 --- a/geom_bottleneck/tests/data/test_230_B +++ b/bottleneck/tests/data/test_230_B diff --git a/geom_bottleneck/tests/data/test_231_A b/bottleneck/tests/data/test_231_A index 8d21ce3..8d21ce3 100644 --- a/geom_bottleneck/tests/data/test_231_A +++ b/bottleneck/tests/data/test_231_A diff --git a/geom_bottleneck/tests/data/test_231_B b/bottleneck/tests/data/test_231_B index f5d94fe..f5d94fe 100644 --- a/geom_bottleneck/tests/data/test_231_B +++ b/bottleneck/tests/data/test_231_B diff --git a/geom_bottleneck/tests/data/test_232_A b/bottleneck/tests/data/test_232_A index ccad736..ccad736 100644 --- a/geom_bottleneck/tests/data/test_232_A +++ b/bottleneck/tests/data/test_232_A diff --git a/geom_bottleneck/tests/data/test_232_B b/bottleneck/tests/data/test_232_B index f132580..f132580 100644 --- a/geom_bottleneck/tests/data/test_232_B +++ b/bottleneck/tests/data/test_232_B diff --git a/geom_bottleneck/tests/data/test_233_A b/bottleneck/tests/data/test_233_A index fd2fa4e..fd2fa4e 100644 --- a/geom_bottleneck/tests/data/test_233_A +++ b/bottleneck/tests/data/test_233_A diff --git a/geom_bottleneck/tests/data/test_233_B b/bottleneck/tests/data/test_233_B index 3dc34c6..3dc34c6 100644 --- a/geom_bottleneck/tests/data/test_233_B +++ b/bottleneck/tests/data/test_233_B diff --git a/geom_bottleneck/tests/data/test_234_A b/bottleneck/tests/data/test_234_A index 6ff3442..6ff3442 100644 --- a/geom_bottleneck/tests/data/test_234_A +++ b/bottleneck/tests/data/test_234_A diff --git a/geom_bottleneck/tests/data/test_234_B b/bottleneck/tests/data/test_234_B index 36a2966..36a2966 100644 --- a/geom_bottleneck/tests/data/test_234_B +++ b/bottleneck/tests/data/test_234_B diff --git a/geom_bottleneck/tests/data/test_235_A b/bottleneck/tests/data/test_235_A index 40aec79..40aec79 100644 --- a/geom_bottleneck/tests/data/test_235_A +++ b/bottleneck/tests/data/test_235_A diff --git a/geom_bottleneck/tests/data/test_235_B b/bottleneck/tests/data/test_235_B index 910422b..910422b 100644 --- a/geom_bottleneck/tests/data/test_235_B +++ b/bottleneck/tests/data/test_235_B diff --git a/geom_bottleneck/tests/data/test_236_A b/bottleneck/tests/data/test_236_A index 8ca54db..8ca54db 100644 --- a/geom_bottleneck/tests/data/test_236_A +++ b/bottleneck/tests/data/test_236_A diff --git a/geom_bottleneck/tests/data/test_236_B b/bottleneck/tests/data/test_236_B index 0855757..0855757 100644 --- a/geom_bottleneck/tests/data/test_236_B +++ b/bottleneck/tests/data/test_236_B diff --git a/geom_bottleneck/tests/data/test_237_A b/bottleneck/tests/data/test_237_A index 18a69fa..18a69fa 100644 --- a/geom_bottleneck/tests/data/test_237_A +++ b/bottleneck/tests/data/test_237_A diff --git a/geom_bottleneck/tests/data/test_237_B b/bottleneck/tests/data/test_237_B index b2ad13f..b2ad13f 100644 --- a/geom_bottleneck/tests/data/test_237_B +++ b/bottleneck/tests/data/test_237_B diff --git a/geom_bottleneck/tests/data/test_238_A b/bottleneck/tests/data/test_238_A index d9011b0..d9011b0 100644 --- a/geom_bottleneck/tests/data/test_238_A +++ b/bottleneck/tests/data/test_238_A diff --git a/geom_bottleneck/tests/data/test_238_B b/bottleneck/tests/data/test_238_B index 788cf40..788cf40 100644 --- a/geom_bottleneck/tests/data/test_238_B +++ b/bottleneck/tests/data/test_238_B diff --git a/geom_bottleneck/tests/data/test_239_A b/bottleneck/tests/data/test_239_A index dbb3bec..dbb3bec 100644 --- a/geom_bottleneck/tests/data/test_239_A +++ b/bottleneck/tests/data/test_239_A diff --git a/geom_bottleneck/tests/data/test_239_B b/bottleneck/tests/data/test_239_B index a0c12ac..a0c12ac 100644 --- a/geom_bottleneck/tests/data/test_239_B +++ b/bottleneck/tests/data/test_239_B diff --git a/geom_bottleneck/tests/data/test_240_A b/bottleneck/tests/data/test_240_A index 2386a27..2386a27 100644 --- a/geom_bottleneck/tests/data/test_240_A +++ b/bottleneck/tests/data/test_240_A diff --git a/geom_bottleneck/tests/data/test_240_B b/bottleneck/tests/data/test_240_B index 15439fb..15439fb 100644 --- a/geom_bottleneck/tests/data/test_240_B +++ b/bottleneck/tests/data/test_240_B diff --git a/geom_bottleneck/tests/data/test_241_A b/bottleneck/tests/data/test_241_A index 8ed0c54..8ed0c54 100644 --- a/geom_bottleneck/tests/data/test_241_A +++ b/bottleneck/tests/data/test_241_A diff --git a/geom_bottleneck/tests/data/test_241_B b/bottleneck/tests/data/test_241_B index fdac53a..fdac53a 100644 --- a/geom_bottleneck/tests/data/test_241_B +++ b/bottleneck/tests/data/test_241_B diff --git a/geom_bottleneck/tests/data/test_242_A b/bottleneck/tests/data/test_242_A index e1af329..e1af329 100644 --- a/geom_bottleneck/tests/data/test_242_A +++ b/bottleneck/tests/data/test_242_A diff --git a/geom_bottleneck/tests/data/test_242_B b/bottleneck/tests/data/test_242_B index b45d054..b45d054 100644 --- a/geom_bottleneck/tests/data/test_242_B +++ b/bottleneck/tests/data/test_242_B diff --git a/geom_bottleneck/tests/data/test_243_A b/bottleneck/tests/data/test_243_A index ed2d61b..ed2d61b 100644 --- a/geom_bottleneck/tests/data/test_243_A +++ b/bottleneck/tests/data/test_243_A diff --git a/geom_bottleneck/tests/data/test_243_B b/bottleneck/tests/data/test_243_B index f0b5359..f0b5359 100644 --- a/geom_bottleneck/tests/data/test_243_B +++ b/bottleneck/tests/data/test_243_B diff --git a/geom_bottleneck/tests/data/test_244_A b/bottleneck/tests/data/test_244_A index 1d1e4a7..1d1e4a7 100644 --- a/geom_bottleneck/tests/data/test_244_A +++ b/bottleneck/tests/data/test_244_A diff --git a/geom_bottleneck/tests/data/test_244_B b/bottleneck/tests/data/test_244_B index 5d9748f..5d9748f 100644 --- a/geom_bottleneck/tests/data/test_244_B +++ b/bottleneck/tests/data/test_244_B diff --git a/geom_bottleneck/tests/data/test_245_A b/bottleneck/tests/data/test_245_A index f17d580..f17d580 100644 --- a/geom_bottleneck/tests/data/test_245_A +++ b/bottleneck/tests/data/test_245_A diff --git a/geom_bottleneck/tests/data/test_245_B b/bottleneck/tests/data/test_245_B index 4b67caa..4b67caa 100644 --- a/geom_bottleneck/tests/data/test_245_B +++ b/bottleneck/tests/data/test_245_B diff --git a/geom_bottleneck/tests/data/test_246_A b/bottleneck/tests/data/test_246_A index b4ddade..b4ddade 100644 --- a/geom_bottleneck/tests/data/test_246_A +++ b/bottleneck/tests/data/test_246_A diff --git a/geom_bottleneck/tests/data/test_246_B b/bottleneck/tests/data/test_246_B index 6e0c12d..6e0c12d 100644 --- a/geom_bottleneck/tests/data/test_246_B +++ b/bottleneck/tests/data/test_246_B diff --git a/geom_bottleneck/tests/data/test_247_A b/bottleneck/tests/data/test_247_A index 4832963..4832963 100644 --- a/geom_bottleneck/tests/data/test_247_A +++ b/bottleneck/tests/data/test_247_A diff --git a/geom_bottleneck/tests/data/test_247_B b/bottleneck/tests/data/test_247_B index 17cc1f0..17cc1f0 100644 --- a/geom_bottleneck/tests/data/test_247_B +++ b/bottleneck/tests/data/test_247_B diff --git a/geom_bottleneck/tests/data/test_248_A b/bottleneck/tests/data/test_248_A index adbf3d6..adbf3d6 100644 --- a/geom_bottleneck/tests/data/test_248_A +++ b/bottleneck/tests/data/test_248_A diff --git a/geom_bottleneck/tests/data/test_248_B b/bottleneck/tests/data/test_248_B index 39ee264..39ee264 100644 --- a/geom_bottleneck/tests/data/test_248_B +++ b/bottleneck/tests/data/test_248_B diff --git a/geom_bottleneck/tests/data/test_249_A b/bottleneck/tests/data/test_249_A index 2b8a639..2b8a639 100644 --- a/geom_bottleneck/tests/data/test_249_A +++ b/bottleneck/tests/data/test_249_A diff --git a/geom_bottleneck/tests/data/test_249_B b/bottleneck/tests/data/test_249_B index 06b036c..06b036c 100644 --- a/geom_bottleneck/tests/data/test_249_B +++ b/bottleneck/tests/data/test_249_B diff --git a/geom_bottleneck/tests/data/test_250_A b/bottleneck/tests/data/test_250_A index 6934dd8..6934dd8 100644 --- a/geom_bottleneck/tests/data/test_250_A +++ b/bottleneck/tests/data/test_250_A diff --git a/geom_bottleneck/tests/data/test_250_B b/bottleneck/tests/data/test_250_B index 0d387ac..0d387ac 100644 --- a/geom_bottleneck/tests/data/test_250_B +++ b/bottleneck/tests/data/test_250_B diff --git a/geom_bottleneck/tests/data/test_251_A b/bottleneck/tests/data/test_251_A index 6fb7509..6fb7509 100644 --- a/geom_bottleneck/tests/data/test_251_A +++ b/bottleneck/tests/data/test_251_A diff --git a/geom_bottleneck/tests/data/test_251_B b/bottleneck/tests/data/test_251_B index 4ea7b4a..4ea7b4a 100644 --- a/geom_bottleneck/tests/data/test_251_B +++ b/bottleneck/tests/data/test_251_B diff --git a/geom_bottleneck/tests/data/test_252_A b/bottleneck/tests/data/test_252_A index 0076fb9..0076fb9 100644 --- a/geom_bottleneck/tests/data/test_252_A +++ b/bottleneck/tests/data/test_252_A diff --git a/geom_bottleneck/tests/data/test_252_B b/bottleneck/tests/data/test_252_B index cf7fab7..cf7fab7 100644 --- a/geom_bottleneck/tests/data/test_252_B +++ b/bottleneck/tests/data/test_252_B diff --git a/geom_bottleneck/tests/data/test_253_A b/bottleneck/tests/data/test_253_A index 0916538..0916538 100644 --- a/geom_bottleneck/tests/data/test_253_A +++ b/bottleneck/tests/data/test_253_A diff --git a/geom_bottleneck/tests/data/test_253_B b/bottleneck/tests/data/test_253_B index 3ee1874..3ee1874 100644 --- a/geom_bottleneck/tests/data/test_253_B +++ b/bottleneck/tests/data/test_253_B diff --git a/geom_bottleneck/tests/data/test_254_A b/bottleneck/tests/data/test_254_A index 85af9cb..85af9cb 100644 --- a/geom_bottleneck/tests/data/test_254_A +++ b/bottleneck/tests/data/test_254_A diff --git a/geom_bottleneck/tests/data/test_254_B b/bottleneck/tests/data/test_254_B index 573f5c5..573f5c5 100644 --- a/geom_bottleneck/tests/data/test_254_B +++ b/bottleneck/tests/data/test_254_B diff --git a/geom_bottleneck/tests/data/test_255_A b/bottleneck/tests/data/test_255_A index 2fc0a84..2fc0a84 100644 --- a/geom_bottleneck/tests/data/test_255_A +++ b/bottleneck/tests/data/test_255_A diff --git a/geom_bottleneck/tests/data/test_255_B b/bottleneck/tests/data/test_255_B index 04e0521..04e0521 100644 --- a/geom_bottleneck/tests/data/test_255_B +++ b/bottleneck/tests/data/test_255_B diff --git a/geom_bottleneck/tests/data/test_256_A b/bottleneck/tests/data/test_256_A index bb1df33..bb1df33 100644 --- a/geom_bottleneck/tests/data/test_256_A +++ b/bottleneck/tests/data/test_256_A diff --git a/geom_bottleneck/tests/data/test_256_B b/bottleneck/tests/data/test_256_B index a9bb2f8..a9bb2f8 100644 --- a/geom_bottleneck/tests/data/test_256_B +++ b/bottleneck/tests/data/test_256_B diff --git a/geom_bottleneck/tests/data/test_257_A b/bottleneck/tests/data/test_257_A index ac06787..ac06787 100644 --- a/geom_bottleneck/tests/data/test_257_A +++ b/bottleneck/tests/data/test_257_A diff --git a/geom_bottleneck/tests/data/test_257_B b/bottleneck/tests/data/test_257_B index 93ab86c..93ab86c 100644 --- a/geom_bottleneck/tests/data/test_257_B +++ b/bottleneck/tests/data/test_257_B diff --git a/geom_bottleneck/tests/data/test_258_A b/bottleneck/tests/data/test_258_A index b00d4c3..b00d4c3 100644 --- a/geom_bottleneck/tests/data/test_258_A +++ b/bottleneck/tests/data/test_258_A diff --git a/geom_bottleneck/tests/data/test_258_B b/bottleneck/tests/data/test_258_B index f3ab79e..f3ab79e 100644 --- a/geom_bottleneck/tests/data/test_258_B +++ b/bottleneck/tests/data/test_258_B diff --git a/geom_bottleneck/tests/data/test_259_A b/bottleneck/tests/data/test_259_A index 30c4a56..30c4a56 100644 --- a/geom_bottleneck/tests/data/test_259_A +++ b/bottleneck/tests/data/test_259_A diff --git a/geom_bottleneck/tests/data/test_259_B b/bottleneck/tests/data/test_259_B index 8cb51f7..8cb51f7 100644 --- a/geom_bottleneck/tests/data/test_259_B +++ b/bottleneck/tests/data/test_259_B diff --git a/geom_bottleneck/tests/data/test_260_A b/bottleneck/tests/data/test_260_A index 83740c1..83740c1 100644 --- a/geom_bottleneck/tests/data/test_260_A +++ b/bottleneck/tests/data/test_260_A diff --git a/geom_bottleneck/tests/data/test_260_B b/bottleneck/tests/data/test_260_B index 18e1128..18e1128 100644 --- a/geom_bottleneck/tests/data/test_260_B +++ b/bottleneck/tests/data/test_260_B diff --git a/geom_bottleneck/tests/data/test_261_A b/bottleneck/tests/data/test_261_A index 259e18a..259e18a 100644 --- a/geom_bottleneck/tests/data/test_261_A +++ b/bottleneck/tests/data/test_261_A diff --git a/geom_bottleneck/tests/data/test_261_B b/bottleneck/tests/data/test_261_B index 2be943f..2be943f 100644 --- a/geom_bottleneck/tests/data/test_261_B +++ b/bottleneck/tests/data/test_261_B diff --git a/geom_bottleneck/tests/data/test_262_A b/bottleneck/tests/data/test_262_A index ccb706b..ccb706b 100644 --- a/geom_bottleneck/tests/data/test_262_A +++ b/bottleneck/tests/data/test_262_A diff --git a/geom_bottleneck/tests/data/test_262_B b/bottleneck/tests/data/test_262_B index 944d288..944d288 100644 --- a/geom_bottleneck/tests/data/test_262_B +++ b/bottleneck/tests/data/test_262_B diff --git a/geom_bottleneck/tests/data/test_263_A b/bottleneck/tests/data/test_263_A index 6262062..6262062 100644 --- a/geom_bottleneck/tests/data/test_263_A +++ b/bottleneck/tests/data/test_263_A diff --git a/geom_bottleneck/tests/data/test_263_B b/bottleneck/tests/data/test_263_B index c9f8716..c9f8716 100644 --- a/geom_bottleneck/tests/data/test_263_B +++ b/bottleneck/tests/data/test_263_B diff --git a/geom_bottleneck/tests/data/test_264_A b/bottleneck/tests/data/test_264_A index 8c79b6d..8c79b6d 100644 --- a/geom_bottleneck/tests/data/test_264_A +++ b/bottleneck/tests/data/test_264_A diff --git a/geom_bottleneck/tests/data/test_264_B b/bottleneck/tests/data/test_264_B index 9b92607..9b92607 100644 --- a/geom_bottleneck/tests/data/test_264_B +++ b/bottleneck/tests/data/test_264_B diff --git a/geom_bottleneck/tests/data/test_265_A b/bottleneck/tests/data/test_265_A index 4de3ff9..4de3ff9 100644 --- a/geom_bottleneck/tests/data/test_265_A +++ b/bottleneck/tests/data/test_265_A diff --git a/geom_bottleneck/tests/data/test_265_B b/bottleneck/tests/data/test_265_B index f03f49f..f03f49f 100644 --- a/geom_bottleneck/tests/data/test_265_B +++ b/bottleneck/tests/data/test_265_B diff --git a/geom_bottleneck/tests/data/test_266_A b/bottleneck/tests/data/test_266_A index 95754d3..95754d3 100644 --- a/geom_bottleneck/tests/data/test_266_A +++ b/bottleneck/tests/data/test_266_A diff --git a/geom_bottleneck/tests/data/test_266_B b/bottleneck/tests/data/test_266_B index 5a2d560..5a2d560 100644 --- a/geom_bottleneck/tests/data/test_266_B +++ b/bottleneck/tests/data/test_266_B diff --git a/geom_bottleneck/tests/data/test_267_A b/bottleneck/tests/data/test_267_A index d2c663e..d2c663e 100644 --- a/geom_bottleneck/tests/data/test_267_A +++ b/bottleneck/tests/data/test_267_A diff --git a/geom_bottleneck/tests/data/test_267_B b/bottleneck/tests/data/test_267_B index aebae2b..aebae2b 100644 --- a/geom_bottleneck/tests/data/test_267_B +++ b/bottleneck/tests/data/test_267_B diff --git a/geom_bottleneck/tests/data/test_268_A b/bottleneck/tests/data/test_268_A index d0e9835..d0e9835 100644 --- a/geom_bottleneck/tests/data/test_268_A +++ b/bottleneck/tests/data/test_268_A diff --git a/geom_bottleneck/tests/data/test_268_B b/bottleneck/tests/data/test_268_B index ac0c242..ac0c242 100644 --- a/geom_bottleneck/tests/data/test_268_B +++ b/bottleneck/tests/data/test_268_B diff --git a/geom_bottleneck/tests/data/test_269_A b/bottleneck/tests/data/test_269_A index 62a1a47..62a1a47 100644 --- a/geom_bottleneck/tests/data/test_269_A +++ b/bottleneck/tests/data/test_269_A diff --git a/geom_bottleneck/tests/data/test_269_B b/bottleneck/tests/data/test_269_B index ecf44f6..ecf44f6 100644 --- a/geom_bottleneck/tests/data/test_269_B +++ b/bottleneck/tests/data/test_269_B diff --git a/geom_bottleneck/tests/data/test_270_A b/bottleneck/tests/data/test_270_A index 6bd9f37..6bd9f37 100644 --- a/geom_bottleneck/tests/data/test_270_A +++ b/bottleneck/tests/data/test_270_A diff --git a/geom_bottleneck/tests/data/test_270_B b/bottleneck/tests/data/test_270_B index 5e177c7..5e177c7 100644 --- a/geom_bottleneck/tests/data/test_270_B +++ b/bottleneck/tests/data/test_270_B diff --git a/geom_bottleneck/tests/data/test_271_A b/bottleneck/tests/data/test_271_A index 12f7492..12f7492 100644 --- a/geom_bottleneck/tests/data/test_271_A +++ b/bottleneck/tests/data/test_271_A diff --git a/geom_bottleneck/tests/data/test_271_B b/bottleneck/tests/data/test_271_B index 1af6dd6..1af6dd6 100644 --- a/geom_bottleneck/tests/data/test_271_B +++ b/bottleneck/tests/data/test_271_B diff --git a/geom_bottleneck/tests/data/test_272_A b/bottleneck/tests/data/test_272_A index b6b67f0..b6b67f0 100644 --- a/geom_bottleneck/tests/data/test_272_A +++ b/bottleneck/tests/data/test_272_A diff --git a/geom_bottleneck/tests/data/test_272_B b/bottleneck/tests/data/test_272_B index 9b12c0e..9b12c0e 100644 --- a/geom_bottleneck/tests/data/test_272_B +++ b/bottleneck/tests/data/test_272_B diff --git a/geom_bottleneck/tests/data/test_273_A b/bottleneck/tests/data/test_273_A index 6ae8fde..6ae8fde 100644 --- a/geom_bottleneck/tests/data/test_273_A +++ b/bottleneck/tests/data/test_273_A diff --git a/geom_bottleneck/tests/data/test_273_B b/bottleneck/tests/data/test_273_B index 42955e8..42955e8 100644 --- a/geom_bottleneck/tests/data/test_273_B +++ b/bottleneck/tests/data/test_273_B diff --git a/geom_bottleneck/tests/data/test_274_A b/bottleneck/tests/data/test_274_A index 78e099d..78e099d 100644 --- a/geom_bottleneck/tests/data/test_274_A +++ b/bottleneck/tests/data/test_274_A diff --git a/geom_bottleneck/tests/data/test_274_B b/bottleneck/tests/data/test_274_B index 59cac0c..59cac0c 100644 --- a/geom_bottleneck/tests/data/test_274_B +++ b/bottleneck/tests/data/test_274_B diff --git a/geom_bottleneck/tests/data/test_275_A b/bottleneck/tests/data/test_275_A index 9593ad1..9593ad1 100644 --- a/geom_bottleneck/tests/data/test_275_A +++ b/bottleneck/tests/data/test_275_A diff --git a/geom_bottleneck/tests/data/test_275_B b/bottleneck/tests/data/test_275_B index 46d793b..46d793b 100644 --- a/geom_bottleneck/tests/data/test_275_B +++ b/bottleneck/tests/data/test_275_B diff --git a/geom_bottleneck/tests/data/test_276_A b/bottleneck/tests/data/test_276_A index 546a9ad..546a9ad 100644 --- a/geom_bottleneck/tests/data/test_276_A +++ b/bottleneck/tests/data/test_276_A diff --git a/geom_bottleneck/tests/data/test_276_B b/bottleneck/tests/data/test_276_B index 3b63537..3b63537 100644 --- a/geom_bottleneck/tests/data/test_276_B +++ b/bottleneck/tests/data/test_276_B diff --git a/geom_bottleneck/tests/data/test_277_A b/bottleneck/tests/data/test_277_A index 41ee575..41ee575 100644 --- a/geom_bottleneck/tests/data/test_277_A +++ b/bottleneck/tests/data/test_277_A diff --git a/geom_bottleneck/tests/data/test_277_B b/bottleneck/tests/data/test_277_B index 84ade69..84ade69 100644 --- a/geom_bottleneck/tests/data/test_277_B +++ b/bottleneck/tests/data/test_277_B diff --git a/geom_bottleneck/tests/data/test_278_A b/bottleneck/tests/data/test_278_A index d2e3a7a..d2e3a7a 100644 --- a/geom_bottleneck/tests/data/test_278_A +++ b/bottleneck/tests/data/test_278_A diff --git a/geom_bottleneck/tests/data/test_278_B b/bottleneck/tests/data/test_278_B index 0046a8a..0046a8a 100644 --- a/geom_bottleneck/tests/data/test_278_B +++ b/bottleneck/tests/data/test_278_B diff --git a/geom_bottleneck/tests/data/test_279_A b/bottleneck/tests/data/test_279_A index 4e5619f..4e5619f 100644 --- a/geom_bottleneck/tests/data/test_279_A +++ b/bottleneck/tests/data/test_279_A diff --git a/geom_bottleneck/tests/data/test_279_B b/bottleneck/tests/data/test_279_B index 7ae40fa..7ae40fa 100644 --- a/geom_bottleneck/tests/data/test_279_B +++ b/bottleneck/tests/data/test_279_B diff --git a/geom_bottleneck/tests/data/test_280_A b/bottleneck/tests/data/test_280_A index 3ac2922..3ac2922 100644 --- a/geom_bottleneck/tests/data/test_280_A +++ b/bottleneck/tests/data/test_280_A diff --git a/geom_bottleneck/tests/data/test_280_B b/bottleneck/tests/data/test_280_B index c5485cf..c5485cf 100644 --- a/geom_bottleneck/tests/data/test_280_B +++ b/bottleneck/tests/data/test_280_B diff --git a/geom_bottleneck/tests/data/test_281_A b/bottleneck/tests/data/test_281_A index e9a4644..e9a4644 100644 --- a/geom_bottleneck/tests/data/test_281_A +++ b/bottleneck/tests/data/test_281_A diff --git a/geom_bottleneck/tests/data/test_281_B b/bottleneck/tests/data/test_281_B index f219b2a..f219b2a 100644 --- a/geom_bottleneck/tests/data/test_281_B +++ b/bottleneck/tests/data/test_281_B diff --git a/geom_bottleneck/tests/data/test_282_A b/bottleneck/tests/data/test_282_A index 946f3f2..946f3f2 100644 --- a/geom_bottleneck/tests/data/test_282_A +++ b/bottleneck/tests/data/test_282_A diff --git a/geom_bottleneck/tests/data/test_282_B b/bottleneck/tests/data/test_282_B index ac3c7c8..ac3c7c8 100644 --- a/geom_bottleneck/tests/data/test_282_B +++ b/bottleneck/tests/data/test_282_B diff --git a/geom_bottleneck/tests/data/test_283_A b/bottleneck/tests/data/test_283_A index 0c4676e..0c4676e 100644 --- a/geom_bottleneck/tests/data/test_283_A +++ b/bottleneck/tests/data/test_283_A diff --git a/geom_bottleneck/tests/data/test_283_B b/bottleneck/tests/data/test_283_B index 23a83e7..23a83e7 100644 --- a/geom_bottleneck/tests/data/test_283_B +++ b/bottleneck/tests/data/test_283_B diff --git a/geom_bottleneck/tests/data/test_284_A b/bottleneck/tests/data/test_284_A index 4cec19a..4cec19a 100644 --- a/geom_bottleneck/tests/data/test_284_A +++ b/bottleneck/tests/data/test_284_A diff --git a/geom_bottleneck/tests/data/test_284_B b/bottleneck/tests/data/test_284_B index f09aa28..f09aa28 100644 --- a/geom_bottleneck/tests/data/test_284_B +++ b/bottleneck/tests/data/test_284_B diff --git a/geom_bottleneck/tests/data/test_285_A b/bottleneck/tests/data/test_285_A index 8e27a5a..8e27a5a 100644 --- a/geom_bottleneck/tests/data/test_285_A +++ b/bottleneck/tests/data/test_285_A diff --git a/geom_bottleneck/tests/data/test_285_B b/bottleneck/tests/data/test_285_B index 16a8754..16a8754 100644 --- a/geom_bottleneck/tests/data/test_285_B +++ b/bottleneck/tests/data/test_285_B diff --git a/geom_bottleneck/tests/data/test_286_A b/bottleneck/tests/data/test_286_A index f8083ac..f8083ac 100644 --- a/geom_bottleneck/tests/data/test_286_A +++ b/bottleneck/tests/data/test_286_A diff --git a/geom_bottleneck/tests/data/test_286_B b/bottleneck/tests/data/test_286_B index 6ba8e74..6ba8e74 100644 --- a/geom_bottleneck/tests/data/test_286_B +++ b/bottleneck/tests/data/test_286_B diff --git a/geom_bottleneck/tests/data/test_287_A b/bottleneck/tests/data/test_287_A index 5dd8f38..5dd8f38 100644 --- a/geom_bottleneck/tests/data/test_287_A +++ b/bottleneck/tests/data/test_287_A diff --git a/geom_bottleneck/tests/data/test_287_B b/bottleneck/tests/data/test_287_B index 6fff124..6fff124 100644 --- a/geom_bottleneck/tests/data/test_287_B +++ b/bottleneck/tests/data/test_287_B diff --git a/geom_bottleneck/tests/data/test_288_A b/bottleneck/tests/data/test_288_A index 567d877..567d877 100644 --- a/geom_bottleneck/tests/data/test_288_A +++ b/bottleneck/tests/data/test_288_A diff --git a/geom_bottleneck/tests/data/test_288_B b/bottleneck/tests/data/test_288_B index 1d50cf6..1d50cf6 100644 --- a/geom_bottleneck/tests/data/test_288_B +++ b/bottleneck/tests/data/test_288_B diff --git a/geom_bottleneck/tests/data/test_289_A b/bottleneck/tests/data/test_289_A index 39c74ff..39c74ff 100644 --- a/geom_bottleneck/tests/data/test_289_A +++ b/bottleneck/tests/data/test_289_A diff --git a/geom_bottleneck/tests/data/test_289_B b/bottleneck/tests/data/test_289_B index cb24888..cb24888 100644 --- a/geom_bottleneck/tests/data/test_289_B +++ b/bottleneck/tests/data/test_289_B diff --git a/geom_bottleneck/tests/data/test_290_A b/bottleneck/tests/data/test_290_A index 21e124b..21e124b 100644 --- a/geom_bottleneck/tests/data/test_290_A +++ b/bottleneck/tests/data/test_290_A diff --git a/geom_bottleneck/tests/data/test_290_B b/bottleneck/tests/data/test_290_B index d705f0e..d705f0e 100644 --- a/geom_bottleneck/tests/data/test_290_B +++ b/bottleneck/tests/data/test_290_B diff --git a/geom_bottleneck/tests/data/test_291_A b/bottleneck/tests/data/test_291_A index 0ba0226..0ba0226 100644 --- a/geom_bottleneck/tests/data/test_291_A +++ b/bottleneck/tests/data/test_291_A diff --git a/geom_bottleneck/tests/data/test_291_B b/bottleneck/tests/data/test_291_B index 1c933ef..1c933ef 100644 --- a/geom_bottleneck/tests/data/test_291_B +++ b/bottleneck/tests/data/test_291_B diff --git a/geom_bottleneck/tests/data/test_292_A b/bottleneck/tests/data/test_292_A index 1929d2e..1929d2e 100644 --- a/geom_bottleneck/tests/data/test_292_A +++ b/bottleneck/tests/data/test_292_A diff --git a/geom_bottleneck/tests/data/test_292_B b/bottleneck/tests/data/test_292_B index 305f8b8..305f8b8 100644 --- a/geom_bottleneck/tests/data/test_292_B +++ b/bottleneck/tests/data/test_292_B diff --git a/geom_bottleneck/tests/data/test_293_A b/bottleneck/tests/data/test_293_A index 752bd33..752bd33 100644 --- a/geom_bottleneck/tests/data/test_293_A +++ b/bottleneck/tests/data/test_293_A diff --git a/geom_bottleneck/tests/data/test_293_B b/bottleneck/tests/data/test_293_B index 6ce5afb..6ce5afb 100644 --- a/geom_bottleneck/tests/data/test_293_B +++ b/bottleneck/tests/data/test_293_B diff --git a/geom_bottleneck/tests/data/test_294_A b/bottleneck/tests/data/test_294_A index 556a43e..556a43e 100644 --- a/geom_bottleneck/tests/data/test_294_A +++ b/bottleneck/tests/data/test_294_A diff --git a/geom_bottleneck/tests/data/test_294_B b/bottleneck/tests/data/test_294_B index 5a0896c..5a0896c 100644 --- a/geom_bottleneck/tests/data/test_294_B +++ b/bottleneck/tests/data/test_294_B diff --git a/geom_bottleneck/tests/data/test_295_A b/bottleneck/tests/data/test_295_A index 53b904f..53b904f 100644 --- a/geom_bottleneck/tests/data/test_295_A +++ b/bottleneck/tests/data/test_295_A diff --git a/geom_bottleneck/tests/data/test_295_B b/bottleneck/tests/data/test_295_B index 61d13ff..61d13ff 100644 --- a/geom_bottleneck/tests/data/test_295_B +++ b/bottleneck/tests/data/test_295_B diff --git a/geom_bottleneck/tests/data/test_296_A b/bottleneck/tests/data/test_296_A index 444d20f..444d20f 100644 --- a/geom_bottleneck/tests/data/test_296_A +++ b/bottleneck/tests/data/test_296_A diff --git a/geom_bottleneck/tests/data/test_296_B b/bottleneck/tests/data/test_296_B index 476d729..476d729 100644 --- a/geom_bottleneck/tests/data/test_296_B +++ b/bottleneck/tests/data/test_296_B diff --git a/geom_bottleneck/tests/data/test_297_A b/bottleneck/tests/data/test_297_A index 745d7f6..745d7f6 100644 --- a/geom_bottleneck/tests/data/test_297_A +++ b/bottleneck/tests/data/test_297_A diff --git a/geom_bottleneck/tests/data/test_297_B b/bottleneck/tests/data/test_297_B index 99b1ccc..99b1ccc 100644 --- a/geom_bottleneck/tests/data/test_297_B +++ b/bottleneck/tests/data/test_297_B diff --git a/geom_bottleneck/tests/data/test_298_A b/bottleneck/tests/data/test_298_A index d35fccc..d35fccc 100644 --- a/geom_bottleneck/tests/data/test_298_A +++ b/bottleneck/tests/data/test_298_A diff --git a/geom_bottleneck/tests/data/test_298_B b/bottleneck/tests/data/test_298_B index 5cf0d1c..5cf0d1c 100644 --- a/geom_bottleneck/tests/data/test_298_B +++ b/bottleneck/tests/data/test_298_B diff --git a/geom_bottleneck/tests/data/test_299_A b/bottleneck/tests/data/test_299_A index 3506828..3506828 100644 --- a/geom_bottleneck/tests/data/test_299_A +++ b/bottleneck/tests/data/test_299_A diff --git a/geom_bottleneck/tests/data/test_299_B b/bottleneck/tests/data/test_299_B index 3600634..3600634 100644 --- a/geom_bottleneck/tests/data/test_299_B +++ b/bottleneck/tests/data/test_299_B diff --git a/geom_bottleneck/tests/data/test_300_A b/bottleneck/tests/data/test_300_A index 2ab4a1e..2ab4a1e 100644 --- a/geom_bottleneck/tests/data/test_300_A +++ b/bottleneck/tests/data/test_300_A diff --git a/geom_bottleneck/tests/data/test_300_B b/bottleneck/tests/data/test_300_B index a54300d..a54300d 100644 --- a/geom_bottleneck/tests/data/test_300_B +++ b/bottleneck/tests/data/test_300_B diff --git a/geom_bottleneck/tests/data/test_301_A b/bottleneck/tests/data/test_301_A index 85f8ae5..85f8ae5 100644 --- a/geom_bottleneck/tests/data/test_301_A +++ b/bottleneck/tests/data/test_301_A diff --git a/geom_bottleneck/tests/data/test_301_B b/bottleneck/tests/data/test_301_B index 4d9ef19..4d9ef19 100644 --- a/geom_bottleneck/tests/data/test_301_B +++ b/bottleneck/tests/data/test_301_B diff --git a/geom_bottleneck/tests/data/test_302_A b/bottleneck/tests/data/test_302_A index be0e810..be0e810 100644 --- a/geom_bottleneck/tests/data/test_302_A +++ b/bottleneck/tests/data/test_302_A diff --git a/geom_bottleneck/tests/data/test_302_B b/bottleneck/tests/data/test_302_B index 38806fc..38806fc 100644 --- a/geom_bottleneck/tests/data/test_302_B +++ b/bottleneck/tests/data/test_302_B diff --git a/geom_bottleneck/tests/data/test_303_A b/bottleneck/tests/data/test_303_A index b277929..b277929 100644 --- a/geom_bottleneck/tests/data/test_303_A +++ b/bottleneck/tests/data/test_303_A diff --git a/geom_bottleneck/tests/data/test_303_B b/bottleneck/tests/data/test_303_B index 2cff171..2cff171 100644 --- a/geom_bottleneck/tests/data/test_303_B +++ b/bottleneck/tests/data/test_303_B diff --git a/geom_bottleneck/tests/data/test_304_A b/bottleneck/tests/data/test_304_A index 2c3de43..2c3de43 100644 --- a/geom_bottleneck/tests/data/test_304_A +++ b/bottleneck/tests/data/test_304_A diff --git a/geom_bottleneck/tests/data/test_304_B b/bottleneck/tests/data/test_304_B index 24402f6..24402f6 100644 --- a/geom_bottleneck/tests/data/test_304_B +++ b/bottleneck/tests/data/test_304_B diff --git a/geom_bottleneck/tests/data/test_305_A b/bottleneck/tests/data/test_305_A index aa88ed8..aa88ed8 100644 --- a/geom_bottleneck/tests/data/test_305_A +++ b/bottleneck/tests/data/test_305_A diff --git a/geom_bottleneck/tests/data/test_305_B b/bottleneck/tests/data/test_305_B index 8edd827..8edd827 100644 --- a/geom_bottleneck/tests/data/test_305_B +++ b/bottleneck/tests/data/test_305_B diff --git a/geom_bottleneck/tests/data/test_306_A b/bottleneck/tests/data/test_306_A index 8baa725..8baa725 100644 --- a/geom_bottleneck/tests/data/test_306_A +++ b/bottleneck/tests/data/test_306_A diff --git a/geom_bottleneck/tests/data/test_306_B b/bottleneck/tests/data/test_306_B index b33f874..b33f874 100644 --- a/geom_bottleneck/tests/data/test_306_B +++ b/bottleneck/tests/data/test_306_B diff --git a/geom_bottleneck/tests/data/test_307_A b/bottleneck/tests/data/test_307_A index bce4bc1..bce4bc1 100644 --- a/geom_bottleneck/tests/data/test_307_A +++ b/bottleneck/tests/data/test_307_A diff --git a/geom_bottleneck/tests/data/test_307_B b/bottleneck/tests/data/test_307_B index fd4fcb5..fd4fcb5 100644 --- a/geom_bottleneck/tests/data/test_307_B +++ b/bottleneck/tests/data/test_307_B diff --git a/geom_bottleneck/tests/data/test_308_A b/bottleneck/tests/data/test_308_A index 55ab2aa..55ab2aa 100644 --- a/geom_bottleneck/tests/data/test_308_A +++ b/bottleneck/tests/data/test_308_A diff --git a/geom_bottleneck/tests/data/test_308_B b/bottleneck/tests/data/test_308_B index cdf0c84..cdf0c84 100644 --- a/geom_bottleneck/tests/data/test_308_B +++ b/bottleneck/tests/data/test_308_B diff --git a/geom_bottleneck/tests/data/test_309_A b/bottleneck/tests/data/test_309_A index 20cee09..20cee09 100644 --- a/geom_bottleneck/tests/data/test_309_A +++ b/bottleneck/tests/data/test_309_A diff --git a/geom_bottleneck/tests/data/test_309_B b/bottleneck/tests/data/test_309_B index 86fe46e..86fe46e 100644 --- a/geom_bottleneck/tests/data/test_309_B +++ b/bottleneck/tests/data/test_309_B diff --git a/geom_bottleneck/tests/data/test_310_A b/bottleneck/tests/data/test_310_A index 320f176..320f176 100644 --- a/geom_bottleneck/tests/data/test_310_A +++ b/bottleneck/tests/data/test_310_A diff --git a/geom_bottleneck/tests/data/test_310_B b/bottleneck/tests/data/test_310_B index 3bcf21c..3bcf21c 100644 --- a/geom_bottleneck/tests/data/test_310_B +++ b/bottleneck/tests/data/test_310_B diff --git a/geom_bottleneck/tests/data/test_311_A b/bottleneck/tests/data/test_311_A index d98eb28..d98eb28 100644 --- a/geom_bottleneck/tests/data/test_311_A +++ b/bottleneck/tests/data/test_311_A diff --git a/geom_bottleneck/tests/data/test_311_B b/bottleneck/tests/data/test_311_B index 311ede4..311ede4 100644 --- a/geom_bottleneck/tests/data/test_311_B +++ b/bottleneck/tests/data/test_311_B diff --git a/geom_bottleneck/tests/data/test_312_A b/bottleneck/tests/data/test_312_A index 2745003..2745003 100644 --- a/geom_bottleneck/tests/data/test_312_A +++ b/bottleneck/tests/data/test_312_A diff --git a/geom_bottleneck/tests/data/test_312_B b/bottleneck/tests/data/test_312_B index 4a7645b..4a7645b 100644 --- a/geom_bottleneck/tests/data/test_312_B +++ b/bottleneck/tests/data/test_312_B diff --git a/geom_bottleneck/tests/data/test_313_A b/bottleneck/tests/data/test_313_A index db46821..db46821 100644 --- a/geom_bottleneck/tests/data/test_313_A +++ b/bottleneck/tests/data/test_313_A diff --git a/geom_bottleneck/tests/data/test_313_B b/bottleneck/tests/data/test_313_B index d387050..d387050 100644 --- a/geom_bottleneck/tests/data/test_313_B +++ b/bottleneck/tests/data/test_313_B diff --git a/geom_bottleneck/tests/data/test_314_A b/bottleneck/tests/data/test_314_A index 03ad5db..03ad5db 100644 --- a/geom_bottleneck/tests/data/test_314_A +++ b/bottleneck/tests/data/test_314_A diff --git a/geom_bottleneck/tests/data/test_314_B b/bottleneck/tests/data/test_314_B index eaa46d9..eaa46d9 100644 --- a/geom_bottleneck/tests/data/test_314_B +++ b/bottleneck/tests/data/test_314_B diff --git a/geom_bottleneck/tests/data/test_315_A b/bottleneck/tests/data/test_315_A index fa49507..fa49507 100644 --- a/geom_bottleneck/tests/data/test_315_A +++ b/bottleneck/tests/data/test_315_A diff --git a/geom_bottleneck/tests/data/test_315_B b/bottleneck/tests/data/test_315_B index d5390e2..d5390e2 100644 --- a/geom_bottleneck/tests/data/test_315_B +++ b/bottleneck/tests/data/test_315_B diff --git a/geom_bottleneck/tests/data/test_316_A b/bottleneck/tests/data/test_316_A index 57ff91f..57ff91f 100644 --- a/geom_bottleneck/tests/data/test_316_A +++ b/bottleneck/tests/data/test_316_A diff --git a/geom_bottleneck/tests/data/test_316_B b/bottleneck/tests/data/test_316_B index 407332e..407332e 100644 --- a/geom_bottleneck/tests/data/test_316_B +++ b/bottleneck/tests/data/test_316_B diff --git a/geom_bottleneck/tests/data/test_317_A b/bottleneck/tests/data/test_317_A index 4b6204e..4b6204e 100644 --- a/geom_bottleneck/tests/data/test_317_A +++ b/bottleneck/tests/data/test_317_A diff --git a/geom_bottleneck/tests/data/test_317_B b/bottleneck/tests/data/test_317_B index b30729a..b30729a 100644 --- a/geom_bottleneck/tests/data/test_317_B +++ b/bottleneck/tests/data/test_317_B diff --git a/geom_bottleneck/tests/data/test_318_A b/bottleneck/tests/data/test_318_A index 2ea4ad5..2ea4ad5 100644 --- a/geom_bottleneck/tests/data/test_318_A +++ b/bottleneck/tests/data/test_318_A diff --git a/geom_bottleneck/tests/data/test_318_B b/bottleneck/tests/data/test_318_B index 64fd49d..64fd49d 100644 --- a/geom_bottleneck/tests/data/test_318_B +++ b/bottleneck/tests/data/test_318_B diff --git a/geom_bottleneck/tests/data/test_319_A b/bottleneck/tests/data/test_319_A index f7ffeda..f7ffeda 100644 --- a/geom_bottleneck/tests/data/test_319_A +++ b/bottleneck/tests/data/test_319_A diff --git a/geom_bottleneck/tests/data/test_319_B b/bottleneck/tests/data/test_319_B index 5529fa0..5529fa0 100644 --- a/geom_bottleneck/tests/data/test_319_B +++ b/bottleneck/tests/data/test_319_B diff --git a/geom_bottleneck/tests/data/test_320_A b/bottleneck/tests/data/test_320_A index c7c7380..c7c7380 100644 --- a/geom_bottleneck/tests/data/test_320_A +++ b/bottleneck/tests/data/test_320_A diff --git a/geom_bottleneck/tests/data/test_320_B b/bottleneck/tests/data/test_320_B index 2807b27..2807b27 100644 --- a/geom_bottleneck/tests/data/test_320_B +++ b/bottleneck/tests/data/test_320_B diff --git a/geom_bottleneck/tests/data/test_321_A b/bottleneck/tests/data/test_321_A index b24cee9..b24cee9 100644 --- a/geom_bottleneck/tests/data/test_321_A +++ b/bottleneck/tests/data/test_321_A diff --git a/geom_bottleneck/tests/data/test_321_B b/bottleneck/tests/data/test_321_B index be6f00b..be6f00b 100644 --- a/geom_bottleneck/tests/data/test_321_B +++ b/bottleneck/tests/data/test_321_B diff --git a/geom_bottleneck/tests/data/test_322_A b/bottleneck/tests/data/test_322_A index 18eed8e..18eed8e 100644 --- a/geom_bottleneck/tests/data/test_322_A +++ b/bottleneck/tests/data/test_322_A diff --git a/geom_bottleneck/tests/data/test_322_B b/bottleneck/tests/data/test_322_B index f829c84..f829c84 100644 --- a/geom_bottleneck/tests/data/test_322_B +++ b/bottleneck/tests/data/test_322_B diff --git a/geom_bottleneck/tests/data/test_323_A b/bottleneck/tests/data/test_323_A index c452dff..c452dff 100644 --- a/geom_bottleneck/tests/data/test_323_A +++ b/bottleneck/tests/data/test_323_A diff --git a/geom_bottleneck/tests/data/test_323_B b/bottleneck/tests/data/test_323_B index 4a7c144..4a7c144 100644 --- a/geom_bottleneck/tests/data/test_323_B +++ b/bottleneck/tests/data/test_323_B diff --git a/geom_bottleneck/tests/data/test_324_A b/bottleneck/tests/data/test_324_A index 330da65..330da65 100644 --- a/geom_bottleneck/tests/data/test_324_A +++ b/bottleneck/tests/data/test_324_A diff --git a/geom_bottleneck/tests/data/test_324_B b/bottleneck/tests/data/test_324_B index 4fb3fef..4fb3fef 100644 --- a/geom_bottleneck/tests/data/test_324_B +++ b/bottleneck/tests/data/test_324_B diff --git a/geom_bottleneck/tests/data/test_325_A b/bottleneck/tests/data/test_325_A index 0e38bad..0e38bad 100644 --- a/geom_bottleneck/tests/data/test_325_A +++ b/bottleneck/tests/data/test_325_A diff --git a/geom_bottleneck/tests/data/test_325_B b/bottleneck/tests/data/test_325_B index 807bb12..807bb12 100644 --- a/geom_bottleneck/tests/data/test_325_B +++ b/bottleneck/tests/data/test_325_B diff --git a/geom_bottleneck/tests/data/test_326_A b/bottleneck/tests/data/test_326_A index 2cb897b..2cb897b 100644 --- a/geom_bottleneck/tests/data/test_326_A +++ b/bottleneck/tests/data/test_326_A diff --git a/geom_bottleneck/tests/data/test_326_B b/bottleneck/tests/data/test_326_B index 6b37e39..6b37e39 100644 --- a/geom_bottleneck/tests/data/test_326_B +++ b/bottleneck/tests/data/test_326_B diff --git a/geom_bottleneck/tests/data/test_327_A b/bottleneck/tests/data/test_327_A index 0d54292..0d54292 100644 --- a/geom_bottleneck/tests/data/test_327_A +++ b/bottleneck/tests/data/test_327_A diff --git a/geom_bottleneck/tests/data/test_327_B b/bottleneck/tests/data/test_327_B index 548eb3f..548eb3f 100644 --- a/geom_bottleneck/tests/data/test_327_B +++ b/bottleneck/tests/data/test_327_B diff --git a/geom_bottleneck/tests/data/test_328_A b/bottleneck/tests/data/test_328_A index 810b747..810b747 100644 --- a/geom_bottleneck/tests/data/test_328_A +++ b/bottleneck/tests/data/test_328_A diff --git a/geom_bottleneck/tests/data/test_328_B b/bottleneck/tests/data/test_328_B index e781d51..e781d51 100644 --- a/geom_bottleneck/tests/data/test_328_B +++ b/bottleneck/tests/data/test_328_B diff --git a/geom_bottleneck/tests/data/test_329_A b/bottleneck/tests/data/test_329_A index b02fd14..b02fd14 100644 --- a/geom_bottleneck/tests/data/test_329_A +++ b/bottleneck/tests/data/test_329_A diff --git a/geom_bottleneck/tests/data/test_329_B b/bottleneck/tests/data/test_329_B index 0ca3fcd..0ca3fcd 100644 --- a/geom_bottleneck/tests/data/test_329_B +++ b/bottleneck/tests/data/test_329_B diff --git a/geom_bottleneck/tests/data/test_330_A b/bottleneck/tests/data/test_330_A index 4cdb2c9..4cdb2c9 100644 --- a/geom_bottleneck/tests/data/test_330_A +++ b/bottleneck/tests/data/test_330_A diff --git a/geom_bottleneck/tests/data/test_330_B b/bottleneck/tests/data/test_330_B index 01f1570..01f1570 100644 --- a/geom_bottleneck/tests/data/test_330_B +++ b/bottleneck/tests/data/test_330_B diff --git a/geom_bottleneck/tests/data/test_331_A b/bottleneck/tests/data/test_331_A index a271a66..a271a66 100644 --- a/geom_bottleneck/tests/data/test_331_A +++ b/bottleneck/tests/data/test_331_A diff --git a/geom_bottleneck/tests/data/test_331_B b/bottleneck/tests/data/test_331_B index 72a1a7b..72a1a7b 100644 --- a/geom_bottleneck/tests/data/test_331_B +++ b/bottleneck/tests/data/test_331_B diff --git a/geom_bottleneck/tests/data/test_332_A b/bottleneck/tests/data/test_332_A index c1e999a..c1e999a 100644 --- a/geom_bottleneck/tests/data/test_332_A +++ b/bottleneck/tests/data/test_332_A diff --git a/geom_bottleneck/tests/data/test_332_B b/bottleneck/tests/data/test_332_B index 1f4686e..1f4686e 100644 --- a/geom_bottleneck/tests/data/test_332_B +++ b/bottleneck/tests/data/test_332_B diff --git a/geom_bottleneck/tests/data/test_333_A b/bottleneck/tests/data/test_333_A index c1cc126..c1cc126 100644 --- a/geom_bottleneck/tests/data/test_333_A +++ b/bottleneck/tests/data/test_333_A diff --git a/geom_bottleneck/tests/data/test_333_B b/bottleneck/tests/data/test_333_B index fd22364..fd22364 100644 --- a/geom_bottleneck/tests/data/test_333_B +++ b/bottleneck/tests/data/test_333_B diff --git a/geom_bottleneck/tests/data/test_334_A b/bottleneck/tests/data/test_334_A index 914d6c3..914d6c3 100644 --- a/geom_bottleneck/tests/data/test_334_A +++ b/bottleneck/tests/data/test_334_A diff --git a/geom_bottleneck/tests/data/test_334_B b/bottleneck/tests/data/test_334_B index 27524b9..27524b9 100644 --- a/geom_bottleneck/tests/data/test_334_B +++ b/bottleneck/tests/data/test_334_B diff --git a/geom_bottleneck/tests/data/test_335_A b/bottleneck/tests/data/test_335_A index 1a400bc..1a400bc 100644 --- a/geom_bottleneck/tests/data/test_335_A +++ b/bottleneck/tests/data/test_335_A diff --git a/geom_bottleneck/tests/data/test_335_B b/bottleneck/tests/data/test_335_B index 93c3211..93c3211 100644 --- a/geom_bottleneck/tests/data/test_335_B +++ b/bottleneck/tests/data/test_335_B diff --git a/geom_bottleneck/tests/data/test_336_A b/bottleneck/tests/data/test_336_A index 5410dc3..5410dc3 100644 --- a/geom_bottleneck/tests/data/test_336_A +++ b/bottleneck/tests/data/test_336_A diff --git a/geom_bottleneck/tests/data/test_336_B b/bottleneck/tests/data/test_336_B index 8b60a46..8b60a46 100644 --- a/geom_bottleneck/tests/data/test_336_B +++ b/bottleneck/tests/data/test_336_B diff --git a/geom_bottleneck/tests/data/test_337_A b/bottleneck/tests/data/test_337_A index 652b5f1..652b5f1 100644 --- a/geom_bottleneck/tests/data/test_337_A +++ b/bottleneck/tests/data/test_337_A diff --git a/geom_bottleneck/tests/data/test_337_B b/bottleneck/tests/data/test_337_B index eba21bc..eba21bc 100644 --- a/geom_bottleneck/tests/data/test_337_B +++ b/bottleneck/tests/data/test_337_B diff --git a/geom_bottleneck/tests/data/test_338_A b/bottleneck/tests/data/test_338_A index 567256f..567256f 100644 --- a/geom_bottleneck/tests/data/test_338_A +++ b/bottleneck/tests/data/test_338_A diff --git a/geom_bottleneck/tests/data/test_338_B b/bottleneck/tests/data/test_338_B index 82c3d80..82c3d80 100644 --- a/geom_bottleneck/tests/data/test_338_B +++ b/bottleneck/tests/data/test_338_B diff --git a/geom_bottleneck/tests/data/test_339_A b/bottleneck/tests/data/test_339_A index 9148a9c..9148a9c 100644 --- a/geom_bottleneck/tests/data/test_339_A +++ b/bottleneck/tests/data/test_339_A diff --git a/geom_bottleneck/tests/data/test_339_B b/bottleneck/tests/data/test_339_B index 385967f..385967f 100644 --- a/geom_bottleneck/tests/data/test_339_B +++ b/bottleneck/tests/data/test_339_B diff --git a/geom_bottleneck/tests/data/test_340_A b/bottleneck/tests/data/test_340_A index 4af25b1..4af25b1 100644 --- a/geom_bottleneck/tests/data/test_340_A +++ b/bottleneck/tests/data/test_340_A diff --git a/geom_bottleneck/tests/data/test_340_B b/bottleneck/tests/data/test_340_B index 0e3fa2a..0e3fa2a 100644 --- a/geom_bottleneck/tests/data/test_340_B +++ b/bottleneck/tests/data/test_340_B diff --git a/geom_bottleneck/tests/data/test_341_A b/bottleneck/tests/data/test_341_A index 932688b..932688b 100644 --- a/geom_bottleneck/tests/data/test_341_A +++ b/bottleneck/tests/data/test_341_A diff --git a/geom_bottleneck/tests/data/test_341_B b/bottleneck/tests/data/test_341_B index 68cc4b9..68cc4b9 100644 --- a/geom_bottleneck/tests/data/test_341_B +++ b/bottleneck/tests/data/test_341_B diff --git a/geom_bottleneck/tests/data/test_342_A b/bottleneck/tests/data/test_342_A index 04cdc19..04cdc19 100644 --- a/geom_bottleneck/tests/data/test_342_A +++ b/bottleneck/tests/data/test_342_A diff --git a/geom_bottleneck/tests/data/test_342_B b/bottleneck/tests/data/test_342_B index e6aae99..e6aae99 100644 --- a/geom_bottleneck/tests/data/test_342_B +++ b/bottleneck/tests/data/test_342_B diff --git a/geom_bottleneck/tests/data/test_343_A b/bottleneck/tests/data/test_343_A index 9759369..9759369 100644 --- a/geom_bottleneck/tests/data/test_343_A +++ b/bottleneck/tests/data/test_343_A diff --git a/geom_bottleneck/tests/data/test_343_B b/bottleneck/tests/data/test_343_B index e338ab2..e338ab2 100644 --- a/geom_bottleneck/tests/data/test_343_B +++ b/bottleneck/tests/data/test_343_B diff --git a/geom_bottleneck/tests/data/test_344_A b/bottleneck/tests/data/test_344_A index e8e81ab..e8e81ab 100644 --- a/geom_bottleneck/tests/data/test_344_A +++ b/bottleneck/tests/data/test_344_A diff --git a/geom_bottleneck/tests/data/test_344_B b/bottleneck/tests/data/test_344_B index af72be5..af72be5 100644 --- a/geom_bottleneck/tests/data/test_344_B +++ b/bottleneck/tests/data/test_344_B diff --git a/geom_bottleneck/tests/data/test_345_A b/bottleneck/tests/data/test_345_A index 584e4ed..584e4ed 100644 --- a/geom_bottleneck/tests/data/test_345_A +++ b/bottleneck/tests/data/test_345_A diff --git a/geom_bottleneck/tests/data/test_345_B b/bottleneck/tests/data/test_345_B index 8c3e758..8c3e758 100644 --- a/geom_bottleneck/tests/data/test_345_B +++ b/bottleneck/tests/data/test_345_B diff --git a/geom_bottleneck/tests/data/test_346_A b/bottleneck/tests/data/test_346_A index ab26e2f..ab26e2f 100644 --- a/geom_bottleneck/tests/data/test_346_A +++ b/bottleneck/tests/data/test_346_A diff --git a/geom_bottleneck/tests/data/test_346_B b/bottleneck/tests/data/test_346_B index 5e30972..5e30972 100644 --- a/geom_bottleneck/tests/data/test_346_B +++ b/bottleneck/tests/data/test_346_B diff --git a/geom_bottleneck/tests/data/test_347_A b/bottleneck/tests/data/test_347_A index 0cfd08b..0cfd08b 100644 --- a/geom_bottleneck/tests/data/test_347_A +++ b/bottleneck/tests/data/test_347_A diff --git a/geom_bottleneck/tests/data/test_347_B b/bottleneck/tests/data/test_347_B index 66d57ea..66d57ea 100644 --- a/geom_bottleneck/tests/data/test_347_B +++ b/bottleneck/tests/data/test_347_B diff --git a/geom_bottleneck/tests/data/test_348_A b/bottleneck/tests/data/test_348_A index 8cef3ff..8cef3ff 100644 --- a/geom_bottleneck/tests/data/test_348_A +++ b/bottleneck/tests/data/test_348_A diff --git a/geom_bottleneck/tests/data/test_348_B b/bottleneck/tests/data/test_348_B index 5db1829..5db1829 100644 --- a/geom_bottleneck/tests/data/test_348_B +++ b/bottleneck/tests/data/test_348_B diff --git a/geom_bottleneck/tests/data/test_349_A b/bottleneck/tests/data/test_349_A index a3d008e..a3d008e 100644 --- a/geom_bottleneck/tests/data/test_349_A +++ b/bottleneck/tests/data/test_349_A diff --git a/geom_bottleneck/tests/data/test_349_B b/bottleneck/tests/data/test_349_B index d66b5eb..d66b5eb 100644 --- a/geom_bottleneck/tests/data/test_349_B +++ b/bottleneck/tests/data/test_349_B diff --git a/geom_bottleneck/tests/data/test_350_A b/bottleneck/tests/data/test_350_A index 734d037..734d037 100644 --- a/geom_bottleneck/tests/data/test_350_A +++ b/bottleneck/tests/data/test_350_A diff --git a/geom_bottleneck/tests/data/test_350_B b/bottleneck/tests/data/test_350_B index 3cf03c4..3cf03c4 100644 --- a/geom_bottleneck/tests/data/test_350_B +++ b/bottleneck/tests/data/test_350_B diff --git a/geom_bottleneck/tests/data/test_351_A b/bottleneck/tests/data/test_351_A index 3989d6c..3989d6c 100644 --- a/geom_bottleneck/tests/data/test_351_A +++ b/bottleneck/tests/data/test_351_A diff --git a/geom_bottleneck/tests/data/test_351_B b/bottleneck/tests/data/test_351_B index b1c32d7..b1c32d7 100644 --- a/geom_bottleneck/tests/data/test_351_B +++ b/bottleneck/tests/data/test_351_B diff --git a/geom_bottleneck/tests/data/test_352_A b/bottleneck/tests/data/test_352_A index df81454..df81454 100644 --- a/geom_bottleneck/tests/data/test_352_A +++ b/bottleneck/tests/data/test_352_A diff --git a/geom_bottleneck/tests/data/test_352_B b/bottleneck/tests/data/test_352_B index 9b30bae..9b30bae 100644 --- a/geom_bottleneck/tests/data/test_352_B +++ b/bottleneck/tests/data/test_352_B diff --git a/geom_bottleneck/tests/data/test_353_A b/bottleneck/tests/data/test_353_A index 3dda9d1..3dda9d1 100644 --- a/geom_bottleneck/tests/data/test_353_A +++ b/bottleneck/tests/data/test_353_A diff --git a/geom_bottleneck/tests/data/test_353_B b/bottleneck/tests/data/test_353_B index 16ed654..16ed654 100644 --- a/geom_bottleneck/tests/data/test_353_B +++ b/bottleneck/tests/data/test_353_B diff --git a/geom_bottleneck/tests/data/test_354_A b/bottleneck/tests/data/test_354_A index c701ef2..c701ef2 100644 --- a/geom_bottleneck/tests/data/test_354_A +++ b/bottleneck/tests/data/test_354_A diff --git a/geom_bottleneck/tests/data/test_354_B b/bottleneck/tests/data/test_354_B index 0a21b24..0a21b24 100644 --- a/geom_bottleneck/tests/data/test_354_B +++ b/bottleneck/tests/data/test_354_B diff --git a/geom_bottleneck/tests/data/test_355_A b/bottleneck/tests/data/test_355_A index 48d49bd..48d49bd 100644 --- a/geom_bottleneck/tests/data/test_355_A +++ b/bottleneck/tests/data/test_355_A diff --git a/geom_bottleneck/tests/data/test_355_B b/bottleneck/tests/data/test_355_B index cd9cec5..cd9cec5 100644 --- a/geom_bottleneck/tests/data/test_355_B +++ b/bottleneck/tests/data/test_355_B diff --git a/geom_bottleneck/tests/data/test_356_A b/bottleneck/tests/data/test_356_A index cb92f38..cb92f38 100644 --- a/geom_bottleneck/tests/data/test_356_A +++ b/bottleneck/tests/data/test_356_A diff --git a/geom_bottleneck/tests/data/test_356_B b/bottleneck/tests/data/test_356_B index 365ed3f..365ed3f 100644 --- a/geom_bottleneck/tests/data/test_356_B +++ b/bottleneck/tests/data/test_356_B diff --git a/geom_bottleneck/tests/data/test_357_A b/bottleneck/tests/data/test_357_A index de1e8eb..de1e8eb 100644 --- a/geom_bottleneck/tests/data/test_357_A +++ b/bottleneck/tests/data/test_357_A diff --git a/geom_bottleneck/tests/data/test_357_B b/bottleneck/tests/data/test_357_B index 1c68b90..1c68b90 100644 --- a/geom_bottleneck/tests/data/test_357_B +++ b/bottleneck/tests/data/test_357_B diff --git a/geom_bottleneck/tests/data/test_358_A b/bottleneck/tests/data/test_358_A index 2297dae..2297dae 100644 --- a/geom_bottleneck/tests/data/test_358_A +++ b/bottleneck/tests/data/test_358_A diff --git a/geom_bottleneck/tests/data/test_358_B b/bottleneck/tests/data/test_358_B index e2d7d03..e2d7d03 100644 --- a/geom_bottleneck/tests/data/test_358_B +++ b/bottleneck/tests/data/test_358_B diff --git a/geom_bottleneck/tests/data/test_359_A b/bottleneck/tests/data/test_359_A index 6e990e4..6e990e4 100644 --- a/geom_bottleneck/tests/data/test_359_A +++ b/bottleneck/tests/data/test_359_A diff --git a/geom_bottleneck/tests/data/test_359_B b/bottleneck/tests/data/test_359_B index 97c1bfe..97c1bfe 100644 --- a/geom_bottleneck/tests/data/test_359_B +++ b/bottleneck/tests/data/test_359_B diff --git a/geom_bottleneck/tests/data/test_360_A b/bottleneck/tests/data/test_360_A index d271aaa..d271aaa 100644 --- a/geom_bottleneck/tests/data/test_360_A +++ b/bottleneck/tests/data/test_360_A diff --git a/geom_bottleneck/tests/data/test_360_B b/bottleneck/tests/data/test_360_B index 2408922..2408922 100644 --- a/geom_bottleneck/tests/data/test_360_B +++ b/bottleneck/tests/data/test_360_B diff --git a/geom_bottleneck/tests/data/test_361_A b/bottleneck/tests/data/test_361_A index b4eea74..b4eea74 100644 --- a/geom_bottleneck/tests/data/test_361_A +++ b/bottleneck/tests/data/test_361_A diff --git a/geom_bottleneck/tests/data/test_361_B b/bottleneck/tests/data/test_361_B index 3680b00..3680b00 100644 --- a/geom_bottleneck/tests/data/test_361_B +++ b/bottleneck/tests/data/test_361_B diff --git a/geom_bottleneck/tests/data/test_362_A b/bottleneck/tests/data/test_362_A index 1c4803d..1c4803d 100644 --- a/geom_bottleneck/tests/data/test_362_A +++ b/bottleneck/tests/data/test_362_A diff --git a/geom_bottleneck/tests/data/test_362_B b/bottleneck/tests/data/test_362_B index 37fc7aa..37fc7aa 100644 --- a/geom_bottleneck/tests/data/test_362_B +++ b/bottleneck/tests/data/test_362_B diff --git a/geom_bottleneck/tests/data/test_363_A b/bottleneck/tests/data/test_363_A index 909ac51..909ac51 100644 --- a/geom_bottleneck/tests/data/test_363_A +++ b/bottleneck/tests/data/test_363_A diff --git a/geom_bottleneck/tests/data/test_363_B b/bottleneck/tests/data/test_363_B index 4c76429..4c76429 100644 --- a/geom_bottleneck/tests/data/test_363_B +++ b/bottleneck/tests/data/test_363_B diff --git a/geom_bottleneck/tests/data/test_364_A b/bottleneck/tests/data/test_364_A index a6e34b7..a6e34b7 100644 --- a/geom_bottleneck/tests/data/test_364_A +++ b/bottleneck/tests/data/test_364_A diff --git a/geom_bottleneck/tests/data/test_364_B b/bottleneck/tests/data/test_364_B index ba5c4bf..ba5c4bf 100644 --- a/geom_bottleneck/tests/data/test_364_B +++ b/bottleneck/tests/data/test_364_B diff --git a/geom_bottleneck/tests/data/test_365_A b/bottleneck/tests/data/test_365_A index 6c9d44c..6c9d44c 100644 --- a/geom_bottleneck/tests/data/test_365_A +++ b/bottleneck/tests/data/test_365_A diff --git a/geom_bottleneck/tests/data/test_365_B b/bottleneck/tests/data/test_365_B index f9e51a7..f9e51a7 100644 --- a/geom_bottleneck/tests/data/test_365_B +++ b/bottleneck/tests/data/test_365_B diff --git a/geom_bottleneck/tests/data/test_366_A b/bottleneck/tests/data/test_366_A index fbf146c..fbf146c 100644 --- a/geom_bottleneck/tests/data/test_366_A +++ b/bottleneck/tests/data/test_366_A diff --git a/geom_bottleneck/tests/data/test_366_B b/bottleneck/tests/data/test_366_B index 7385b5f..7385b5f 100644 --- a/geom_bottleneck/tests/data/test_366_B +++ b/bottleneck/tests/data/test_366_B diff --git a/geom_bottleneck/tests/data/test_367_A b/bottleneck/tests/data/test_367_A index 48190bb..48190bb 100644 --- a/geom_bottleneck/tests/data/test_367_A +++ b/bottleneck/tests/data/test_367_A diff --git a/geom_bottleneck/tests/data/test_367_B b/bottleneck/tests/data/test_367_B index 7e26c08..7e26c08 100644 --- a/geom_bottleneck/tests/data/test_367_B +++ b/bottleneck/tests/data/test_367_B diff --git a/geom_bottleneck/tests/data/test_368_A b/bottleneck/tests/data/test_368_A index 4b4767d..4b4767d 100644 --- a/geom_bottleneck/tests/data/test_368_A +++ b/bottleneck/tests/data/test_368_A diff --git a/geom_bottleneck/tests/data/test_368_B b/bottleneck/tests/data/test_368_B index 3c72417..3c72417 100644 --- a/geom_bottleneck/tests/data/test_368_B +++ b/bottleneck/tests/data/test_368_B diff --git a/geom_bottleneck/tests/data/test_369_A b/bottleneck/tests/data/test_369_A index d8a01b6..d8a01b6 100644 --- a/geom_bottleneck/tests/data/test_369_A +++ b/bottleneck/tests/data/test_369_A diff --git a/geom_bottleneck/tests/data/test_369_B b/bottleneck/tests/data/test_369_B index 9f7da60..9f7da60 100644 --- a/geom_bottleneck/tests/data/test_369_B +++ b/bottleneck/tests/data/test_369_B diff --git a/geom_bottleneck/tests/data/test_370_A b/bottleneck/tests/data/test_370_A index bdc8979..bdc8979 100644 --- a/geom_bottleneck/tests/data/test_370_A +++ b/bottleneck/tests/data/test_370_A diff --git a/geom_bottleneck/tests/data/test_370_B b/bottleneck/tests/data/test_370_B index e145eb4..e145eb4 100644 --- a/geom_bottleneck/tests/data/test_370_B +++ b/bottleneck/tests/data/test_370_B diff --git a/geom_bottleneck/tests/data/test_371_A b/bottleneck/tests/data/test_371_A index 208a164..208a164 100644 --- a/geom_bottleneck/tests/data/test_371_A +++ b/bottleneck/tests/data/test_371_A diff --git a/geom_bottleneck/tests/data/test_371_B b/bottleneck/tests/data/test_371_B index 7a2fc8a..7a2fc8a 100644 --- a/geom_bottleneck/tests/data/test_371_B +++ b/bottleneck/tests/data/test_371_B diff --git a/geom_bottleneck/tests/data/test_372_A b/bottleneck/tests/data/test_372_A index dd3597a..dd3597a 100644 --- a/geom_bottleneck/tests/data/test_372_A +++ b/bottleneck/tests/data/test_372_A diff --git a/geom_bottleneck/tests/data/test_372_B b/bottleneck/tests/data/test_372_B index 225c36e..225c36e 100644 --- a/geom_bottleneck/tests/data/test_372_B +++ b/bottleneck/tests/data/test_372_B diff --git a/geom_bottleneck/tests/data/test_373_A b/bottleneck/tests/data/test_373_A index 0a84fd2..0a84fd2 100644 --- a/geom_bottleneck/tests/data/test_373_A +++ b/bottleneck/tests/data/test_373_A diff --git a/geom_bottleneck/tests/data/test_373_B b/bottleneck/tests/data/test_373_B index b790337..b790337 100644 --- a/geom_bottleneck/tests/data/test_373_B +++ b/bottleneck/tests/data/test_373_B diff --git a/geom_bottleneck/tests/data/test_374_A b/bottleneck/tests/data/test_374_A index 0df06a4..0df06a4 100644 --- a/geom_bottleneck/tests/data/test_374_A +++ b/bottleneck/tests/data/test_374_A diff --git a/geom_bottleneck/tests/data/test_374_B b/bottleneck/tests/data/test_374_B index 7bd1bdd..7bd1bdd 100644 --- a/geom_bottleneck/tests/data/test_374_B +++ b/bottleneck/tests/data/test_374_B diff --git a/geom_bottleneck/tests/data/test_375_A b/bottleneck/tests/data/test_375_A index 77cd274..77cd274 100644 --- a/geom_bottleneck/tests/data/test_375_A +++ b/bottleneck/tests/data/test_375_A diff --git a/geom_bottleneck/tests/data/test_375_B b/bottleneck/tests/data/test_375_B index db3c6ee..db3c6ee 100644 --- a/geom_bottleneck/tests/data/test_375_B +++ b/bottleneck/tests/data/test_375_B diff --git a/geom_bottleneck/tests/data/test_376_A b/bottleneck/tests/data/test_376_A index aca7402..aca7402 100644 --- a/geom_bottleneck/tests/data/test_376_A +++ b/bottleneck/tests/data/test_376_A diff --git a/geom_bottleneck/tests/data/test_376_B b/bottleneck/tests/data/test_376_B index 5bbae78..5bbae78 100644 --- a/geom_bottleneck/tests/data/test_376_B +++ b/bottleneck/tests/data/test_376_B diff --git a/geom_bottleneck/tests/data/test_377_A b/bottleneck/tests/data/test_377_A index 707adfd..707adfd 100644 --- a/geom_bottleneck/tests/data/test_377_A +++ b/bottleneck/tests/data/test_377_A diff --git a/geom_bottleneck/tests/data/test_377_B b/bottleneck/tests/data/test_377_B index afbe113..afbe113 100644 --- a/geom_bottleneck/tests/data/test_377_B +++ b/bottleneck/tests/data/test_377_B diff --git a/geom_bottleneck/tests/data/test_378_A b/bottleneck/tests/data/test_378_A index 7ac23e9..7ac23e9 100644 --- a/geom_bottleneck/tests/data/test_378_A +++ b/bottleneck/tests/data/test_378_A diff --git a/geom_bottleneck/tests/data/test_378_B b/bottleneck/tests/data/test_378_B index 328b726..328b726 100644 --- a/geom_bottleneck/tests/data/test_378_B +++ b/bottleneck/tests/data/test_378_B diff --git a/geom_bottleneck/tests/data/test_379_A b/bottleneck/tests/data/test_379_A index 0f57258..0f57258 100644 --- a/geom_bottleneck/tests/data/test_379_A +++ b/bottleneck/tests/data/test_379_A diff --git a/geom_bottleneck/tests/data/test_379_B b/bottleneck/tests/data/test_379_B index 45e35ba..45e35ba 100644 --- a/geom_bottleneck/tests/data/test_379_B +++ b/bottleneck/tests/data/test_379_B diff --git a/geom_bottleneck/tests/data/test_380_A b/bottleneck/tests/data/test_380_A index a6d1d31..a6d1d31 100644 --- a/geom_bottleneck/tests/data/test_380_A +++ b/bottleneck/tests/data/test_380_A diff --git a/geom_bottleneck/tests/data/test_380_B b/bottleneck/tests/data/test_380_B index 023f533..023f533 100644 --- a/geom_bottleneck/tests/data/test_380_B +++ b/bottleneck/tests/data/test_380_B diff --git a/geom_bottleneck/tests/data/test_381_A b/bottleneck/tests/data/test_381_A index 0b5985d..0b5985d 100644 --- a/geom_bottleneck/tests/data/test_381_A +++ b/bottleneck/tests/data/test_381_A diff --git a/geom_bottleneck/tests/data/test_381_B b/bottleneck/tests/data/test_381_B index 1f5ffef..1f5ffef 100644 --- a/geom_bottleneck/tests/data/test_381_B +++ b/bottleneck/tests/data/test_381_B diff --git a/geom_bottleneck/tests/data/test_382_A b/bottleneck/tests/data/test_382_A index e155629..e155629 100644 --- a/geom_bottleneck/tests/data/test_382_A +++ b/bottleneck/tests/data/test_382_A diff --git a/geom_bottleneck/tests/data/test_382_B b/bottleneck/tests/data/test_382_B index 5273c5f..5273c5f 100644 --- a/geom_bottleneck/tests/data/test_382_B +++ b/bottleneck/tests/data/test_382_B diff --git a/geom_bottleneck/tests/data/test_383_A b/bottleneck/tests/data/test_383_A index 7579cf6..7579cf6 100644 --- a/geom_bottleneck/tests/data/test_383_A +++ b/bottleneck/tests/data/test_383_A diff --git a/geom_bottleneck/tests/data/test_383_B b/bottleneck/tests/data/test_383_B index 050e76d..050e76d 100644 --- a/geom_bottleneck/tests/data/test_383_B +++ b/bottleneck/tests/data/test_383_B diff --git a/geom_bottleneck/tests/data/test_384_A b/bottleneck/tests/data/test_384_A index 5ba83b2..5ba83b2 100644 --- a/geom_bottleneck/tests/data/test_384_A +++ b/bottleneck/tests/data/test_384_A diff --git a/geom_bottleneck/tests/data/test_384_B b/bottleneck/tests/data/test_384_B index f1a0074..f1a0074 100644 --- a/geom_bottleneck/tests/data/test_384_B +++ b/bottleneck/tests/data/test_384_B diff --git a/geom_bottleneck/tests/data/test_385_A b/bottleneck/tests/data/test_385_A index 195db5d..195db5d 100644 --- a/geom_bottleneck/tests/data/test_385_A +++ b/bottleneck/tests/data/test_385_A diff --git a/geom_bottleneck/tests/data/test_385_B b/bottleneck/tests/data/test_385_B index 9234688..9234688 100644 --- a/geom_bottleneck/tests/data/test_385_B +++ b/bottleneck/tests/data/test_385_B diff --git a/geom_bottleneck/tests/data/test_386_A b/bottleneck/tests/data/test_386_A index 7a9281c..7a9281c 100644 --- a/geom_bottleneck/tests/data/test_386_A +++ b/bottleneck/tests/data/test_386_A diff --git a/geom_bottleneck/tests/data/test_386_B b/bottleneck/tests/data/test_386_B index 86a3caf..86a3caf 100644 --- a/geom_bottleneck/tests/data/test_386_B +++ b/bottleneck/tests/data/test_386_B diff --git a/geom_bottleneck/tests/data/test_387_A b/bottleneck/tests/data/test_387_A index ff92400..ff92400 100644 --- a/geom_bottleneck/tests/data/test_387_A +++ b/bottleneck/tests/data/test_387_A diff --git a/geom_bottleneck/tests/data/test_387_B b/bottleneck/tests/data/test_387_B index c2e44a4..c2e44a4 100644 --- a/geom_bottleneck/tests/data/test_387_B +++ b/bottleneck/tests/data/test_387_B diff --git a/geom_bottleneck/tests/data/test_388_A b/bottleneck/tests/data/test_388_A index 62b75be..62b75be 100644 --- a/geom_bottleneck/tests/data/test_388_A +++ b/bottleneck/tests/data/test_388_A diff --git a/geom_bottleneck/tests/data/test_388_B b/bottleneck/tests/data/test_388_B index 025fdc6..025fdc6 100644 --- a/geom_bottleneck/tests/data/test_388_B +++ b/bottleneck/tests/data/test_388_B diff --git a/geom_bottleneck/tests/data/test_389_A b/bottleneck/tests/data/test_389_A index 5fa0b26..5fa0b26 100644 --- a/geom_bottleneck/tests/data/test_389_A +++ b/bottleneck/tests/data/test_389_A diff --git a/geom_bottleneck/tests/data/test_389_B b/bottleneck/tests/data/test_389_B index 7ebd7f3..7ebd7f3 100644 --- a/geom_bottleneck/tests/data/test_389_B +++ b/bottleneck/tests/data/test_389_B diff --git a/geom_bottleneck/tests/data/test_390_A b/bottleneck/tests/data/test_390_A index 9f2c33d..9f2c33d 100644 --- a/geom_bottleneck/tests/data/test_390_A +++ b/bottleneck/tests/data/test_390_A diff --git a/geom_bottleneck/tests/data/test_390_B b/bottleneck/tests/data/test_390_B index 833af00..833af00 100644 --- a/geom_bottleneck/tests/data/test_390_B +++ b/bottleneck/tests/data/test_390_B diff --git a/geom_bottleneck/tests/data/test_391_A b/bottleneck/tests/data/test_391_A index f353fda..f353fda 100644 --- a/geom_bottleneck/tests/data/test_391_A +++ b/bottleneck/tests/data/test_391_A diff --git a/geom_bottleneck/tests/data/test_391_B b/bottleneck/tests/data/test_391_B index edff01f..edff01f 100644 --- a/geom_bottleneck/tests/data/test_391_B +++ b/bottleneck/tests/data/test_391_B diff --git a/geom_bottleneck/tests/data/test_392_A b/bottleneck/tests/data/test_392_A index 317da32..317da32 100644 --- a/geom_bottleneck/tests/data/test_392_A +++ b/bottleneck/tests/data/test_392_A diff --git a/geom_bottleneck/tests/data/test_392_B b/bottleneck/tests/data/test_392_B index c8cb61c..c8cb61c 100644 --- a/geom_bottleneck/tests/data/test_392_B +++ b/bottleneck/tests/data/test_392_B diff --git a/geom_bottleneck/tests/data/test_393_A b/bottleneck/tests/data/test_393_A index 10b537c..10b537c 100644 --- a/geom_bottleneck/tests/data/test_393_A +++ b/bottleneck/tests/data/test_393_A diff --git a/geom_bottleneck/tests/data/test_393_B b/bottleneck/tests/data/test_393_B index 24bc23a..24bc23a 100644 --- a/geom_bottleneck/tests/data/test_393_B +++ b/bottleneck/tests/data/test_393_B diff --git a/geom_bottleneck/tests/data/test_394_A b/bottleneck/tests/data/test_394_A index e626e4a..e626e4a 100644 --- a/geom_bottleneck/tests/data/test_394_A +++ b/bottleneck/tests/data/test_394_A diff --git a/geom_bottleneck/tests/data/test_394_B b/bottleneck/tests/data/test_394_B index 24e086f..24e086f 100644 --- a/geom_bottleneck/tests/data/test_394_B +++ b/bottleneck/tests/data/test_394_B diff --git a/geom_bottleneck/tests/data/test_395_A b/bottleneck/tests/data/test_395_A index fa5d9e1..fa5d9e1 100644 --- a/geom_bottleneck/tests/data/test_395_A +++ b/bottleneck/tests/data/test_395_A diff --git a/geom_bottleneck/tests/data/test_395_B b/bottleneck/tests/data/test_395_B index 8cc1049..8cc1049 100644 --- a/geom_bottleneck/tests/data/test_395_B +++ b/bottleneck/tests/data/test_395_B diff --git a/geom_bottleneck/tests/data/test_396_A b/bottleneck/tests/data/test_396_A index ab2ac42..ab2ac42 100644 --- a/geom_bottleneck/tests/data/test_396_A +++ b/bottleneck/tests/data/test_396_A diff --git a/geom_bottleneck/tests/data/test_396_B b/bottleneck/tests/data/test_396_B index dd8a3d4..dd8a3d4 100644 --- a/geom_bottleneck/tests/data/test_396_B +++ b/bottleneck/tests/data/test_396_B diff --git a/geom_bottleneck/tests/data/test_397_A b/bottleneck/tests/data/test_397_A index 683bdca..683bdca 100644 --- a/geom_bottleneck/tests/data/test_397_A +++ b/bottleneck/tests/data/test_397_A diff --git a/geom_bottleneck/tests/data/test_397_B b/bottleneck/tests/data/test_397_B index a7b2d72..a7b2d72 100644 --- a/geom_bottleneck/tests/data/test_397_B +++ b/bottleneck/tests/data/test_397_B diff --git a/geom_bottleneck/tests/data/test_398_A b/bottleneck/tests/data/test_398_A index d802d50..d802d50 100644 --- a/geom_bottleneck/tests/data/test_398_A +++ b/bottleneck/tests/data/test_398_A diff --git a/geom_bottleneck/tests/data/test_398_B b/bottleneck/tests/data/test_398_B index 9e5b5e1..9e5b5e1 100644 --- a/geom_bottleneck/tests/data/test_398_B +++ b/bottleneck/tests/data/test_398_B diff --git a/geom_bottleneck/tests/data/test_399_A b/bottleneck/tests/data/test_399_A index 204dfdf..204dfdf 100644 --- a/geom_bottleneck/tests/data/test_399_A +++ b/bottleneck/tests/data/test_399_A diff --git a/geom_bottleneck/tests/data/test_399_B b/bottleneck/tests/data/test_399_B index 58cb084..58cb084 100644 --- a/geom_bottleneck/tests/data/test_399_B +++ b/bottleneck/tests/data/test_399_B diff --git a/geom_bottleneck/tests/data/test_400_A b/bottleneck/tests/data/test_400_A index b867cf5..b867cf5 100644 --- a/geom_bottleneck/tests/data/test_400_A +++ b/bottleneck/tests/data/test_400_A diff --git a/geom_bottleneck/tests/data/test_400_B b/bottleneck/tests/data/test_400_B index 18df91d..18df91d 100644 --- a/geom_bottleneck/tests/data/test_400_B +++ b/bottleneck/tests/data/test_400_B diff --git a/geom_bottleneck/tests/data/test_401_A b/bottleneck/tests/data/test_401_A index 0f03308..0f03308 100644 --- a/geom_bottleneck/tests/data/test_401_A +++ b/bottleneck/tests/data/test_401_A diff --git a/geom_bottleneck/tests/data/test_401_B b/bottleneck/tests/data/test_401_B index b517be8..b517be8 100644 --- a/geom_bottleneck/tests/data/test_401_B +++ b/bottleneck/tests/data/test_401_B diff --git a/geom_bottleneck/tests/data/test_402_A b/bottleneck/tests/data/test_402_A index 6a6f79f..6a6f79f 100644 --- a/geom_bottleneck/tests/data/test_402_A +++ b/bottleneck/tests/data/test_402_A diff --git a/geom_bottleneck/tests/data/test_402_B b/bottleneck/tests/data/test_402_B index 6585f2b..6585f2b 100644 --- a/geom_bottleneck/tests/data/test_402_B +++ b/bottleneck/tests/data/test_402_B diff --git a/geom_bottleneck/tests/data/test_403_A b/bottleneck/tests/data/test_403_A index 8b5929a..8b5929a 100644 --- a/geom_bottleneck/tests/data/test_403_A +++ b/bottleneck/tests/data/test_403_A diff --git a/geom_bottleneck/tests/data/test_403_B b/bottleneck/tests/data/test_403_B index 71f089f..71f089f 100644 --- a/geom_bottleneck/tests/data/test_403_B +++ b/bottleneck/tests/data/test_403_B diff --git a/geom_bottleneck/tests/data/test_404_A b/bottleneck/tests/data/test_404_A index 10add8e..10add8e 100644 --- a/geom_bottleneck/tests/data/test_404_A +++ b/bottleneck/tests/data/test_404_A diff --git a/geom_bottleneck/tests/data/test_404_B b/bottleneck/tests/data/test_404_B index b38a7a7..b38a7a7 100644 --- a/geom_bottleneck/tests/data/test_404_B +++ b/bottleneck/tests/data/test_404_B diff --git a/geom_bottleneck/tests/data/test_405_A b/bottleneck/tests/data/test_405_A index 6cab1bd..6cab1bd 100644 --- a/geom_bottleneck/tests/data/test_405_A +++ b/bottleneck/tests/data/test_405_A diff --git a/geom_bottleneck/tests/data/test_405_B b/bottleneck/tests/data/test_405_B index 96645aa..96645aa 100644 --- a/geom_bottleneck/tests/data/test_405_B +++ b/bottleneck/tests/data/test_405_B diff --git a/geom_bottleneck/tests/data/test_406_A b/bottleneck/tests/data/test_406_A index cf08c48..cf08c48 100644 --- a/geom_bottleneck/tests/data/test_406_A +++ b/bottleneck/tests/data/test_406_A diff --git a/geom_bottleneck/tests/data/test_406_B b/bottleneck/tests/data/test_406_B index b4ca0a0..b4ca0a0 100644 --- a/geom_bottleneck/tests/data/test_406_B +++ b/bottleneck/tests/data/test_406_B diff --git a/geom_bottleneck/tests/data/test_407_A b/bottleneck/tests/data/test_407_A index 2372aba..2372aba 100644 --- a/geom_bottleneck/tests/data/test_407_A +++ b/bottleneck/tests/data/test_407_A diff --git a/geom_bottleneck/tests/data/test_407_B b/bottleneck/tests/data/test_407_B index bd43334..bd43334 100644 --- a/geom_bottleneck/tests/data/test_407_B +++ b/bottleneck/tests/data/test_407_B diff --git a/geom_bottleneck/tests/data/test_408_A b/bottleneck/tests/data/test_408_A index 91652d4..91652d4 100644 --- a/geom_bottleneck/tests/data/test_408_A +++ b/bottleneck/tests/data/test_408_A diff --git a/geom_bottleneck/tests/data/test_408_B b/bottleneck/tests/data/test_408_B index 5f936a7..5f936a7 100644 --- a/geom_bottleneck/tests/data/test_408_B +++ b/bottleneck/tests/data/test_408_B diff --git a/geom_bottleneck/tests/data/test_409_A b/bottleneck/tests/data/test_409_A index b4d01d2..b4d01d2 100644 --- a/geom_bottleneck/tests/data/test_409_A +++ b/bottleneck/tests/data/test_409_A diff --git a/geom_bottleneck/tests/data/test_409_B b/bottleneck/tests/data/test_409_B index 4e15e41..4e15e41 100644 --- a/geom_bottleneck/tests/data/test_409_B +++ b/bottleneck/tests/data/test_409_B diff --git a/geom_bottleneck/tests/data/test_410_A b/bottleneck/tests/data/test_410_A index c02ab24..c02ab24 100644 --- a/geom_bottleneck/tests/data/test_410_A +++ b/bottleneck/tests/data/test_410_A diff --git a/geom_bottleneck/tests/data/test_410_B b/bottleneck/tests/data/test_410_B index d000095..d000095 100644 --- a/geom_bottleneck/tests/data/test_410_B +++ b/bottleneck/tests/data/test_410_B diff --git a/geom_bottleneck/tests/data/test_411_A b/bottleneck/tests/data/test_411_A index 8130c4a..8130c4a 100644 --- a/geom_bottleneck/tests/data/test_411_A +++ b/bottleneck/tests/data/test_411_A diff --git a/geom_bottleneck/tests/data/test_411_B b/bottleneck/tests/data/test_411_B index e53f61f..e53f61f 100644 --- a/geom_bottleneck/tests/data/test_411_B +++ b/bottleneck/tests/data/test_411_B diff --git a/geom_bottleneck/tests/data/test_412_A b/bottleneck/tests/data/test_412_A index 34a88b0..34a88b0 100644 --- a/geom_bottleneck/tests/data/test_412_A +++ b/bottleneck/tests/data/test_412_A diff --git a/geom_bottleneck/tests/data/test_412_B b/bottleneck/tests/data/test_412_B index a163ece..a163ece 100644 --- a/geom_bottleneck/tests/data/test_412_B +++ b/bottleneck/tests/data/test_412_B diff --git a/geom_bottleneck/tests/data/test_413_A b/bottleneck/tests/data/test_413_A index 61d6f70..61d6f70 100644 --- a/geom_bottleneck/tests/data/test_413_A +++ b/bottleneck/tests/data/test_413_A diff --git a/geom_bottleneck/tests/data/test_413_B b/bottleneck/tests/data/test_413_B index 5b9dc54..5b9dc54 100644 --- a/geom_bottleneck/tests/data/test_413_B +++ b/bottleneck/tests/data/test_413_B diff --git a/geom_bottleneck/tests/data/test_414_A b/bottleneck/tests/data/test_414_A index 933f1e4..933f1e4 100644 --- a/geom_bottleneck/tests/data/test_414_A +++ b/bottleneck/tests/data/test_414_A diff --git a/geom_bottleneck/tests/data/test_414_B b/bottleneck/tests/data/test_414_B index b54a5fe..b54a5fe 100644 --- a/geom_bottleneck/tests/data/test_414_B +++ b/bottleneck/tests/data/test_414_B diff --git a/geom_bottleneck/tests/data/test_415_A b/bottleneck/tests/data/test_415_A index bbce6b8..bbce6b8 100644 --- a/geom_bottleneck/tests/data/test_415_A +++ b/bottleneck/tests/data/test_415_A diff --git a/geom_bottleneck/tests/data/test_415_B b/bottleneck/tests/data/test_415_B index 3943a46..3943a46 100644 --- a/geom_bottleneck/tests/data/test_415_B +++ b/bottleneck/tests/data/test_415_B diff --git a/geom_bottleneck/tests/data/test_416_A b/bottleneck/tests/data/test_416_A index c7a9a3d..c7a9a3d 100644 --- a/geom_bottleneck/tests/data/test_416_A +++ b/bottleneck/tests/data/test_416_A diff --git a/geom_bottleneck/tests/data/test_416_B b/bottleneck/tests/data/test_416_B index 6e8c430..6e8c430 100644 --- a/geom_bottleneck/tests/data/test_416_B +++ b/bottleneck/tests/data/test_416_B diff --git a/geom_bottleneck/tests/data/test_417_A b/bottleneck/tests/data/test_417_A index 6e5688c..6e5688c 100644 --- a/geom_bottleneck/tests/data/test_417_A +++ b/bottleneck/tests/data/test_417_A diff --git a/geom_bottleneck/tests/data/test_417_B b/bottleneck/tests/data/test_417_B index 2bfa9c2..2bfa9c2 100644 --- a/geom_bottleneck/tests/data/test_417_B +++ b/bottleneck/tests/data/test_417_B diff --git a/geom_bottleneck/tests/data/test_418_A b/bottleneck/tests/data/test_418_A index 9ab98de..9ab98de 100644 --- a/geom_bottleneck/tests/data/test_418_A +++ b/bottleneck/tests/data/test_418_A diff --git a/geom_bottleneck/tests/data/test_418_B b/bottleneck/tests/data/test_418_B index f3231de..f3231de 100644 --- a/geom_bottleneck/tests/data/test_418_B +++ b/bottleneck/tests/data/test_418_B diff --git a/geom_bottleneck/tests/data/test_419_A b/bottleneck/tests/data/test_419_A index 825d191..825d191 100644 --- a/geom_bottleneck/tests/data/test_419_A +++ b/bottleneck/tests/data/test_419_A diff --git a/geom_bottleneck/tests/data/test_419_B b/bottleneck/tests/data/test_419_B index 101be4f..101be4f 100644 --- a/geom_bottleneck/tests/data/test_419_B +++ b/bottleneck/tests/data/test_419_B diff --git a/geom_bottleneck/tests/data/test_420_A b/bottleneck/tests/data/test_420_A index 455d829..455d829 100644 --- a/geom_bottleneck/tests/data/test_420_A +++ b/bottleneck/tests/data/test_420_A diff --git a/geom_bottleneck/tests/data/test_420_B b/bottleneck/tests/data/test_420_B index 27e1c6d..27e1c6d 100644 --- a/geom_bottleneck/tests/data/test_420_B +++ b/bottleneck/tests/data/test_420_B diff --git a/geom_bottleneck/tests/data/test_421_A b/bottleneck/tests/data/test_421_A index c08ddf1..c08ddf1 100644 --- a/geom_bottleneck/tests/data/test_421_A +++ b/bottleneck/tests/data/test_421_A diff --git a/geom_bottleneck/tests/data/test_421_B b/bottleneck/tests/data/test_421_B index 37cbda8..37cbda8 100644 --- a/geom_bottleneck/tests/data/test_421_B +++ b/bottleneck/tests/data/test_421_B diff --git a/geom_bottleneck/tests/data/test_422_A b/bottleneck/tests/data/test_422_A index 348a116..348a116 100644 --- a/geom_bottleneck/tests/data/test_422_A +++ b/bottleneck/tests/data/test_422_A diff --git a/geom_bottleneck/tests/data/test_422_B b/bottleneck/tests/data/test_422_B index 0f33ae9..0f33ae9 100644 --- a/geom_bottleneck/tests/data/test_422_B +++ b/bottleneck/tests/data/test_422_B diff --git a/geom_bottleneck/tests/data/test_423_A b/bottleneck/tests/data/test_423_A index b3b448e..b3b448e 100644 --- a/geom_bottleneck/tests/data/test_423_A +++ b/bottleneck/tests/data/test_423_A diff --git a/geom_bottleneck/tests/data/test_423_B b/bottleneck/tests/data/test_423_B index 873a875..873a875 100644 --- a/geom_bottleneck/tests/data/test_423_B +++ b/bottleneck/tests/data/test_423_B diff --git a/geom_bottleneck/tests/data/test_424_A b/bottleneck/tests/data/test_424_A index ab20fc1..ab20fc1 100644 --- a/geom_bottleneck/tests/data/test_424_A +++ b/bottleneck/tests/data/test_424_A diff --git a/geom_bottleneck/tests/data/test_424_B b/bottleneck/tests/data/test_424_B index a0f5059..a0f5059 100644 --- a/geom_bottleneck/tests/data/test_424_B +++ b/bottleneck/tests/data/test_424_B diff --git a/geom_bottleneck/tests/data/test_425_A b/bottleneck/tests/data/test_425_A index 7116974..7116974 100644 --- a/geom_bottleneck/tests/data/test_425_A +++ b/bottleneck/tests/data/test_425_A diff --git a/geom_bottleneck/tests/data/test_425_B b/bottleneck/tests/data/test_425_B index 6f1e713..6f1e713 100644 --- a/geom_bottleneck/tests/data/test_425_B +++ b/bottleneck/tests/data/test_425_B diff --git a/geom_bottleneck/tests/data/test_426_A b/bottleneck/tests/data/test_426_A index 6404cdd..6404cdd 100644 --- a/geom_bottleneck/tests/data/test_426_A +++ b/bottleneck/tests/data/test_426_A diff --git a/geom_bottleneck/tests/data/test_426_B b/bottleneck/tests/data/test_426_B index 06fbc21..06fbc21 100644 --- a/geom_bottleneck/tests/data/test_426_B +++ b/bottleneck/tests/data/test_426_B diff --git a/geom_bottleneck/tests/data/test_427_A b/bottleneck/tests/data/test_427_A index ab36b49..ab36b49 100644 --- a/geom_bottleneck/tests/data/test_427_A +++ b/bottleneck/tests/data/test_427_A diff --git a/geom_bottleneck/tests/data/test_427_B b/bottleneck/tests/data/test_427_B index eb34e17..eb34e17 100644 --- a/geom_bottleneck/tests/data/test_427_B +++ b/bottleneck/tests/data/test_427_B diff --git a/geom_bottleneck/tests/data/test_428_A b/bottleneck/tests/data/test_428_A index 12957ab..12957ab 100644 --- a/geom_bottleneck/tests/data/test_428_A +++ b/bottleneck/tests/data/test_428_A diff --git a/geom_bottleneck/tests/data/test_428_B b/bottleneck/tests/data/test_428_B index b0fd1c4..b0fd1c4 100644 --- a/geom_bottleneck/tests/data/test_428_B +++ b/bottleneck/tests/data/test_428_B diff --git a/geom_bottleneck/tests/data/test_429_A b/bottleneck/tests/data/test_429_A index 0cdda41..0cdda41 100644 --- a/geom_bottleneck/tests/data/test_429_A +++ b/bottleneck/tests/data/test_429_A diff --git a/geom_bottleneck/tests/data/test_429_B b/bottleneck/tests/data/test_429_B index 0180a92..0180a92 100644 --- a/geom_bottleneck/tests/data/test_429_B +++ b/bottleneck/tests/data/test_429_B diff --git a/geom_bottleneck/tests/data/test_430_A b/bottleneck/tests/data/test_430_A index 03029c6..03029c6 100644 --- a/geom_bottleneck/tests/data/test_430_A +++ b/bottleneck/tests/data/test_430_A diff --git a/geom_bottleneck/tests/data/test_430_B b/bottleneck/tests/data/test_430_B index 9c58f1f..9c58f1f 100644 --- a/geom_bottleneck/tests/data/test_430_B +++ b/bottleneck/tests/data/test_430_B diff --git a/geom_bottleneck/tests/data/test_431_A b/bottleneck/tests/data/test_431_A index 272ec7d..272ec7d 100644 --- a/geom_bottleneck/tests/data/test_431_A +++ b/bottleneck/tests/data/test_431_A diff --git a/geom_bottleneck/tests/data/test_431_B b/bottleneck/tests/data/test_431_B index 9ccc9d1..9ccc9d1 100644 --- a/geom_bottleneck/tests/data/test_431_B +++ b/bottleneck/tests/data/test_431_B diff --git a/geom_bottleneck/tests/data/test_432_A b/bottleneck/tests/data/test_432_A index 91dbacb..91dbacb 100644 --- a/geom_bottleneck/tests/data/test_432_A +++ b/bottleneck/tests/data/test_432_A diff --git a/geom_bottleneck/tests/data/test_432_B b/bottleneck/tests/data/test_432_B index 47afd85..47afd85 100644 --- a/geom_bottleneck/tests/data/test_432_B +++ b/bottleneck/tests/data/test_432_B diff --git a/geom_bottleneck/tests/data/test_433_A b/bottleneck/tests/data/test_433_A index 1577e13..1577e13 100644 --- a/geom_bottleneck/tests/data/test_433_A +++ b/bottleneck/tests/data/test_433_A diff --git a/geom_bottleneck/tests/data/test_433_B b/bottleneck/tests/data/test_433_B index f63aea0..f63aea0 100644 --- a/geom_bottleneck/tests/data/test_433_B +++ b/bottleneck/tests/data/test_433_B diff --git a/geom_bottleneck/tests/data/test_434_A b/bottleneck/tests/data/test_434_A index 5ef7655..5ef7655 100644 --- a/geom_bottleneck/tests/data/test_434_A +++ b/bottleneck/tests/data/test_434_A diff --git a/geom_bottleneck/tests/data/test_434_B b/bottleneck/tests/data/test_434_B index a089420..a089420 100644 --- a/geom_bottleneck/tests/data/test_434_B +++ b/bottleneck/tests/data/test_434_B diff --git a/geom_bottleneck/tests/data/test_435_A b/bottleneck/tests/data/test_435_A index 9021906..9021906 100644 --- a/geom_bottleneck/tests/data/test_435_A +++ b/bottleneck/tests/data/test_435_A diff --git a/geom_bottleneck/tests/data/test_435_B b/bottleneck/tests/data/test_435_B index 225d87c..225d87c 100644 --- a/geom_bottleneck/tests/data/test_435_B +++ b/bottleneck/tests/data/test_435_B diff --git a/geom_bottleneck/tests/data/test_436_A b/bottleneck/tests/data/test_436_A index 4004cfe..4004cfe 100644 --- a/geom_bottleneck/tests/data/test_436_A +++ b/bottleneck/tests/data/test_436_A diff --git a/geom_bottleneck/tests/data/test_436_B b/bottleneck/tests/data/test_436_B index 8fbd097..8fbd097 100644 --- a/geom_bottleneck/tests/data/test_436_B +++ b/bottleneck/tests/data/test_436_B diff --git a/geom_bottleneck/tests/data/test_437_A b/bottleneck/tests/data/test_437_A index 8210316..8210316 100644 --- a/geom_bottleneck/tests/data/test_437_A +++ b/bottleneck/tests/data/test_437_A diff --git a/geom_bottleneck/tests/data/test_437_B b/bottleneck/tests/data/test_437_B index c7e55b3..c7e55b3 100644 --- a/geom_bottleneck/tests/data/test_437_B +++ b/bottleneck/tests/data/test_437_B diff --git a/geom_bottleneck/tests/data/test_438_A b/bottleneck/tests/data/test_438_A index e2f48a4..e2f48a4 100644 --- a/geom_bottleneck/tests/data/test_438_A +++ b/bottleneck/tests/data/test_438_A diff --git a/geom_bottleneck/tests/data/test_438_B b/bottleneck/tests/data/test_438_B index eb84689..eb84689 100644 --- a/geom_bottleneck/tests/data/test_438_B +++ b/bottleneck/tests/data/test_438_B diff --git a/geom_bottleneck/tests/data/test_439_A b/bottleneck/tests/data/test_439_A index fc36518..fc36518 100644 --- a/geom_bottleneck/tests/data/test_439_A +++ b/bottleneck/tests/data/test_439_A diff --git a/geom_bottleneck/tests/data/test_439_B b/bottleneck/tests/data/test_439_B index b9de5b7..b9de5b7 100644 --- a/geom_bottleneck/tests/data/test_439_B +++ b/bottleneck/tests/data/test_439_B diff --git a/geom_bottleneck/tests/data/test_440_A b/bottleneck/tests/data/test_440_A index 4f0cdc2..4f0cdc2 100644 --- a/geom_bottleneck/tests/data/test_440_A +++ b/bottleneck/tests/data/test_440_A diff --git a/geom_bottleneck/tests/data/test_440_B b/bottleneck/tests/data/test_440_B index c06754e..c06754e 100644 --- a/geom_bottleneck/tests/data/test_440_B +++ b/bottleneck/tests/data/test_440_B diff --git a/geom_bottleneck/tests/data/test_441_A b/bottleneck/tests/data/test_441_A index f1d7779..f1d7779 100644 --- a/geom_bottleneck/tests/data/test_441_A +++ b/bottleneck/tests/data/test_441_A diff --git a/geom_bottleneck/tests/data/test_441_B b/bottleneck/tests/data/test_441_B index 039c8db..039c8db 100644 --- a/geom_bottleneck/tests/data/test_441_B +++ b/bottleneck/tests/data/test_441_B diff --git a/geom_bottleneck/tests/data/test_442_A b/bottleneck/tests/data/test_442_A index 9a22bd2..9a22bd2 100644 --- a/geom_bottleneck/tests/data/test_442_A +++ b/bottleneck/tests/data/test_442_A diff --git a/geom_bottleneck/tests/data/test_442_B b/bottleneck/tests/data/test_442_B index 9663228..9663228 100644 --- a/geom_bottleneck/tests/data/test_442_B +++ b/bottleneck/tests/data/test_442_B diff --git a/geom_bottleneck/tests/data/test_443_A b/bottleneck/tests/data/test_443_A index 27d9885..27d9885 100644 --- a/geom_bottleneck/tests/data/test_443_A +++ b/bottleneck/tests/data/test_443_A diff --git a/geom_bottleneck/tests/data/test_443_B b/bottleneck/tests/data/test_443_B index c084218..c084218 100644 --- a/geom_bottleneck/tests/data/test_443_B +++ b/bottleneck/tests/data/test_443_B diff --git a/geom_bottleneck/tests/data/test_444_A b/bottleneck/tests/data/test_444_A index 86dfb79..86dfb79 100644 --- a/geom_bottleneck/tests/data/test_444_A +++ b/bottleneck/tests/data/test_444_A diff --git a/geom_bottleneck/tests/data/test_444_B b/bottleneck/tests/data/test_444_B index b7f54f9..b7f54f9 100644 --- a/geom_bottleneck/tests/data/test_444_B +++ b/bottleneck/tests/data/test_444_B diff --git a/geom_bottleneck/tests/data/test_445_A b/bottleneck/tests/data/test_445_A index 6ec29f6..6ec29f6 100644 --- a/geom_bottleneck/tests/data/test_445_A +++ b/bottleneck/tests/data/test_445_A diff --git a/geom_bottleneck/tests/data/test_445_B b/bottleneck/tests/data/test_445_B index 7e5ce8e..7e5ce8e 100644 --- a/geom_bottleneck/tests/data/test_445_B +++ b/bottleneck/tests/data/test_445_B diff --git a/geom_bottleneck/tests/data/test_446_A b/bottleneck/tests/data/test_446_A index 2e66159..2e66159 100644 --- a/geom_bottleneck/tests/data/test_446_A +++ b/bottleneck/tests/data/test_446_A diff --git a/geom_bottleneck/tests/data/test_446_B b/bottleneck/tests/data/test_446_B index b4a4baa..b4a4baa 100644 --- a/geom_bottleneck/tests/data/test_446_B +++ b/bottleneck/tests/data/test_446_B diff --git a/geom_bottleneck/tests/data/test_447_A b/bottleneck/tests/data/test_447_A index adbca26..adbca26 100644 --- a/geom_bottleneck/tests/data/test_447_A +++ b/bottleneck/tests/data/test_447_A diff --git a/geom_bottleneck/tests/data/test_447_B b/bottleneck/tests/data/test_447_B index c996a99..c996a99 100644 --- a/geom_bottleneck/tests/data/test_447_B +++ b/bottleneck/tests/data/test_447_B diff --git a/geom_bottleneck/tests/data/test_448_A b/bottleneck/tests/data/test_448_A index 3b1d2ac..3b1d2ac 100644 --- a/geom_bottleneck/tests/data/test_448_A +++ b/bottleneck/tests/data/test_448_A diff --git a/geom_bottleneck/tests/data/test_448_B b/bottleneck/tests/data/test_448_B index 358c96b..358c96b 100644 --- a/geom_bottleneck/tests/data/test_448_B +++ b/bottleneck/tests/data/test_448_B diff --git a/geom_bottleneck/tests/data/test_449_A b/bottleneck/tests/data/test_449_A index 1b9fdde..1b9fdde 100644 --- a/geom_bottleneck/tests/data/test_449_A +++ b/bottleneck/tests/data/test_449_A diff --git a/geom_bottleneck/tests/data/test_449_B b/bottleneck/tests/data/test_449_B index 39ca7bf..39ca7bf 100644 --- a/geom_bottleneck/tests/data/test_449_B +++ b/bottleneck/tests/data/test_449_B diff --git a/geom_bottleneck/tests/data/test_450_A b/bottleneck/tests/data/test_450_A index c97d1bd..c97d1bd 100644 --- a/geom_bottleneck/tests/data/test_450_A +++ b/bottleneck/tests/data/test_450_A diff --git a/geom_bottleneck/tests/data/test_450_B b/bottleneck/tests/data/test_450_B index 038d497..038d497 100644 --- a/geom_bottleneck/tests/data/test_450_B +++ b/bottleneck/tests/data/test_450_B diff --git a/geom_bottleneck/tests/data/test_451_A b/bottleneck/tests/data/test_451_A index 1c77ff4..1c77ff4 100644 --- a/geom_bottleneck/tests/data/test_451_A +++ b/bottleneck/tests/data/test_451_A diff --git a/geom_bottleneck/tests/data/test_451_B b/bottleneck/tests/data/test_451_B index 37c9b78..37c9b78 100644 --- a/geom_bottleneck/tests/data/test_451_B +++ b/bottleneck/tests/data/test_451_B diff --git a/geom_bottleneck/tests/data/test_452_A b/bottleneck/tests/data/test_452_A index 24159ea..24159ea 100644 --- a/geom_bottleneck/tests/data/test_452_A +++ b/bottleneck/tests/data/test_452_A diff --git a/geom_bottleneck/tests/data/test_452_B b/bottleneck/tests/data/test_452_B index 602fb45..602fb45 100644 --- a/geom_bottleneck/tests/data/test_452_B +++ b/bottleneck/tests/data/test_452_B diff --git a/geom_bottleneck/tests/data/test_453_A b/bottleneck/tests/data/test_453_A index aa29541..aa29541 100644 --- a/geom_bottleneck/tests/data/test_453_A +++ b/bottleneck/tests/data/test_453_A diff --git a/geom_bottleneck/tests/data/test_453_B b/bottleneck/tests/data/test_453_B index 7cce047..7cce047 100644 --- a/geom_bottleneck/tests/data/test_453_B +++ b/bottleneck/tests/data/test_453_B diff --git a/geom_bottleneck/tests/data/test_454_A b/bottleneck/tests/data/test_454_A index 3e5e41b..3e5e41b 100644 --- a/geom_bottleneck/tests/data/test_454_A +++ b/bottleneck/tests/data/test_454_A diff --git a/geom_bottleneck/tests/data/test_454_B b/bottleneck/tests/data/test_454_B index e5e2305..e5e2305 100644 --- a/geom_bottleneck/tests/data/test_454_B +++ b/bottleneck/tests/data/test_454_B diff --git a/geom_bottleneck/tests/data/test_455_A b/bottleneck/tests/data/test_455_A index d06d256..d06d256 100644 --- a/geom_bottleneck/tests/data/test_455_A +++ b/bottleneck/tests/data/test_455_A diff --git a/geom_bottleneck/tests/data/test_455_B b/bottleneck/tests/data/test_455_B index afdab0b..afdab0b 100644 --- a/geom_bottleneck/tests/data/test_455_B +++ b/bottleneck/tests/data/test_455_B diff --git a/geom_bottleneck/tests/data/test_456_A b/bottleneck/tests/data/test_456_A index 7a30bf3..7a30bf3 100644 --- a/geom_bottleneck/tests/data/test_456_A +++ b/bottleneck/tests/data/test_456_A diff --git a/geom_bottleneck/tests/data/test_456_B b/bottleneck/tests/data/test_456_B index a1a1329..a1a1329 100644 --- a/geom_bottleneck/tests/data/test_456_B +++ b/bottleneck/tests/data/test_456_B diff --git a/geom_bottleneck/tests/data/test_457_A b/bottleneck/tests/data/test_457_A index d5339ec..d5339ec 100644 --- a/geom_bottleneck/tests/data/test_457_A +++ b/bottleneck/tests/data/test_457_A diff --git a/geom_bottleneck/tests/data/test_457_B b/bottleneck/tests/data/test_457_B index e96c110..e96c110 100644 --- a/geom_bottleneck/tests/data/test_457_B +++ b/bottleneck/tests/data/test_457_B diff --git a/geom_bottleneck/tests/data/test_458_A b/bottleneck/tests/data/test_458_A index a9287b2..a9287b2 100644 --- a/geom_bottleneck/tests/data/test_458_A +++ b/bottleneck/tests/data/test_458_A diff --git a/geom_bottleneck/tests/data/test_458_B b/bottleneck/tests/data/test_458_B index 63b7c63..63b7c63 100644 --- a/geom_bottleneck/tests/data/test_458_B +++ b/bottleneck/tests/data/test_458_B diff --git a/geom_bottleneck/tests/data/test_459_A b/bottleneck/tests/data/test_459_A index f8a82f8..f8a82f8 100644 --- a/geom_bottleneck/tests/data/test_459_A +++ b/bottleneck/tests/data/test_459_A diff --git a/geom_bottleneck/tests/data/test_459_B b/bottleneck/tests/data/test_459_B index dc645ee..dc645ee 100644 --- a/geom_bottleneck/tests/data/test_459_B +++ b/bottleneck/tests/data/test_459_B diff --git a/geom_bottleneck/tests/data/test_460_A b/bottleneck/tests/data/test_460_A index 000c14e..000c14e 100644 --- a/geom_bottleneck/tests/data/test_460_A +++ b/bottleneck/tests/data/test_460_A diff --git a/geom_bottleneck/tests/data/test_460_B b/bottleneck/tests/data/test_460_B index 4a7d4a3..4a7d4a3 100644 --- a/geom_bottleneck/tests/data/test_460_B +++ b/bottleneck/tests/data/test_460_B diff --git a/geom_bottleneck/tests/data/test_461_A b/bottleneck/tests/data/test_461_A index aaebf2d..aaebf2d 100644 --- a/geom_bottleneck/tests/data/test_461_A +++ b/bottleneck/tests/data/test_461_A diff --git a/geom_bottleneck/tests/data/test_461_B b/bottleneck/tests/data/test_461_B index 183fa51..183fa51 100644 --- a/geom_bottleneck/tests/data/test_461_B +++ b/bottleneck/tests/data/test_461_B diff --git a/geom_bottleneck/tests/data/test_462_A b/bottleneck/tests/data/test_462_A index df1936d..df1936d 100644 --- a/geom_bottleneck/tests/data/test_462_A +++ b/bottleneck/tests/data/test_462_A diff --git a/geom_bottleneck/tests/data/test_462_B b/bottleneck/tests/data/test_462_B index 5be3bf0..5be3bf0 100644 --- a/geom_bottleneck/tests/data/test_462_B +++ b/bottleneck/tests/data/test_462_B diff --git a/geom_bottleneck/tests/data/test_463_A b/bottleneck/tests/data/test_463_A index c8776fe..c8776fe 100644 --- a/geom_bottleneck/tests/data/test_463_A +++ b/bottleneck/tests/data/test_463_A diff --git a/geom_bottleneck/tests/data/test_463_B b/bottleneck/tests/data/test_463_B index a9f1273..a9f1273 100644 --- a/geom_bottleneck/tests/data/test_463_B +++ b/bottleneck/tests/data/test_463_B diff --git a/geom_bottleneck/tests/data/test_464_A b/bottleneck/tests/data/test_464_A index 98ff6a9..98ff6a9 100644 --- a/geom_bottleneck/tests/data/test_464_A +++ b/bottleneck/tests/data/test_464_A diff --git a/geom_bottleneck/tests/data/test_464_B b/bottleneck/tests/data/test_464_B index 0e57b03..0e57b03 100644 --- a/geom_bottleneck/tests/data/test_464_B +++ b/bottleneck/tests/data/test_464_B diff --git a/geom_bottleneck/tests/data/test_465_A b/bottleneck/tests/data/test_465_A index b164c7a..b164c7a 100644 --- a/geom_bottleneck/tests/data/test_465_A +++ b/bottleneck/tests/data/test_465_A diff --git a/geom_bottleneck/tests/data/test_465_B b/bottleneck/tests/data/test_465_B index 610a2a5..610a2a5 100644 --- a/geom_bottleneck/tests/data/test_465_B +++ b/bottleneck/tests/data/test_465_B diff --git a/geom_bottleneck/tests/data/test_466_A b/bottleneck/tests/data/test_466_A index 3c0052c..3c0052c 100644 --- a/geom_bottleneck/tests/data/test_466_A +++ b/bottleneck/tests/data/test_466_A diff --git a/geom_bottleneck/tests/data/test_466_B b/bottleneck/tests/data/test_466_B index e8c16f8..e8c16f8 100644 --- a/geom_bottleneck/tests/data/test_466_B +++ b/bottleneck/tests/data/test_466_B diff --git a/geom_bottleneck/tests/data/test_467_A b/bottleneck/tests/data/test_467_A index 69280bb..69280bb 100644 --- a/geom_bottleneck/tests/data/test_467_A +++ b/bottleneck/tests/data/test_467_A diff --git a/geom_bottleneck/tests/data/test_467_B b/bottleneck/tests/data/test_467_B index c857912..c857912 100644 --- a/geom_bottleneck/tests/data/test_467_B +++ b/bottleneck/tests/data/test_467_B diff --git a/geom_bottleneck/tests/data/test_468_A b/bottleneck/tests/data/test_468_A index 9f92c43..9f92c43 100644 --- a/geom_bottleneck/tests/data/test_468_A +++ b/bottleneck/tests/data/test_468_A diff --git a/geom_bottleneck/tests/data/test_468_B b/bottleneck/tests/data/test_468_B index b20cdf4..b20cdf4 100644 --- a/geom_bottleneck/tests/data/test_468_B +++ b/bottleneck/tests/data/test_468_B diff --git a/geom_bottleneck/tests/data/test_469_A b/bottleneck/tests/data/test_469_A index 842bb69..842bb69 100644 --- a/geom_bottleneck/tests/data/test_469_A +++ b/bottleneck/tests/data/test_469_A diff --git a/geom_bottleneck/tests/data/test_469_B b/bottleneck/tests/data/test_469_B index e6de4fe..e6de4fe 100644 --- a/geom_bottleneck/tests/data/test_469_B +++ b/bottleneck/tests/data/test_469_B diff --git a/geom_bottleneck/tests/data/test_470_A b/bottleneck/tests/data/test_470_A index 5f2fd6b..5f2fd6b 100644 --- a/geom_bottleneck/tests/data/test_470_A +++ b/bottleneck/tests/data/test_470_A diff --git a/geom_bottleneck/tests/data/test_470_B b/bottleneck/tests/data/test_470_B index 5db84e8..5db84e8 100644 --- a/geom_bottleneck/tests/data/test_470_B +++ b/bottleneck/tests/data/test_470_B diff --git a/geom_bottleneck/tests/data/test_471_A b/bottleneck/tests/data/test_471_A index e88e5ff..e88e5ff 100644 --- a/geom_bottleneck/tests/data/test_471_A +++ b/bottleneck/tests/data/test_471_A diff --git a/geom_bottleneck/tests/data/test_471_B b/bottleneck/tests/data/test_471_B index 26065c0..26065c0 100644 --- a/geom_bottleneck/tests/data/test_471_B +++ b/bottleneck/tests/data/test_471_B diff --git a/geom_bottleneck/tests/data/test_472_A b/bottleneck/tests/data/test_472_A index bd2ec1a..bd2ec1a 100644 --- a/geom_bottleneck/tests/data/test_472_A +++ b/bottleneck/tests/data/test_472_A diff --git a/geom_bottleneck/tests/data/test_472_B b/bottleneck/tests/data/test_472_B index 3914a18..3914a18 100644 --- a/geom_bottleneck/tests/data/test_472_B +++ b/bottleneck/tests/data/test_472_B diff --git a/geom_bottleneck/tests/data/test_473_A b/bottleneck/tests/data/test_473_A index d8e4ed1..d8e4ed1 100644 --- a/geom_bottleneck/tests/data/test_473_A +++ b/bottleneck/tests/data/test_473_A diff --git a/geom_bottleneck/tests/data/test_473_B b/bottleneck/tests/data/test_473_B index 1ce2c2f..1ce2c2f 100644 --- a/geom_bottleneck/tests/data/test_473_B +++ b/bottleneck/tests/data/test_473_B diff --git a/geom_bottleneck/tests/data/test_474_A b/bottleneck/tests/data/test_474_A index 30c9ad1..30c9ad1 100644 --- a/geom_bottleneck/tests/data/test_474_A +++ b/bottleneck/tests/data/test_474_A diff --git a/geom_bottleneck/tests/data/test_474_B b/bottleneck/tests/data/test_474_B index 35c507a..35c507a 100644 --- a/geom_bottleneck/tests/data/test_474_B +++ b/bottleneck/tests/data/test_474_B diff --git a/geom_bottleneck/tests/data/test_475_A b/bottleneck/tests/data/test_475_A index 05023db..05023db 100644 --- a/geom_bottleneck/tests/data/test_475_A +++ b/bottleneck/tests/data/test_475_A diff --git a/geom_bottleneck/tests/data/test_475_B b/bottleneck/tests/data/test_475_B index 0fcc2d0..0fcc2d0 100644 --- a/geom_bottleneck/tests/data/test_475_B +++ b/bottleneck/tests/data/test_475_B diff --git a/geom_bottleneck/tests/data/test_476_A b/bottleneck/tests/data/test_476_A index 0c4ede1..0c4ede1 100644 --- a/geom_bottleneck/tests/data/test_476_A +++ b/bottleneck/tests/data/test_476_A diff --git a/geom_bottleneck/tests/data/test_476_B b/bottleneck/tests/data/test_476_B index ae68bae..ae68bae 100644 --- a/geom_bottleneck/tests/data/test_476_B +++ b/bottleneck/tests/data/test_476_B diff --git a/geom_bottleneck/tests/data/test_477_A b/bottleneck/tests/data/test_477_A index 719e1b7..719e1b7 100644 --- a/geom_bottleneck/tests/data/test_477_A +++ b/bottleneck/tests/data/test_477_A diff --git a/geom_bottleneck/tests/data/test_477_B b/bottleneck/tests/data/test_477_B index 6c2e706..6c2e706 100644 --- a/geom_bottleneck/tests/data/test_477_B +++ b/bottleneck/tests/data/test_477_B diff --git a/geom_bottleneck/tests/data/test_478_A b/bottleneck/tests/data/test_478_A index 61b09a8..61b09a8 100644 --- a/geom_bottleneck/tests/data/test_478_A +++ b/bottleneck/tests/data/test_478_A diff --git a/geom_bottleneck/tests/data/test_478_B b/bottleneck/tests/data/test_478_B index a302122..a302122 100644 --- a/geom_bottleneck/tests/data/test_478_B +++ b/bottleneck/tests/data/test_478_B diff --git a/geom_bottleneck/tests/data/test_479_A b/bottleneck/tests/data/test_479_A index b956a54..b956a54 100644 --- a/geom_bottleneck/tests/data/test_479_A +++ b/bottleneck/tests/data/test_479_A diff --git a/geom_bottleneck/tests/data/test_479_B b/bottleneck/tests/data/test_479_B index 10d8948..10d8948 100644 --- a/geom_bottleneck/tests/data/test_479_B +++ b/bottleneck/tests/data/test_479_B diff --git a/geom_bottleneck/tests/data/test_480_A b/bottleneck/tests/data/test_480_A index 6ad5182..6ad5182 100644 --- a/geom_bottleneck/tests/data/test_480_A +++ b/bottleneck/tests/data/test_480_A diff --git a/geom_bottleneck/tests/data/test_480_B b/bottleneck/tests/data/test_480_B index 246f278..246f278 100644 --- a/geom_bottleneck/tests/data/test_480_B +++ b/bottleneck/tests/data/test_480_B diff --git a/geom_bottleneck/tests/data/test_481_A b/bottleneck/tests/data/test_481_A index 8e414ab..8e414ab 100644 --- a/geom_bottleneck/tests/data/test_481_A +++ b/bottleneck/tests/data/test_481_A diff --git a/geom_bottleneck/tests/data/test_481_B b/bottleneck/tests/data/test_481_B index 5596312..5596312 100644 --- a/geom_bottleneck/tests/data/test_481_B +++ b/bottleneck/tests/data/test_481_B diff --git a/geom_bottleneck/tests/data/test_482_A b/bottleneck/tests/data/test_482_A index b40bc32..b40bc32 100644 --- a/geom_bottleneck/tests/data/test_482_A +++ b/bottleneck/tests/data/test_482_A diff --git a/geom_bottleneck/tests/data/test_482_B b/bottleneck/tests/data/test_482_B index 04b23b5..04b23b5 100644 --- a/geom_bottleneck/tests/data/test_482_B +++ b/bottleneck/tests/data/test_482_B diff --git a/geom_bottleneck/tests/data/test_483_A b/bottleneck/tests/data/test_483_A index 7ef0f99..7ef0f99 100644 --- a/geom_bottleneck/tests/data/test_483_A +++ b/bottleneck/tests/data/test_483_A diff --git a/geom_bottleneck/tests/data/test_483_B b/bottleneck/tests/data/test_483_B index eabdee1..eabdee1 100644 --- a/geom_bottleneck/tests/data/test_483_B +++ b/bottleneck/tests/data/test_483_B diff --git a/geom_bottleneck/tests/data/test_484_A b/bottleneck/tests/data/test_484_A index 11fa5dd..11fa5dd 100644 --- a/geom_bottleneck/tests/data/test_484_A +++ b/bottleneck/tests/data/test_484_A diff --git a/geom_bottleneck/tests/data/test_484_B b/bottleneck/tests/data/test_484_B index 2dda740..2dda740 100644 --- a/geom_bottleneck/tests/data/test_484_B +++ b/bottleneck/tests/data/test_484_B diff --git a/geom_bottleneck/tests/data/test_485_A b/bottleneck/tests/data/test_485_A index bd500dd..bd500dd 100644 --- a/geom_bottleneck/tests/data/test_485_A +++ b/bottleneck/tests/data/test_485_A diff --git a/geom_bottleneck/tests/data/test_485_B b/bottleneck/tests/data/test_485_B index a117670..a117670 100644 --- a/geom_bottleneck/tests/data/test_485_B +++ b/bottleneck/tests/data/test_485_B diff --git a/geom_bottleneck/tests/data/test_486_A b/bottleneck/tests/data/test_486_A index 4dcc3ca..4dcc3ca 100644 --- a/geom_bottleneck/tests/data/test_486_A +++ b/bottleneck/tests/data/test_486_A diff --git a/geom_bottleneck/tests/data/test_486_B b/bottleneck/tests/data/test_486_B index c808dc5..c808dc5 100644 --- a/geom_bottleneck/tests/data/test_486_B +++ b/bottleneck/tests/data/test_486_B diff --git a/geom_bottleneck/tests/data/test_487_A b/bottleneck/tests/data/test_487_A index 7250b20..7250b20 100644 --- a/geom_bottleneck/tests/data/test_487_A +++ b/bottleneck/tests/data/test_487_A diff --git a/geom_bottleneck/tests/data/test_487_B b/bottleneck/tests/data/test_487_B index b0a4119..b0a4119 100644 --- a/geom_bottleneck/tests/data/test_487_B +++ b/bottleneck/tests/data/test_487_B diff --git a/geom_bottleneck/tests/data/test_488_A b/bottleneck/tests/data/test_488_A index 92f19ab..92f19ab 100644 --- a/geom_bottleneck/tests/data/test_488_A +++ b/bottleneck/tests/data/test_488_A diff --git a/geom_bottleneck/tests/data/test_488_B b/bottleneck/tests/data/test_488_B index 712480d..712480d 100644 --- a/geom_bottleneck/tests/data/test_488_B +++ b/bottleneck/tests/data/test_488_B diff --git a/geom_bottleneck/tests/data/test_489_A b/bottleneck/tests/data/test_489_A index f1c9abf..f1c9abf 100644 --- a/geom_bottleneck/tests/data/test_489_A +++ b/bottleneck/tests/data/test_489_A diff --git a/geom_bottleneck/tests/data/test_489_B b/bottleneck/tests/data/test_489_B index 5c5316f..5c5316f 100644 --- a/geom_bottleneck/tests/data/test_489_B +++ b/bottleneck/tests/data/test_489_B diff --git a/geom_bottleneck/tests/data/test_490_A b/bottleneck/tests/data/test_490_A index e907d09..e907d09 100644 --- a/geom_bottleneck/tests/data/test_490_A +++ b/bottleneck/tests/data/test_490_A diff --git a/geom_bottleneck/tests/data/test_490_B b/bottleneck/tests/data/test_490_B index 6368e47..6368e47 100644 --- a/geom_bottleneck/tests/data/test_490_B +++ b/bottleneck/tests/data/test_490_B diff --git a/geom_bottleneck/tests/data/test_491_A b/bottleneck/tests/data/test_491_A index 9fdc2fb..9fdc2fb 100644 --- a/geom_bottleneck/tests/data/test_491_A +++ b/bottleneck/tests/data/test_491_A diff --git a/geom_bottleneck/tests/data/test_491_B b/bottleneck/tests/data/test_491_B index 09cd4ac..09cd4ac 100644 --- a/geom_bottleneck/tests/data/test_491_B +++ b/bottleneck/tests/data/test_491_B diff --git a/geom_bottleneck/tests/data/test_492_A b/bottleneck/tests/data/test_492_A index 434683d..434683d 100644 --- a/geom_bottleneck/tests/data/test_492_A +++ b/bottleneck/tests/data/test_492_A diff --git a/geom_bottleneck/tests/data/test_492_B b/bottleneck/tests/data/test_492_B index 3f6f5fa..3f6f5fa 100644 --- a/geom_bottleneck/tests/data/test_492_B +++ b/bottleneck/tests/data/test_492_B diff --git a/geom_bottleneck/tests/data/test_493_A b/bottleneck/tests/data/test_493_A index 12cfc64..12cfc64 100644 --- a/geom_bottleneck/tests/data/test_493_A +++ b/bottleneck/tests/data/test_493_A diff --git a/geom_bottleneck/tests/data/test_493_B b/bottleneck/tests/data/test_493_B index 43dcf08..43dcf08 100644 --- a/geom_bottleneck/tests/data/test_493_B +++ b/bottleneck/tests/data/test_493_B diff --git a/geom_bottleneck/tests/data/test_494_A b/bottleneck/tests/data/test_494_A index b35b505..b35b505 100644 --- a/geom_bottleneck/tests/data/test_494_A +++ b/bottleneck/tests/data/test_494_A diff --git a/geom_bottleneck/tests/data/test_494_B b/bottleneck/tests/data/test_494_B index fb70ed6..fb70ed6 100644 --- a/geom_bottleneck/tests/data/test_494_B +++ b/bottleneck/tests/data/test_494_B diff --git a/geom_bottleneck/tests/data/test_495_A b/bottleneck/tests/data/test_495_A index c244b7a..c244b7a 100644 --- a/geom_bottleneck/tests/data/test_495_A +++ b/bottleneck/tests/data/test_495_A diff --git a/geom_bottleneck/tests/data/test_495_B b/bottleneck/tests/data/test_495_B index 4bd121d..4bd121d 100644 --- a/geom_bottleneck/tests/data/test_495_B +++ b/bottleneck/tests/data/test_495_B diff --git a/geom_bottleneck/tests/data/test_496_A b/bottleneck/tests/data/test_496_A index cc2cc0b..cc2cc0b 100644 --- a/geom_bottleneck/tests/data/test_496_A +++ b/bottleneck/tests/data/test_496_A diff --git a/geom_bottleneck/tests/data/test_496_B b/bottleneck/tests/data/test_496_B index 5b8aeaa..5b8aeaa 100644 --- a/geom_bottleneck/tests/data/test_496_B +++ b/bottleneck/tests/data/test_496_B diff --git a/geom_bottleneck/tests/data/test_497_A b/bottleneck/tests/data/test_497_A index b3b511d..b3b511d 100644 --- a/geom_bottleneck/tests/data/test_497_A +++ b/bottleneck/tests/data/test_497_A diff --git a/geom_bottleneck/tests/data/test_497_B b/bottleneck/tests/data/test_497_B index 8870c73..8870c73 100644 --- a/geom_bottleneck/tests/data/test_497_B +++ b/bottleneck/tests/data/test_497_B diff --git a/geom_bottleneck/tests/data/test_498_A b/bottleneck/tests/data/test_498_A index 5bef5fa..5bef5fa 100644 --- a/geom_bottleneck/tests/data/test_498_A +++ b/bottleneck/tests/data/test_498_A diff --git a/geom_bottleneck/tests/data/test_498_B b/bottleneck/tests/data/test_498_B index b1ed38a..b1ed38a 100644 --- a/geom_bottleneck/tests/data/test_498_B +++ b/bottleneck/tests/data/test_498_B diff --git a/geom_bottleneck/tests/data/test_499_A b/bottleneck/tests/data/test_499_A index a24f367..a24f367 100644 --- a/geom_bottleneck/tests/data/test_499_A +++ b/bottleneck/tests/data/test_499_A diff --git a/geom_bottleneck/tests/data/test_499_B b/bottleneck/tests/data/test_499_B index 24d0d92..24d0d92 100644 --- a/geom_bottleneck/tests/data/test_499_B +++ b/bottleneck/tests/data/test_499_B diff --git a/geom_bottleneck/tests/data/test_500_A b/bottleneck/tests/data/test_500_A index ed86941..ed86941 100644 --- a/geom_bottleneck/tests/data/test_500_A +++ b/bottleneck/tests/data/test_500_A diff --git a/geom_bottleneck/tests/data/test_500_B b/bottleneck/tests/data/test_500_B index 58f0cd6..58f0cd6 100644 --- a/geom_bottleneck/tests/data/test_500_B +++ b/bottleneck/tests/data/test_500_B diff --git a/geom_bottleneck/tests/data/test_501_A b/bottleneck/tests/data/test_501_A index b6f9335..b6f9335 100644 --- a/geom_bottleneck/tests/data/test_501_A +++ b/bottleneck/tests/data/test_501_A diff --git a/geom_bottleneck/tests/data/test_501_B b/bottleneck/tests/data/test_501_B index af0d32b..af0d32b 100644 --- a/geom_bottleneck/tests/data/test_501_B +++ b/bottleneck/tests/data/test_501_B diff --git a/geom_bottleneck/tests/data/test_502_A b/bottleneck/tests/data/test_502_A index 64c4bfe..64c4bfe 100644 --- a/geom_bottleneck/tests/data/test_502_A +++ b/bottleneck/tests/data/test_502_A diff --git a/geom_bottleneck/tests/data/test_502_B b/bottleneck/tests/data/test_502_B index 4b1bb48..4b1bb48 100644 --- a/geom_bottleneck/tests/data/test_502_B +++ b/bottleneck/tests/data/test_502_B diff --git a/geom_bottleneck/tests/data/test_503_A b/bottleneck/tests/data/test_503_A index 7686e8d..7686e8d 100644 --- a/geom_bottleneck/tests/data/test_503_A +++ b/bottleneck/tests/data/test_503_A diff --git a/geom_bottleneck/tests/data/test_503_B b/bottleneck/tests/data/test_503_B index c662290..c662290 100644 --- a/geom_bottleneck/tests/data/test_503_B +++ b/bottleneck/tests/data/test_503_B diff --git a/geom_bottleneck/tests/data/test_504_A b/bottleneck/tests/data/test_504_A index 7b0bcd8..7b0bcd8 100644 --- a/geom_bottleneck/tests/data/test_504_A +++ b/bottleneck/tests/data/test_504_A diff --git a/geom_bottleneck/tests/data/test_504_B b/bottleneck/tests/data/test_504_B index 1fb9704..1fb9704 100644 --- a/geom_bottleneck/tests/data/test_504_B +++ b/bottleneck/tests/data/test_504_B diff --git a/geom_bottleneck/tests/data/test_505_A b/bottleneck/tests/data/test_505_A index fd80b53..fd80b53 100644 --- a/geom_bottleneck/tests/data/test_505_A +++ b/bottleneck/tests/data/test_505_A diff --git a/geom_bottleneck/tests/data/test_505_B b/bottleneck/tests/data/test_505_B index 9bd046e..9bd046e 100644 --- a/geom_bottleneck/tests/data/test_505_B +++ b/bottleneck/tests/data/test_505_B diff --git a/geom_bottleneck/tests/data/test_506_A b/bottleneck/tests/data/test_506_A index 1f5e9ac..1f5e9ac 100644 --- a/geom_bottleneck/tests/data/test_506_A +++ b/bottleneck/tests/data/test_506_A diff --git a/geom_bottleneck/tests/data/test_506_B b/bottleneck/tests/data/test_506_B index 0dc89b8..0dc89b8 100644 --- a/geom_bottleneck/tests/data/test_506_B +++ b/bottleneck/tests/data/test_506_B diff --git a/geom_bottleneck/tests/data/test_507_A b/bottleneck/tests/data/test_507_A index a6d164e..a6d164e 100644 --- a/geom_bottleneck/tests/data/test_507_A +++ b/bottleneck/tests/data/test_507_A diff --git a/geom_bottleneck/tests/data/test_507_B b/bottleneck/tests/data/test_507_B index b39a7fe..b39a7fe 100644 --- a/geom_bottleneck/tests/data/test_507_B +++ b/bottleneck/tests/data/test_507_B diff --git a/geom_bottleneck/tests/data/test_508_A b/bottleneck/tests/data/test_508_A index c837ce3..c837ce3 100644 --- a/geom_bottleneck/tests/data/test_508_A +++ b/bottleneck/tests/data/test_508_A diff --git a/geom_bottleneck/tests/data/test_508_B b/bottleneck/tests/data/test_508_B index 733b5a0..733b5a0 100644 --- a/geom_bottleneck/tests/data/test_508_B +++ b/bottleneck/tests/data/test_508_B diff --git a/geom_bottleneck/tests/data/test_509_A b/bottleneck/tests/data/test_509_A index 98137f3..98137f3 100644 --- a/geom_bottleneck/tests/data/test_509_A +++ b/bottleneck/tests/data/test_509_A diff --git a/geom_bottleneck/tests/data/test_509_B b/bottleneck/tests/data/test_509_B index 1edd08c..1edd08c 100644 --- a/geom_bottleneck/tests/data/test_509_B +++ b/bottleneck/tests/data/test_509_B diff --git a/geom_bottleneck/tests/data/test_510_A b/bottleneck/tests/data/test_510_A index b1e0e68..b1e0e68 100644 --- a/geom_bottleneck/tests/data/test_510_A +++ b/bottleneck/tests/data/test_510_A diff --git a/geom_bottleneck/tests/data/test_510_B b/bottleneck/tests/data/test_510_B index 8e48152..8e48152 100644 --- a/geom_bottleneck/tests/data/test_510_B +++ b/bottleneck/tests/data/test_510_B diff --git a/geom_bottleneck/tests/data/test_511_A b/bottleneck/tests/data/test_511_A index a2c6b34..a2c6b34 100644 --- a/geom_bottleneck/tests/data/test_511_A +++ b/bottleneck/tests/data/test_511_A diff --git a/geom_bottleneck/tests/data/test_511_B b/bottleneck/tests/data/test_511_B index ff48216..ff48216 100644 --- a/geom_bottleneck/tests/data/test_511_B +++ b/bottleneck/tests/data/test_511_B diff --git a/geom_bottleneck/tests/data/test_512_A b/bottleneck/tests/data/test_512_A index 8f875d8..8f875d8 100644 --- a/geom_bottleneck/tests/data/test_512_A +++ b/bottleneck/tests/data/test_512_A diff --git a/geom_bottleneck/tests/data/test_512_B b/bottleneck/tests/data/test_512_B index c6988c1..c6988c1 100644 --- a/geom_bottleneck/tests/data/test_512_B +++ b/bottleneck/tests/data/test_512_B diff --git a/geom_bottleneck/tests/data/test_513_A b/bottleneck/tests/data/test_513_A index 844c16d..844c16d 100644 --- a/geom_bottleneck/tests/data/test_513_A +++ b/bottleneck/tests/data/test_513_A diff --git a/geom_bottleneck/tests/data/test_513_B b/bottleneck/tests/data/test_513_B index ee75f8c..ee75f8c 100644 --- a/geom_bottleneck/tests/data/test_513_B +++ b/bottleneck/tests/data/test_513_B diff --git a/geom_bottleneck/tests/data/test_514_A b/bottleneck/tests/data/test_514_A index 9b58831..9b58831 100644 --- a/geom_bottleneck/tests/data/test_514_A +++ b/bottleneck/tests/data/test_514_A diff --git a/geom_bottleneck/tests/data/test_514_B b/bottleneck/tests/data/test_514_B index 39c6534..39c6534 100644 --- a/geom_bottleneck/tests/data/test_514_B +++ b/bottleneck/tests/data/test_514_B diff --git a/geom_bottleneck/tests/data/test_515_A b/bottleneck/tests/data/test_515_A index fc2578b..fc2578b 100644 --- a/geom_bottleneck/tests/data/test_515_A +++ b/bottleneck/tests/data/test_515_A diff --git a/geom_bottleneck/tests/data/test_515_B b/bottleneck/tests/data/test_515_B index 715f6e5..715f6e5 100644 --- a/geom_bottleneck/tests/data/test_515_B +++ b/bottleneck/tests/data/test_515_B diff --git a/geom_bottleneck/tests/data/test_516_A b/bottleneck/tests/data/test_516_A index bd37e5d..bd37e5d 100644 --- a/geom_bottleneck/tests/data/test_516_A +++ b/bottleneck/tests/data/test_516_A diff --git a/geom_bottleneck/tests/data/test_516_B b/bottleneck/tests/data/test_516_B index 8d23127..8d23127 100644 --- a/geom_bottleneck/tests/data/test_516_B +++ b/bottleneck/tests/data/test_516_B diff --git a/geom_bottleneck/tests/data/test_517_A b/bottleneck/tests/data/test_517_A index 17ca01c..17ca01c 100644 --- a/geom_bottleneck/tests/data/test_517_A +++ b/bottleneck/tests/data/test_517_A diff --git a/geom_bottleneck/tests/data/test_517_B b/bottleneck/tests/data/test_517_B index ba82599..ba82599 100644 --- a/geom_bottleneck/tests/data/test_517_B +++ b/bottleneck/tests/data/test_517_B diff --git a/geom_bottleneck/tests/data/test_518_A b/bottleneck/tests/data/test_518_A index bb1711c..bb1711c 100644 --- a/geom_bottleneck/tests/data/test_518_A +++ b/bottleneck/tests/data/test_518_A diff --git a/geom_bottleneck/tests/data/test_518_B b/bottleneck/tests/data/test_518_B index 5b2e95a..5b2e95a 100644 --- a/geom_bottleneck/tests/data/test_518_B +++ b/bottleneck/tests/data/test_518_B diff --git a/geom_bottleneck/tests/data/test_519_A b/bottleneck/tests/data/test_519_A index f0cb6ea..f0cb6ea 100644 --- a/geom_bottleneck/tests/data/test_519_A +++ b/bottleneck/tests/data/test_519_A diff --git a/geom_bottleneck/tests/data/test_519_B b/bottleneck/tests/data/test_519_B index 03396db..03396db 100644 --- a/geom_bottleneck/tests/data/test_519_B +++ b/bottleneck/tests/data/test_519_B diff --git a/geom_bottleneck/tests/data/test_520_A b/bottleneck/tests/data/test_520_A index 9353285..9353285 100644 --- a/geom_bottleneck/tests/data/test_520_A +++ b/bottleneck/tests/data/test_520_A diff --git a/geom_bottleneck/tests/data/test_520_B b/bottleneck/tests/data/test_520_B index 1e328cd..1e328cd 100644 --- a/geom_bottleneck/tests/data/test_520_B +++ b/bottleneck/tests/data/test_520_B diff --git a/geom_bottleneck/tests/data/test_521_A b/bottleneck/tests/data/test_521_A index d0bea91..d0bea91 100644 --- a/geom_bottleneck/tests/data/test_521_A +++ b/bottleneck/tests/data/test_521_A diff --git a/geom_bottleneck/tests/data/test_521_B b/bottleneck/tests/data/test_521_B index 5e584b0..5e584b0 100644 --- a/geom_bottleneck/tests/data/test_521_B +++ b/bottleneck/tests/data/test_521_B diff --git a/geom_bottleneck/tests/data/test_522_A b/bottleneck/tests/data/test_522_A index 5631735..5631735 100644 --- a/geom_bottleneck/tests/data/test_522_A +++ b/bottleneck/tests/data/test_522_A diff --git a/geom_bottleneck/tests/data/test_522_B b/bottleneck/tests/data/test_522_B index 903bcdc..903bcdc 100644 --- a/geom_bottleneck/tests/data/test_522_B +++ b/bottleneck/tests/data/test_522_B diff --git a/geom_bottleneck/tests/data/test_523_A b/bottleneck/tests/data/test_523_A index b4da958..b4da958 100644 --- a/geom_bottleneck/tests/data/test_523_A +++ b/bottleneck/tests/data/test_523_A diff --git a/geom_bottleneck/tests/data/test_523_B b/bottleneck/tests/data/test_523_B index bcc7438..bcc7438 100644 --- a/geom_bottleneck/tests/data/test_523_B +++ b/bottleneck/tests/data/test_523_B diff --git a/geom_bottleneck/tests/data/test_524_A b/bottleneck/tests/data/test_524_A index e260687..e260687 100644 --- a/geom_bottleneck/tests/data/test_524_A +++ b/bottleneck/tests/data/test_524_A diff --git a/geom_bottleneck/tests/data/test_524_B b/bottleneck/tests/data/test_524_B index 92a2d76..92a2d76 100644 --- a/geom_bottleneck/tests/data/test_524_B +++ b/bottleneck/tests/data/test_524_B diff --git a/geom_bottleneck/tests/data/test_525_A b/bottleneck/tests/data/test_525_A index 25d9d8f..25d9d8f 100644 --- a/geom_bottleneck/tests/data/test_525_A +++ b/bottleneck/tests/data/test_525_A diff --git a/geom_bottleneck/tests/data/test_525_B b/bottleneck/tests/data/test_525_B index d61ee84..d61ee84 100644 --- a/geom_bottleneck/tests/data/test_525_B +++ b/bottleneck/tests/data/test_525_B diff --git a/geom_bottleneck/tests/data/test_526_A b/bottleneck/tests/data/test_526_A index 985ba29..985ba29 100644 --- a/geom_bottleneck/tests/data/test_526_A +++ b/bottleneck/tests/data/test_526_A diff --git a/geom_bottleneck/tests/data/test_526_B b/bottleneck/tests/data/test_526_B index 2ebf00a..2ebf00a 100644 --- a/geom_bottleneck/tests/data/test_526_B +++ b/bottleneck/tests/data/test_526_B diff --git a/geom_bottleneck/tests/data/test_527_A b/bottleneck/tests/data/test_527_A index 802b177..802b177 100644 --- a/geom_bottleneck/tests/data/test_527_A +++ b/bottleneck/tests/data/test_527_A diff --git a/geom_bottleneck/tests/data/test_527_B b/bottleneck/tests/data/test_527_B index a04d9f1..a04d9f1 100644 --- a/geom_bottleneck/tests/data/test_527_B +++ b/bottleneck/tests/data/test_527_B diff --git a/geom_bottleneck/tests/data/test_528_A b/bottleneck/tests/data/test_528_A index da776dc..da776dc 100644 --- a/geom_bottleneck/tests/data/test_528_A +++ b/bottleneck/tests/data/test_528_A diff --git a/geom_bottleneck/tests/data/test_528_B b/bottleneck/tests/data/test_528_B index 5329277..5329277 100644 --- a/geom_bottleneck/tests/data/test_528_B +++ b/bottleneck/tests/data/test_528_B diff --git a/geom_bottleneck/tests/data/test_529_A b/bottleneck/tests/data/test_529_A index ebbf6fa..ebbf6fa 100644 --- a/geom_bottleneck/tests/data/test_529_A +++ b/bottleneck/tests/data/test_529_A diff --git a/geom_bottleneck/tests/data/test_529_B b/bottleneck/tests/data/test_529_B index 6e0f836..6e0f836 100644 --- a/geom_bottleneck/tests/data/test_529_B +++ b/bottleneck/tests/data/test_529_B diff --git a/geom_bottleneck/tests/data/test_530_A b/bottleneck/tests/data/test_530_A index 904eac4..904eac4 100644 --- a/geom_bottleneck/tests/data/test_530_A +++ b/bottleneck/tests/data/test_530_A diff --git a/geom_bottleneck/tests/data/test_530_B b/bottleneck/tests/data/test_530_B index f4cfc4c..f4cfc4c 100644 --- a/geom_bottleneck/tests/data/test_530_B +++ b/bottleneck/tests/data/test_530_B diff --git a/geom_bottleneck/tests/data/test_531_A b/bottleneck/tests/data/test_531_A index 416eb0a..416eb0a 100644 --- a/geom_bottleneck/tests/data/test_531_A +++ b/bottleneck/tests/data/test_531_A diff --git a/geom_bottleneck/tests/data/test_531_B b/bottleneck/tests/data/test_531_B index afb424a..afb424a 100644 --- a/geom_bottleneck/tests/data/test_531_B +++ b/bottleneck/tests/data/test_531_B diff --git a/geom_bottleneck/tests/data/test_532_A b/bottleneck/tests/data/test_532_A index 7eb97c1..7eb97c1 100644 --- a/geom_bottleneck/tests/data/test_532_A +++ b/bottleneck/tests/data/test_532_A diff --git a/geom_bottleneck/tests/data/test_532_B b/bottleneck/tests/data/test_532_B index e86a6a0..e86a6a0 100644 --- a/geom_bottleneck/tests/data/test_532_B +++ b/bottleneck/tests/data/test_532_B diff --git a/geom_bottleneck/tests/data/test_533_A b/bottleneck/tests/data/test_533_A index 0462a89..0462a89 100644 --- a/geom_bottleneck/tests/data/test_533_A +++ b/bottleneck/tests/data/test_533_A diff --git a/geom_bottleneck/tests/data/test_533_B b/bottleneck/tests/data/test_533_B index d077aa2..d077aa2 100644 --- a/geom_bottleneck/tests/data/test_533_B +++ b/bottleneck/tests/data/test_533_B diff --git a/geom_bottleneck/tests/data/test_534_A b/bottleneck/tests/data/test_534_A index a5c6b69..a5c6b69 100644 --- a/geom_bottleneck/tests/data/test_534_A +++ b/bottleneck/tests/data/test_534_A diff --git a/geom_bottleneck/tests/data/test_534_B b/bottleneck/tests/data/test_534_B index 10d4e7b..10d4e7b 100644 --- a/geom_bottleneck/tests/data/test_534_B +++ b/bottleneck/tests/data/test_534_B diff --git a/geom_bottleneck/tests/data/test_535_A b/bottleneck/tests/data/test_535_A index faaf29f..faaf29f 100644 --- a/geom_bottleneck/tests/data/test_535_A +++ b/bottleneck/tests/data/test_535_A diff --git a/geom_bottleneck/tests/data/test_535_B b/bottleneck/tests/data/test_535_B index 108c8a3..108c8a3 100644 --- a/geom_bottleneck/tests/data/test_535_B +++ b/bottleneck/tests/data/test_535_B diff --git a/geom_bottleneck/tests/data/test_536_A b/bottleneck/tests/data/test_536_A index 320f5af..320f5af 100644 --- a/geom_bottleneck/tests/data/test_536_A +++ b/bottleneck/tests/data/test_536_A diff --git a/geom_bottleneck/tests/data/test_536_B b/bottleneck/tests/data/test_536_B index 9ce91f5..9ce91f5 100644 --- a/geom_bottleneck/tests/data/test_536_B +++ b/bottleneck/tests/data/test_536_B diff --git a/geom_bottleneck/tests/data/test_537_A b/bottleneck/tests/data/test_537_A index c41e293..c41e293 100644 --- a/geom_bottleneck/tests/data/test_537_A +++ b/bottleneck/tests/data/test_537_A diff --git a/geom_bottleneck/tests/data/test_537_B b/bottleneck/tests/data/test_537_B index a10f64d..a10f64d 100644 --- a/geom_bottleneck/tests/data/test_537_B +++ b/bottleneck/tests/data/test_537_B diff --git a/geom_bottleneck/tests/data/test_538_A b/bottleneck/tests/data/test_538_A index 0d98495..0d98495 100644 --- a/geom_bottleneck/tests/data/test_538_A +++ b/bottleneck/tests/data/test_538_A diff --git a/geom_bottleneck/tests/data/test_538_B b/bottleneck/tests/data/test_538_B index 6dde6f3..6dde6f3 100644 --- a/geom_bottleneck/tests/data/test_538_B +++ b/bottleneck/tests/data/test_538_B diff --git a/geom_bottleneck/tests/data/test_539_A b/bottleneck/tests/data/test_539_A index a844d1c..a844d1c 100644 --- a/geom_bottleneck/tests/data/test_539_A +++ b/bottleneck/tests/data/test_539_A diff --git a/geom_bottleneck/tests/data/test_539_B b/bottleneck/tests/data/test_539_B index 824a004..824a004 100644 --- a/geom_bottleneck/tests/data/test_539_B +++ b/bottleneck/tests/data/test_539_B diff --git a/geom_bottleneck/tests/data/test_540_A b/bottleneck/tests/data/test_540_A index 26bd782..26bd782 100644 --- a/geom_bottleneck/tests/data/test_540_A +++ b/bottleneck/tests/data/test_540_A diff --git a/geom_bottleneck/tests/data/test_540_B b/bottleneck/tests/data/test_540_B index 224839d..224839d 100644 --- a/geom_bottleneck/tests/data/test_540_B +++ b/bottleneck/tests/data/test_540_B diff --git a/geom_bottleneck/tests/data/test_541_A b/bottleneck/tests/data/test_541_A index fe8039b..fe8039b 100644 --- a/geom_bottleneck/tests/data/test_541_A +++ b/bottleneck/tests/data/test_541_A diff --git a/geom_bottleneck/tests/data/test_541_B b/bottleneck/tests/data/test_541_B index c33af0e..c33af0e 100644 --- a/geom_bottleneck/tests/data/test_541_B +++ b/bottleneck/tests/data/test_541_B diff --git a/geom_bottleneck/tests/data/test_542_A b/bottleneck/tests/data/test_542_A index d45ea52..d45ea52 100644 --- a/geom_bottleneck/tests/data/test_542_A +++ b/bottleneck/tests/data/test_542_A diff --git a/geom_bottleneck/tests/data/test_542_B b/bottleneck/tests/data/test_542_B index 9dcdf8a..9dcdf8a 100644 --- a/geom_bottleneck/tests/data/test_542_B +++ b/bottleneck/tests/data/test_542_B diff --git a/geom_bottleneck/tests/data/test_543_A b/bottleneck/tests/data/test_543_A index 511fbc1..511fbc1 100644 --- a/geom_bottleneck/tests/data/test_543_A +++ b/bottleneck/tests/data/test_543_A diff --git a/geom_bottleneck/tests/data/test_543_B b/bottleneck/tests/data/test_543_B index 879080c..879080c 100644 --- a/geom_bottleneck/tests/data/test_543_B +++ b/bottleneck/tests/data/test_543_B diff --git a/geom_bottleneck/tests/data/test_544_A b/bottleneck/tests/data/test_544_A index a355d41..a355d41 100644 --- a/geom_bottleneck/tests/data/test_544_A +++ b/bottleneck/tests/data/test_544_A diff --git a/geom_bottleneck/tests/data/test_544_B b/bottleneck/tests/data/test_544_B index 83587cf..83587cf 100644 --- a/geom_bottleneck/tests/data/test_544_B +++ b/bottleneck/tests/data/test_544_B diff --git a/geom_bottleneck/tests/data/test_545_A b/bottleneck/tests/data/test_545_A index c5351d7..c5351d7 100644 --- a/geom_bottleneck/tests/data/test_545_A +++ b/bottleneck/tests/data/test_545_A diff --git a/geom_bottleneck/tests/data/test_545_B b/bottleneck/tests/data/test_545_B index 0c60c17..0c60c17 100644 --- a/geom_bottleneck/tests/data/test_545_B +++ b/bottleneck/tests/data/test_545_B diff --git a/geom_bottleneck/tests/data/test_546_A b/bottleneck/tests/data/test_546_A index 4391c84..4391c84 100644 --- a/geom_bottleneck/tests/data/test_546_A +++ b/bottleneck/tests/data/test_546_A diff --git a/geom_bottleneck/tests/data/test_546_B b/bottleneck/tests/data/test_546_B index 3d3dec6..3d3dec6 100644 --- a/geom_bottleneck/tests/data/test_546_B +++ b/bottleneck/tests/data/test_546_B diff --git a/geom_bottleneck/tests/data/test_547_A b/bottleneck/tests/data/test_547_A index 1388d05..1388d05 100644 --- a/geom_bottleneck/tests/data/test_547_A +++ b/bottleneck/tests/data/test_547_A diff --git a/geom_bottleneck/tests/data/test_547_B b/bottleneck/tests/data/test_547_B index dbb925d..dbb925d 100644 --- a/geom_bottleneck/tests/data/test_547_B +++ b/bottleneck/tests/data/test_547_B diff --git a/geom_bottleneck/tests/data/test_548_A b/bottleneck/tests/data/test_548_A index 08c858e..08c858e 100644 --- a/geom_bottleneck/tests/data/test_548_A +++ b/bottleneck/tests/data/test_548_A diff --git a/geom_bottleneck/tests/data/test_548_B b/bottleneck/tests/data/test_548_B index b6dda3a..b6dda3a 100644 --- a/geom_bottleneck/tests/data/test_548_B +++ b/bottleneck/tests/data/test_548_B diff --git a/geom_bottleneck/tests/data/test_549_A b/bottleneck/tests/data/test_549_A index b0d5ddf..b0d5ddf 100644 --- a/geom_bottleneck/tests/data/test_549_A +++ b/bottleneck/tests/data/test_549_A diff --git a/geom_bottleneck/tests/data/test_549_B b/bottleneck/tests/data/test_549_B index a44a982..a44a982 100644 --- a/geom_bottleneck/tests/data/test_549_B +++ b/bottleneck/tests/data/test_549_B diff --git a/geom_bottleneck/tests/data/test_550_A b/bottleneck/tests/data/test_550_A index b8ba8e8..b8ba8e8 100644 --- a/geom_bottleneck/tests/data/test_550_A +++ b/bottleneck/tests/data/test_550_A diff --git a/geom_bottleneck/tests/data/test_550_B b/bottleneck/tests/data/test_550_B index ed900f0..ed900f0 100644 --- a/geom_bottleneck/tests/data/test_550_B +++ b/bottleneck/tests/data/test_550_B diff --git a/geom_bottleneck/tests/data/test_551_A b/bottleneck/tests/data/test_551_A index 3002ec2..3002ec2 100644 --- a/geom_bottleneck/tests/data/test_551_A +++ b/bottleneck/tests/data/test_551_A diff --git a/geom_bottleneck/tests/data/test_551_B b/bottleneck/tests/data/test_551_B index 5a9b2de..5a9b2de 100644 --- a/geom_bottleneck/tests/data/test_551_B +++ b/bottleneck/tests/data/test_551_B diff --git a/geom_bottleneck/tests/data/test_552_A b/bottleneck/tests/data/test_552_A index 19de840..19de840 100644 --- a/geom_bottleneck/tests/data/test_552_A +++ b/bottleneck/tests/data/test_552_A diff --git a/geom_bottleneck/tests/data/test_552_B b/bottleneck/tests/data/test_552_B index 54b3e00..54b3e00 100644 --- a/geom_bottleneck/tests/data/test_552_B +++ b/bottleneck/tests/data/test_552_B diff --git a/geom_bottleneck/tests/data/test_553_A b/bottleneck/tests/data/test_553_A index deff96a..deff96a 100644 --- a/geom_bottleneck/tests/data/test_553_A +++ b/bottleneck/tests/data/test_553_A diff --git a/geom_bottleneck/tests/data/test_553_B b/bottleneck/tests/data/test_553_B index ee7ce9b..ee7ce9b 100644 --- a/geom_bottleneck/tests/data/test_553_B +++ b/bottleneck/tests/data/test_553_B diff --git a/geom_bottleneck/tests/data/test_554_A b/bottleneck/tests/data/test_554_A index da38226..da38226 100644 --- a/geom_bottleneck/tests/data/test_554_A +++ b/bottleneck/tests/data/test_554_A diff --git a/geom_bottleneck/tests/data/test_554_B b/bottleneck/tests/data/test_554_B index 8583236..8583236 100644 --- a/geom_bottleneck/tests/data/test_554_B +++ b/bottleneck/tests/data/test_554_B diff --git a/geom_bottleneck/tests/data/test_555_A b/bottleneck/tests/data/test_555_A index 87cd93d..87cd93d 100644 --- a/geom_bottleneck/tests/data/test_555_A +++ b/bottleneck/tests/data/test_555_A diff --git a/geom_bottleneck/tests/data/test_555_B b/bottleneck/tests/data/test_555_B index 2b8c351..2b8c351 100644 --- a/geom_bottleneck/tests/data/test_555_B +++ b/bottleneck/tests/data/test_555_B diff --git a/geom_bottleneck/tests/data/test_556_A b/bottleneck/tests/data/test_556_A index 182965d..182965d 100644 --- a/geom_bottleneck/tests/data/test_556_A +++ b/bottleneck/tests/data/test_556_A diff --git a/geom_bottleneck/tests/data/test_556_B b/bottleneck/tests/data/test_556_B index f2e3409..f2e3409 100644 --- a/geom_bottleneck/tests/data/test_556_B +++ b/bottleneck/tests/data/test_556_B diff --git a/geom_bottleneck/tests/data/test_557_A b/bottleneck/tests/data/test_557_A index ac233bb..ac233bb 100644 --- a/geom_bottleneck/tests/data/test_557_A +++ b/bottleneck/tests/data/test_557_A diff --git a/geom_bottleneck/tests/data/test_557_B b/bottleneck/tests/data/test_557_B index f838403..f838403 100644 --- a/geom_bottleneck/tests/data/test_557_B +++ b/bottleneck/tests/data/test_557_B diff --git a/geom_bottleneck/tests/data/test_558_A b/bottleneck/tests/data/test_558_A index 7108d09..7108d09 100644 --- a/geom_bottleneck/tests/data/test_558_A +++ b/bottleneck/tests/data/test_558_A diff --git a/geom_bottleneck/tests/data/test_558_B b/bottleneck/tests/data/test_558_B index dd19869..dd19869 100644 --- a/geom_bottleneck/tests/data/test_558_B +++ b/bottleneck/tests/data/test_558_B diff --git a/geom_bottleneck/tests/data/test_559_A b/bottleneck/tests/data/test_559_A index 46f07b4..46f07b4 100644 --- a/geom_bottleneck/tests/data/test_559_A +++ b/bottleneck/tests/data/test_559_A diff --git a/geom_bottleneck/tests/data/test_559_B b/bottleneck/tests/data/test_559_B index b747fb8..b747fb8 100644 --- a/geom_bottleneck/tests/data/test_559_B +++ b/bottleneck/tests/data/test_559_B diff --git a/geom_bottleneck/tests/data/test_560_A b/bottleneck/tests/data/test_560_A index 9b704ae..9b704ae 100644 --- a/geom_bottleneck/tests/data/test_560_A +++ b/bottleneck/tests/data/test_560_A diff --git a/geom_bottleneck/tests/data/test_560_B b/bottleneck/tests/data/test_560_B index d4ece9d..d4ece9d 100644 --- a/geom_bottleneck/tests/data/test_560_B +++ b/bottleneck/tests/data/test_560_B diff --git a/geom_bottleneck/tests/data/test_561_A b/bottleneck/tests/data/test_561_A index 81a3e31..81a3e31 100644 --- a/geom_bottleneck/tests/data/test_561_A +++ b/bottleneck/tests/data/test_561_A diff --git a/geom_bottleneck/tests/data/test_561_B b/bottleneck/tests/data/test_561_B index c60b08c..c60b08c 100644 --- a/geom_bottleneck/tests/data/test_561_B +++ b/bottleneck/tests/data/test_561_B diff --git a/geom_bottleneck/tests/data/test_562_A b/bottleneck/tests/data/test_562_A index 6dadf55..6dadf55 100644 --- a/geom_bottleneck/tests/data/test_562_A +++ b/bottleneck/tests/data/test_562_A diff --git a/geom_bottleneck/tests/data/test_562_B b/bottleneck/tests/data/test_562_B index 48eaf77..48eaf77 100644 --- a/geom_bottleneck/tests/data/test_562_B +++ b/bottleneck/tests/data/test_562_B diff --git a/geom_bottleneck/tests/data/test_563_A b/bottleneck/tests/data/test_563_A index 954685e..954685e 100644 --- a/geom_bottleneck/tests/data/test_563_A +++ b/bottleneck/tests/data/test_563_A diff --git a/geom_bottleneck/tests/data/test_563_B b/bottleneck/tests/data/test_563_B index c3d7844..c3d7844 100644 --- a/geom_bottleneck/tests/data/test_563_B +++ b/bottleneck/tests/data/test_563_B diff --git a/geom_bottleneck/tests/data/test_564_A b/bottleneck/tests/data/test_564_A index a39b7ae..a39b7ae 100644 --- a/geom_bottleneck/tests/data/test_564_A +++ b/bottleneck/tests/data/test_564_A diff --git a/geom_bottleneck/tests/data/test_564_B b/bottleneck/tests/data/test_564_B index 22adad2..22adad2 100644 --- a/geom_bottleneck/tests/data/test_564_B +++ b/bottleneck/tests/data/test_564_B diff --git a/geom_bottleneck/tests/data/test_565_A b/bottleneck/tests/data/test_565_A index 34eb265..34eb265 100644 --- a/geom_bottleneck/tests/data/test_565_A +++ b/bottleneck/tests/data/test_565_A diff --git a/geom_bottleneck/tests/data/test_565_B b/bottleneck/tests/data/test_565_B index da5ed1d..da5ed1d 100644 --- a/geom_bottleneck/tests/data/test_565_B +++ b/bottleneck/tests/data/test_565_B diff --git a/geom_bottleneck/tests/data/test_566_A b/bottleneck/tests/data/test_566_A index 55d0a13..55d0a13 100644 --- a/geom_bottleneck/tests/data/test_566_A +++ b/bottleneck/tests/data/test_566_A diff --git a/geom_bottleneck/tests/data/test_566_B b/bottleneck/tests/data/test_566_B index 57c08b6..57c08b6 100644 --- a/geom_bottleneck/tests/data/test_566_B +++ b/bottleneck/tests/data/test_566_B diff --git a/geom_bottleneck/tests/data/test_567_A b/bottleneck/tests/data/test_567_A index 3304c25..3304c25 100644 --- a/geom_bottleneck/tests/data/test_567_A +++ b/bottleneck/tests/data/test_567_A diff --git a/geom_bottleneck/tests/data/test_567_B b/bottleneck/tests/data/test_567_B index 4a8f5fa..4a8f5fa 100644 --- a/geom_bottleneck/tests/data/test_567_B +++ b/bottleneck/tests/data/test_567_B diff --git a/geom_bottleneck/tests/data/test_568_A b/bottleneck/tests/data/test_568_A index e6e0ecb..e6e0ecb 100644 --- a/geom_bottleneck/tests/data/test_568_A +++ b/bottleneck/tests/data/test_568_A diff --git a/geom_bottleneck/tests/data/test_568_B b/bottleneck/tests/data/test_568_B index 081ff5e..081ff5e 100644 --- a/geom_bottleneck/tests/data/test_568_B +++ b/bottleneck/tests/data/test_568_B diff --git a/geom_bottleneck/tests/data/test_569_A b/bottleneck/tests/data/test_569_A index 7fc96cf..7fc96cf 100644 --- a/geom_bottleneck/tests/data/test_569_A +++ b/bottleneck/tests/data/test_569_A diff --git a/geom_bottleneck/tests/data/test_569_B b/bottleneck/tests/data/test_569_B index b732aac..b732aac 100644 --- a/geom_bottleneck/tests/data/test_569_B +++ b/bottleneck/tests/data/test_569_B diff --git a/geom_bottleneck/tests/data/test_570_A b/bottleneck/tests/data/test_570_A index 371835b..371835b 100644 --- a/geom_bottleneck/tests/data/test_570_A +++ b/bottleneck/tests/data/test_570_A diff --git a/geom_bottleneck/tests/data/test_570_B b/bottleneck/tests/data/test_570_B index 3ce3450..3ce3450 100644 --- a/geom_bottleneck/tests/data/test_570_B +++ b/bottleneck/tests/data/test_570_B diff --git a/geom_bottleneck/tests/data/test_571_A b/bottleneck/tests/data/test_571_A index 6b58a17..6b58a17 100644 --- a/geom_bottleneck/tests/data/test_571_A +++ b/bottleneck/tests/data/test_571_A diff --git a/geom_bottleneck/tests/data/test_571_B b/bottleneck/tests/data/test_571_B index 0bb3b3e..0bb3b3e 100644 --- a/geom_bottleneck/tests/data/test_571_B +++ b/bottleneck/tests/data/test_571_B diff --git a/geom_bottleneck/tests/data/test_572_A b/bottleneck/tests/data/test_572_A index 052ddfe..052ddfe 100644 --- a/geom_bottleneck/tests/data/test_572_A +++ b/bottleneck/tests/data/test_572_A diff --git a/geom_bottleneck/tests/data/test_572_B b/bottleneck/tests/data/test_572_B index d816eab..d816eab 100644 --- a/geom_bottleneck/tests/data/test_572_B +++ b/bottleneck/tests/data/test_572_B diff --git a/geom_bottleneck/tests/data/test_573_A b/bottleneck/tests/data/test_573_A index fe68d64..fe68d64 100644 --- a/geom_bottleneck/tests/data/test_573_A +++ b/bottleneck/tests/data/test_573_A diff --git a/geom_bottleneck/tests/data/test_573_B b/bottleneck/tests/data/test_573_B index 9824068..9824068 100644 --- a/geom_bottleneck/tests/data/test_573_B +++ b/bottleneck/tests/data/test_573_B diff --git a/geom_bottleneck/tests/data/test_574_A b/bottleneck/tests/data/test_574_A index 9dbb066..9dbb066 100644 --- a/geom_bottleneck/tests/data/test_574_A +++ b/bottleneck/tests/data/test_574_A diff --git a/geom_bottleneck/tests/data/test_574_B b/bottleneck/tests/data/test_574_B index dc0f4c7..dc0f4c7 100644 --- a/geom_bottleneck/tests/data/test_574_B +++ b/bottleneck/tests/data/test_574_B diff --git a/geom_bottleneck/tests/data/test_575_A b/bottleneck/tests/data/test_575_A index 7703382..7703382 100644 --- a/geom_bottleneck/tests/data/test_575_A +++ b/bottleneck/tests/data/test_575_A diff --git a/geom_bottleneck/tests/data/test_575_B b/bottleneck/tests/data/test_575_B index a5ba6b7..a5ba6b7 100644 --- a/geom_bottleneck/tests/data/test_575_B +++ b/bottleneck/tests/data/test_575_B diff --git a/geom_bottleneck/tests/data/test_576_A b/bottleneck/tests/data/test_576_A index 57eb281..57eb281 100644 --- a/geom_bottleneck/tests/data/test_576_A +++ b/bottleneck/tests/data/test_576_A diff --git a/geom_bottleneck/tests/data/test_576_B b/bottleneck/tests/data/test_576_B index fa63de8..fa63de8 100644 --- a/geom_bottleneck/tests/data/test_576_B +++ b/bottleneck/tests/data/test_576_B diff --git a/geom_bottleneck/tests/data/test_577_A b/bottleneck/tests/data/test_577_A index d086e3f..d086e3f 100644 --- a/geom_bottleneck/tests/data/test_577_A +++ b/bottleneck/tests/data/test_577_A diff --git a/geom_bottleneck/tests/data/test_577_B b/bottleneck/tests/data/test_577_B index e48e09a..e48e09a 100644 --- a/geom_bottleneck/tests/data/test_577_B +++ b/bottleneck/tests/data/test_577_B diff --git a/geom_bottleneck/tests/data/test_578_A b/bottleneck/tests/data/test_578_A index 8b9a6fe..8b9a6fe 100644 --- a/geom_bottleneck/tests/data/test_578_A +++ b/bottleneck/tests/data/test_578_A diff --git a/geom_bottleneck/tests/data/test_578_B b/bottleneck/tests/data/test_578_B index 636f20d..636f20d 100644 --- a/geom_bottleneck/tests/data/test_578_B +++ b/bottleneck/tests/data/test_578_B diff --git a/geom_bottleneck/tests/data/test_579_A b/bottleneck/tests/data/test_579_A index 99bbb96..99bbb96 100644 --- a/geom_bottleneck/tests/data/test_579_A +++ b/bottleneck/tests/data/test_579_A diff --git a/geom_bottleneck/tests/data/test_579_B b/bottleneck/tests/data/test_579_B index 6d3e9b6..6d3e9b6 100644 --- a/geom_bottleneck/tests/data/test_579_B +++ b/bottleneck/tests/data/test_579_B diff --git a/geom_bottleneck/tests/data/test_580_A b/bottleneck/tests/data/test_580_A index b8d1c86..b8d1c86 100644 --- a/geom_bottleneck/tests/data/test_580_A +++ b/bottleneck/tests/data/test_580_A diff --git a/geom_bottleneck/tests/data/test_580_B b/bottleneck/tests/data/test_580_B index 1fd48af..1fd48af 100644 --- a/geom_bottleneck/tests/data/test_580_B +++ b/bottleneck/tests/data/test_580_B diff --git a/geom_bottleneck/tests/data/test_581_A b/bottleneck/tests/data/test_581_A index cf1555c..cf1555c 100644 --- a/geom_bottleneck/tests/data/test_581_A +++ b/bottleneck/tests/data/test_581_A diff --git a/geom_bottleneck/tests/data/test_581_B b/bottleneck/tests/data/test_581_B index 853ac92..853ac92 100644 --- a/geom_bottleneck/tests/data/test_581_B +++ b/bottleneck/tests/data/test_581_B diff --git a/geom_bottleneck/tests/data/test_582_A b/bottleneck/tests/data/test_582_A index dcabc9f..dcabc9f 100644 --- a/geom_bottleneck/tests/data/test_582_A +++ b/bottleneck/tests/data/test_582_A diff --git a/geom_bottleneck/tests/data/test_582_B b/bottleneck/tests/data/test_582_B index 9420fa9..9420fa9 100644 --- a/geom_bottleneck/tests/data/test_582_B +++ b/bottleneck/tests/data/test_582_B diff --git a/geom_bottleneck/tests/data/test_583_A b/bottleneck/tests/data/test_583_A index cc36f56..cc36f56 100644 --- a/geom_bottleneck/tests/data/test_583_A +++ b/bottleneck/tests/data/test_583_A diff --git a/geom_bottleneck/tests/data/test_583_B b/bottleneck/tests/data/test_583_B index d021fb3..d021fb3 100644 --- a/geom_bottleneck/tests/data/test_583_B +++ b/bottleneck/tests/data/test_583_B diff --git a/geom_bottleneck/tests/data/test_584_A b/bottleneck/tests/data/test_584_A index c934a50..c934a50 100644 --- a/geom_bottleneck/tests/data/test_584_A +++ b/bottleneck/tests/data/test_584_A diff --git a/geom_bottleneck/tests/data/test_584_B b/bottleneck/tests/data/test_584_B index 9f07efc..9f07efc 100644 --- a/geom_bottleneck/tests/data/test_584_B +++ b/bottleneck/tests/data/test_584_B diff --git a/geom_bottleneck/tests/data/test_585_A b/bottleneck/tests/data/test_585_A index 903e5b1..903e5b1 100644 --- a/geom_bottleneck/tests/data/test_585_A +++ b/bottleneck/tests/data/test_585_A diff --git a/geom_bottleneck/tests/data/test_585_B b/bottleneck/tests/data/test_585_B index 69f116a..69f116a 100644 --- a/geom_bottleneck/tests/data/test_585_B +++ b/bottleneck/tests/data/test_585_B diff --git a/geom_bottleneck/tests/data/test_586_A b/bottleneck/tests/data/test_586_A index ed8b673..ed8b673 100644 --- a/geom_bottleneck/tests/data/test_586_A +++ b/bottleneck/tests/data/test_586_A diff --git a/geom_bottleneck/tests/data/test_586_B b/bottleneck/tests/data/test_586_B index 715be5e..715be5e 100644 --- a/geom_bottleneck/tests/data/test_586_B +++ b/bottleneck/tests/data/test_586_B diff --git a/geom_bottleneck/tests/data/test_587_A b/bottleneck/tests/data/test_587_A index 883ddd7..883ddd7 100644 --- a/geom_bottleneck/tests/data/test_587_A +++ b/bottleneck/tests/data/test_587_A diff --git a/geom_bottleneck/tests/data/test_587_B b/bottleneck/tests/data/test_587_B index 589512c..589512c 100644 --- a/geom_bottleneck/tests/data/test_587_B +++ b/bottleneck/tests/data/test_587_B diff --git a/geom_bottleneck/tests/data/test_588_A b/bottleneck/tests/data/test_588_A index c486b96..c486b96 100644 --- a/geom_bottleneck/tests/data/test_588_A +++ b/bottleneck/tests/data/test_588_A diff --git a/geom_bottleneck/tests/data/test_588_B b/bottleneck/tests/data/test_588_B index 13829bc..13829bc 100644 --- a/geom_bottleneck/tests/data/test_588_B +++ b/bottleneck/tests/data/test_588_B diff --git a/geom_bottleneck/tests/data/test_589_A b/bottleneck/tests/data/test_589_A index 7743778..7743778 100644 --- a/geom_bottleneck/tests/data/test_589_A +++ b/bottleneck/tests/data/test_589_A diff --git a/geom_bottleneck/tests/data/test_589_B b/bottleneck/tests/data/test_589_B index bbd5038..bbd5038 100644 --- a/geom_bottleneck/tests/data/test_589_B +++ b/bottleneck/tests/data/test_589_B diff --git a/geom_bottleneck/tests/data/test_590_A b/bottleneck/tests/data/test_590_A index 3dfb2df..3dfb2df 100644 --- a/geom_bottleneck/tests/data/test_590_A +++ b/bottleneck/tests/data/test_590_A diff --git a/geom_bottleneck/tests/data/test_590_B b/bottleneck/tests/data/test_590_B index 18d6a7f..18d6a7f 100644 --- a/geom_bottleneck/tests/data/test_590_B +++ b/bottleneck/tests/data/test_590_B diff --git a/geom_bottleneck/tests/data/test_591_A b/bottleneck/tests/data/test_591_A index 411c1bb..411c1bb 100644 --- a/geom_bottleneck/tests/data/test_591_A +++ b/bottleneck/tests/data/test_591_A diff --git a/geom_bottleneck/tests/data/test_591_B b/bottleneck/tests/data/test_591_B index cc96d2f..cc96d2f 100644 --- a/geom_bottleneck/tests/data/test_591_B +++ b/bottleneck/tests/data/test_591_B diff --git a/geom_bottleneck/tests/data/test_592_A b/bottleneck/tests/data/test_592_A index bac0698..bac0698 100644 --- a/geom_bottleneck/tests/data/test_592_A +++ b/bottleneck/tests/data/test_592_A diff --git a/geom_bottleneck/tests/data/test_592_B b/bottleneck/tests/data/test_592_B index bc8a8c6..bc8a8c6 100644 --- a/geom_bottleneck/tests/data/test_592_B +++ b/bottleneck/tests/data/test_592_B diff --git a/geom_bottleneck/tests/data/test_593_A b/bottleneck/tests/data/test_593_A index e62ec21..e62ec21 100644 --- a/geom_bottleneck/tests/data/test_593_A +++ b/bottleneck/tests/data/test_593_A diff --git a/geom_bottleneck/tests/data/test_593_B b/bottleneck/tests/data/test_593_B index a5150da..a5150da 100644 --- a/geom_bottleneck/tests/data/test_593_B +++ b/bottleneck/tests/data/test_593_B diff --git a/geom_bottleneck/tests/data/test_594_A b/bottleneck/tests/data/test_594_A index ca81d4c..ca81d4c 100644 --- a/geom_bottleneck/tests/data/test_594_A +++ b/bottleneck/tests/data/test_594_A diff --git a/geom_bottleneck/tests/data/test_594_B b/bottleneck/tests/data/test_594_B index d366e85..d366e85 100644 --- a/geom_bottleneck/tests/data/test_594_B +++ b/bottleneck/tests/data/test_594_B diff --git a/geom_bottleneck/tests/data/test_595_A b/bottleneck/tests/data/test_595_A index 805de28..805de28 100644 --- a/geom_bottleneck/tests/data/test_595_A +++ b/bottleneck/tests/data/test_595_A diff --git a/geom_bottleneck/tests/data/test_595_B b/bottleneck/tests/data/test_595_B index c458a54..c458a54 100644 --- a/geom_bottleneck/tests/data/test_595_B +++ b/bottleneck/tests/data/test_595_B diff --git a/geom_bottleneck/tests/data/test_596_A b/bottleneck/tests/data/test_596_A index 3a32cf7..3a32cf7 100644 --- a/geom_bottleneck/tests/data/test_596_A +++ b/bottleneck/tests/data/test_596_A diff --git a/geom_bottleneck/tests/data/test_596_B b/bottleneck/tests/data/test_596_B index 1b9c765..1b9c765 100644 --- a/geom_bottleneck/tests/data/test_596_B +++ b/bottleneck/tests/data/test_596_B diff --git a/geom_bottleneck/tests/data/test_597_A b/bottleneck/tests/data/test_597_A index 984cc9f..984cc9f 100644 --- a/geom_bottleneck/tests/data/test_597_A +++ b/bottleneck/tests/data/test_597_A diff --git a/geom_bottleneck/tests/data/test_597_B b/bottleneck/tests/data/test_597_B index d84920c..d84920c 100644 --- a/geom_bottleneck/tests/data/test_597_B +++ b/bottleneck/tests/data/test_597_B diff --git a/geom_bottleneck/tests/data/test_598_A b/bottleneck/tests/data/test_598_A index 4c4fa46..4c4fa46 100644 --- a/geom_bottleneck/tests/data/test_598_A +++ b/bottleneck/tests/data/test_598_A diff --git a/geom_bottleneck/tests/data/test_598_B b/bottleneck/tests/data/test_598_B index 974d069..974d069 100644 --- a/geom_bottleneck/tests/data/test_598_B +++ b/bottleneck/tests/data/test_598_B diff --git a/geom_bottleneck/tests/data/test_599_A b/bottleneck/tests/data/test_599_A index 984a0ed..984a0ed 100644 --- a/geom_bottleneck/tests/data/test_599_A +++ b/bottleneck/tests/data/test_599_A diff --git a/geom_bottleneck/tests/data/test_599_B b/bottleneck/tests/data/test_599_B index aaea2a7..aaea2a7 100644 --- a/geom_bottleneck/tests/data/test_599_B +++ b/bottleneck/tests/data/test_599_B diff --git a/geom_bottleneck/tests/data/test_600_A b/bottleneck/tests/data/test_600_A index 13c5659..13c5659 100644 --- a/geom_bottleneck/tests/data/test_600_A +++ b/bottleneck/tests/data/test_600_A diff --git a/geom_bottleneck/tests/data/test_600_B b/bottleneck/tests/data/test_600_B index 5de1dfa..5de1dfa 100644 --- a/geom_bottleneck/tests/data/test_600_B +++ b/bottleneck/tests/data/test_600_B diff --git a/geom_bottleneck/tests/data/test_601_A b/bottleneck/tests/data/test_601_A index 9f57dd0..9f57dd0 100644 --- a/geom_bottleneck/tests/data/test_601_A +++ b/bottleneck/tests/data/test_601_A diff --git a/geom_bottleneck/tests/data/test_601_B b/bottleneck/tests/data/test_601_B index 64d7ef8..64d7ef8 100644 --- a/geom_bottleneck/tests/data/test_601_B +++ b/bottleneck/tests/data/test_601_B diff --git a/geom_bottleneck/tests/data/test_602_A b/bottleneck/tests/data/test_602_A index df83de7..df83de7 100644 --- a/geom_bottleneck/tests/data/test_602_A +++ b/bottleneck/tests/data/test_602_A diff --git a/geom_bottleneck/tests/data/test_602_B b/bottleneck/tests/data/test_602_B index fb19e1c..fb19e1c 100644 --- a/geom_bottleneck/tests/data/test_602_B +++ b/bottleneck/tests/data/test_602_B diff --git a/geom_bottleneck/tests/data/test_603_A b/bottleneck/tests/data/test_603_A index a81f6cb..a81f6cb 100644 --- a/geom_bottleneck/tests/data/test_603_A +++ b/bottleneck/tests/data/test_603_A diff --git a/geom_bottleneck/tests/data/test_603_B b/bottleneck/tests/data/test_603_B index 0ea6eda..0ea6eda 100644 --- a/geom_bottleneck/tests/data/test_603_B +++ b/bottleneck/tests/data/test_603_B diff --git a/geom_bottleneck/tests/data/test_604_A b/bottleneck/tests/data/test_604_A index 11a7c84..11a7c84 100644 --- a/geom_bottleneck/tests/data/test_604_A +++ b/bottleneck/tests/data/test_604_A diff --git a/geom_bottleneck/tests/data/test_604_B b/bottleneck/tests/data/test_604_B index 6e14339..6e14339 100644 --- a/geom_bottleneck/tests/data/test_604_B +++ b/bottleneck/tests/data/test_604_B diff --git a/geom_bottleneck/tests/data/test_605_A b/bottleneck/tests/data/test_605_A index 522dbf9..522dbf9 100644 --- a/geom_bottleneck/tests/data/test_605_A +++ b/bottleneck/tests/data/test_605_A diff --git a/geom_bottleneck/tests/data/test_605_B b/bottleneck/tests/data/test_605_B index 34f19db..34f19db 100644 --- a/geom_bottleneck/tests/data/test_605_B +++ b/bottleneck/tests/data/test_605_B diff --git a/geom_bottleneck/tests/data/test_606_A b/bottleneck/tests/data/test_606_A index 2f4dec4..2f4dec4 100644 --- a/geom_bottleneck/tests/data/test_606_A +++ b/bottleneck/tests/data/test_606_A diff --git a/geom_bottleneck/tests/data/test_606_B b/bottleneck/tests/data/test_606_B index 62417b1..62417b1 100644 --- a/geom_bottleneck/tests/data/test_606_B +++ b/bottleneck/tests/data/test_606_B diff --git a/geom_bottleneck/tests/data/test_607_A b/bottleneck/tests/data/test_607_A index abc3b6b..abc3b6b 100644 --- a/geom_bottleneck/tests/data/test_607_A +++ b/bottleneck/tests/data/test_607_A diff --git a/geom_bottleneck/tests/data/test_607_B b/bottleneck/tests/data/test_607_B index 0f79931..0f79931 100644 --- a/geom_bottleneck/tests/data/test_607_B +++ b/bottleneck/tests/data/test_607_B diff --git a/geom_bottleneck/tests/data/test_608_A b/bottleneck/tests/data/test_608_A index a4beccc..a4beccc 100644 --- a/geom_bottleneck/tests/data/test_608_A +++ b/bottleneck/tests/data/test_608_A diff --git a/geom_bottleneck/tests/data/test_608_B b/bottleneck/tests/data/test_608_B index 94f4c9a..94f4c9a 100644 --- a/geom_bottleneck/tests/data/test_608_B +++ b/bottleneck/tests/data/test_608_B diff --git a/geom_bottleneck/tests/data/test_609_A b/bottleneck/tests/data/test_609_A index a8e841e..a8e841e 100644 --- a/geom_bottleneck/tests/data/test_609_A +++ b/bottleneck/tests/data/test_609_A diff --git a/geom_bottleneck/tests/data/test_609_B b/bottleneck/tests/data/test_609_B index 574351a..574351a 100644 --- a/geom_bottleneck/tests/data/test_609_B +++ b/bottleneck/tests/data/test_609_B diff --git a/geom_bottleneck/tests/data/test_610_A b/bottleneck/tests/data/test_610_A index c37fa9c..c37fa9c 100644 --- a/geom_bottleneck/tests/data/test_610_A +++ b/bottleneck/tests/data/test_610_A diff --git a/geom_bottleneck/tests/data/test_610_B b/bottleneck/tests/data/test_610_B index 0745255..0745255 100644 --- a/geom_bottleneck/tests/data/test_610_B +++ b/bottleneck/tests/data/test_610_B diff --git a/geom_bottleneck/tests/data/test_611_A b/bottleneck/tests/data/test_611_A index f7cfbbe..f7cfbbe 100644 --- a/geom_bottleneck/tests/data/test_611_A +++ b/bottleneck/tests/data/test_611_A diff --git a/geom_bottleneck/tests/data/test_611_B b/bottleneck/tests/data/test_611_B index ffc3bf6..ffc3bf6 100644 --- a/geom_bottleneck/tests/data/test_611_B +++ b/bottleneck/tests/data/test_611_B diff --git a/geom_bottleneck/tests/data/test_612_A b/bottleneck/tests/data/test_612_A index 1d08d30..1d08d30 100644 --- a/geom_bottleneck/tests/data/test_612_A +++ b/bottleneck/tests/data/test_612_A diff --git a/geom_bottleneck/tests/data/test_612_B b/bottleneck/tests/data/test_612_B index 712c645..712c645 100644 --- a/geom_bottleneck/tests/data/test_612_B +++ b/bottleneck/tests/data/test_612_B diff --git a/geom_bottleneck/tests/data/test_613_A b/bottleneck/tests/data/test_613_A index 909c462..909c462 100644 --- a/geom_bottleneck/tests/data/test_613_A +++ b/bottleneck/tests/data/test_613_A diff --git a/geom_bottleneck/tests/data/test_613_B b/bottleneck/tests/data/test_613_B index 9569b49..9569b49 100644 --- a/geom_bottleneck/tests/data/test_613_B +++ b/bottleneck/tests/data/test_613_B diff --git a/geom_bottleneck/tests/data/test_614_A b/bottleneck/tests/data/test_614_A index 29c02c8..29c02c8 100644 --- a/geom_bottleneck/tests/data/test_614_A +++ b/bottleneck/tests/data/test_614_A diff --git a/geom_bottleneck/tests/data/test_614_B b/bottleneck/tests/data/test_614_B index f34b836..f34b836 100644 --- a/geom_bottleneck/tests/data/test_614_B +++ b/bottleneck/tests/data/test_614_B diff --git a/geom_bottleneck/tests/data/test_615_A b/bottleneck/tests/data/test_615_A index d1b55eb..d1b55eb 100644 --- a/geom_bottleneck/tests/data/test_615_A +++ b/bottleneck/tests/data/test_615_A diff --git a/geom_bottleneck/tests/data/test_615_B b/bottleneck/tests/data/test_615_B index ab204be..ab204be 100644 --- a/geom_bottleneck/tests/data/test_615_B +++ b/bottleneck/tests/data/test_615_B diff --git a/geom_bottleneck/tests/data/test_616_A b/bottleneck/tests/data/test_616_A index 2b99b87..2b99b87 100644 --- a/geom_bottleneck/tests/data/test_616_A +++ b/bottleneck/tests/data/test_616_A diff --git a/geom_bottleneck/tests/data/test_616_B b/bottleneck/tests/data/test_616_B index 55a8c9f..55a8c9f 100644 --- a/geom_bottleneck/tests/data/test_616_B +++ b/bottleneck/tests/data/test_616_B diff --git a/geom_bottleneck/tests/data/test_617_A b/bottleneck/tests/data/test_617_A index 9eb04ba..9eb04ba 100644 --- a/geom_bottleneck/tests/data/test_617_A +++ b/bottleneck/tests/data/test_617_A diff --git a/geom_bottleneck/tests/data/test_617_B b/bottleneck/tests/data/test_617_B index eb300a8..eb300a8 100644 --- a/geom_bottleneck/tests/data/test_617_B +++ b/bottleneck/tests/data/test_617_B diff --git a/geom_bottleneck/tests/data/test_618_A b/bottleneck/tests/data/test_618_A index a53c5f8..a53c5f8 100644 --- a/geom_bottleneck/tests/data/test_618_A +++ b/bottleneck/tests/data/test_618_A diff --git a/geom_bottleneck/tests/data/test_618_B b/bottleneck/tests/data/test_618_B index 611fb6a..611fb6a 100644 --- a/geom_bottleneck/tests/data/test_618_B +++ b/bottleneck/tests/data/test_618_B diff --git a/geom_bottleneck/tests/data/test_619_A b/bottleneck/tests/data/test_619_A index 4dd6557..4dd6557 100644 --- a/geom_bottleneck/tests/data/test_619_A +++ b/bottleneck/tests/data/test_619_A diff --git a/geom_bottleneck/tests/data/test_619_B b/bottleneck/tests/data/test_619_B index 711d7cb..711d7cb 100644 --- a/geom_bottleneck/tests/data/test_619_B +++ b/bottleneck/tests/data/test_619_B diff --git a/geom_bottleneck/tests/data/test_620_A b/bottleneck/tests/data/test_620_A index 74e7856..74e7856 100644 --- a/geom_bottleneck/tests/data/test_620_A +++ b/bottleneck/tests/data/test_620_A diff --git a/geom_bottleneck/tests/data/test_620_B b/bottleneck/tests/data/test_620_B index e7efa97..e7efa97 100644 --- a/geom_bottleneck/tests/data/test_620_B +++ b/bottleneck/tests/data/test_620_B diff --git a/geom_bottleneck/tests/data/test_621_A b/bottleneck/tests/data/test_621_A index 6a24523..6a24523 100644 --- a/geom_bottleneck/tests/data/test_621_A +++ b/bottleneck/tests/data/test_621_A diff --git a/geom_bottleneck/tests/data/test_621_B b/bottleneck/tests/data/test_621_B index 7b49acb..7b49acb 100644 --- a/geom_bottleneck/tests/data/test_621_B +++ b/bottleneck/tests/data/test_621_B diff --git a/geom_bottleneck/tests/data/test_622_A b/bottleneck/tests/data/test_622_A index 58d67ac..58d67ac 100644 --- a/geom_bottleneck/tests/data/test_622_A +++ b/bottleneck/tests/data/test_622_A diff --git a/geom_bottleneck/tests/data/test_622_B b/bottleneck/tests/data/test_622_B index f9a4fdd..f9a4fdd 100644 --- a/geom_bottleneck/tests/data/test_622_B +++ b/bottleneck/tests/data/test_622_B diff --git a/geom_bottleneck/tests/data/test_623_A b/bottleneck/tests/data/test_623_A index 8d99200..8d99200 100644 --- a/geom_bottleneck/tests/data/test_623_A +++ b/bottleneck/tests/data/test_623_A diff --git a/geom_bottleneck/tests/data/test_623_B b/bottleneck/tests/data/test_623_B index 22ab9fd..22ab9fd 100644 --- a/geom_bottleneck/tests/data/test_623_B +++ b/bottleneck/tests/data/test_623_B diff --git a/geom_bottleneck/tests/data/test_624_A b/bottleneck/tests/data/test_624_A index 49891f6..49891f6 100644 --- a/geom_bottleneck/tests/data/test_624_A +++ b/bottleneck/tests/data/test_624_A diff --git a/geom_bottleneck/tests/data/test_624_B b/bottleneck/tests/data/test_624_B index fa3e1ea..fa3e1ea 100644 --- a/geom_bottleneck/tests/data/test_624_B +++ b/bottleneck/tests/data/test_624_B diff --git a/geom_bottleneck/tests/data/test_625_A b/bottleneck/tests/data/test_625_A index 4da6ce4..4da6ce4 100644 --- a/geom_bottleneck/tests/data/test_625_A +++ b/bottleneck/tests/data/test_625_A diff --git a/geom_bottleneck/tests/data/test_625_B b/bottleneck/tests/data/test_625_B index bf587fc..bf587fc 100644 --- a/geom_bottleneck/tests/data/test_625_B +++ b/bottleneck/tests/data/test_625_B diff --git a/geom_bottleneck/tests/data/test_626_A b/bottleneck/tests/data/test_626_A index 92036c8..92036c8 100644 --- a/geom_bottleneck/tests/data/test_626_A +++ b/bottleneck/tests/data/test_626_A diff --git a/geom_bottleneck/tests/data/test_626_B b/bottleneck/tests/data/test_626_B index 3052b59..3052b59 100644 --- a/geom_bottleneck/tests/data/test_626_B +++ b/bottleneck/tests/data/test_626_B diff --git a/geom_bottleneck/tests/data/test_627_A b/bottleneck/tests/data/test_627_A index f682247..f682247 100644 --- a/geom_bottleneck/tests/data/test_627_A +++ b/bottleneck/tests/data/test_627_A diff --git a/geom_bottleneck/tests/data/test_627_B b/bottleneck/tests/data/test_627_B index 7c61fad..7c61fad 100644 --- a/geom_bottleneck/tests/data/test_627_B +++ b/bottleneck/tests/data/test_627_B diff --git a/geom_bottleneck/tests/data/test_628_A b/bottleneck/tests/data/test_628_A index f499ec3..f499ec3 100644 --- a/geom_bottleneck/tests/data/test_628_A +++ b/bottleneck/tests/data/test_628_A diff --git a/geom_bottleneck/tests/data/test_628_B b/bottleneck/tests/data/test_628_B index 5eb5994..5eb5994 100644 --- a/geom_bottleneck/tests/data/test_628_B +++ b/bottleneck/tests/data/test_628_B diff --git a/geom_bottleneck/tests/data/test_629_A b/bottleneck/tests/data/test_629_A index ff42c12..ff42c12 100644 --- a/geom_bottleneck/tests/data/test_629_A +++ b/bottleneck/tests/data/test_629_A diff --git a/geom_bottleneck/tests/data/test_629_B b/bottleneck/tests/data/test_629_B index b0b983a..b0b983a 100644 --- a/geom_bottleneck/tests/data/test_629_B +++ b/bottleneck/tests/data/test_629_B diff --git a/geom_bottleneck/tests/data/test_630_A b/bottleneck/tests/data/test_630_A index 6ed10cf..6ed10cf 100644 --- a/geom_bottleneck/tests/data/test_630_A +++ b/bottleneck/tests/data/test_630_A diff --git a/geom_bottleneck/tests/data/test_630_B b/bottleneck/tests/data/test_630_B index 0583a0c..0583a0c 100644 --- a/geom_bottleneck/tests/data/test_630_B +++ b/bottleneck/tests/data/test_630_B diff --git a/geom_bottleneck/tests/data/test_631_A b/bottleneck/tests/data/test_631_A index d49637c..d49637c 100644 --- a/geom_bottleneck/tests/data/test_631_A +++ b/bottleneck/tests/data/test_631_A diff --git a/geom_bottleneck/tests/data/test_631_B b/bottleneck/tests/data/test_631_B index f522f48..f522f48 100644 --- a/geom_bottleneck/tests/data/test_631_B +++ b/bottleneck/tests/data/test_631_B diff --git a/geom_bottleneck/tests/data/test_632_A b/bottleneck/tests/data/test_632_A index 32c4757..32c4757 100644 --- a/geom_bottleneck/tests/data/test_632_A +++ b/bottleneck/tests/data/test_632_A diff --git a/geom_bottleneck/tests/data/test_632_B b/bottleneck/tests/data/test_632_B index f50a6bb..f50a6bb 100644 --- a/geom_bottleneck/tests/data/test_632_B +++ b/bottleneck/tests/data/test_632_B diff --git a/geom_bottleneck/tests/data/test_633_A b/bottleneck/tests/data/test_633_A index 0199c88..0199c88 100644 --- a/geom_bottleneck/tests/data/test_633_A +++ b/bottleneck/tests/data/test_633_A diff --git a/geom_bottleneck/tests/data/test_633_B b/bottleneck/tests/data/test_633_B index d516834..d516834 100644 --- a/geom_bottleneck/tests/data/test_633_B +++ b/bottleneck/tests/data/test_633_B diff --git a/geom_bottleneck/tests/data/test_634_A b/bottleneck/tests/data/test_634_A index 45493ad..45493ad 100644 --- a/geom_bottleneck/tests/data/test_634_A +++ b/bottleneck/tests/data/test_634_A diff --git a/geom_bottleneck/tests/data/test_634_B b/bottleneck/tests/data/test_634_B index 8840b3a..8840b3a 100644 --- a/geom_bottleneck/tests/data/test_634_B +++ b/bottleneck/tests/data/test_634_B diff --git a/geom_bottleneck/tests/data/test_635_A b/bottleneck/tests/data/test_635_A index d65240b..d65240b 100644 --- a/geom_bottleneck/tests/data/test_635_A +++ b/bottleneck/tests/data/test_635_A diff --git a/geom_bottleneck/tests/data/test_635_B b/bottleneck/tests/data/test_635_B index 8cc813d..8cc813d 100644 --- a/geom_bottleneck/tests/data/test_635_B +++ b/bottleneck/tests/data/test_635_B diff --git a/geom_bottleneck/tests/data/test_636_A b/bottleneck/tests/data/test_636_A index eee9635..eee9635 100644 --- a/geom_bottleneck/tests/data/test_636_A +++ b/bottleneck/tests/data/test_636_A diff --git a/geom_bottleneck/tests/data/test_636_B b/bottleneck/tests/data/test_636_B index e565845..e565845 100644 --- a/geom_bottleneck/tests/data/test_636_B +++ b/bottleneck/tests/data/test_636_B diff --git a/geom_bottleneck/tests/data/test_637_A b/bottleneck/tests/data/test_637_A index 4ba4314..4ba4314 100644 --- a/geom_bottleneck/tests/data/test_637_A +++ b/bottleneck/tests/data/test_637_A diff --git a/geom_bottleneck/tests/data/test_637_B b/bottleneck/tests/data/test_637_B index 58aba0f..58aba0f 100644 --- a/geom_bottleneck/tests/data/test_637_B +++ b/bottleneck/tests/data/test_637_B diff --git a/geom_bottleneck/tests/data/test_638_A b/bottleneck/tests/data/test_638_A index 4d993df..4d993df 100644 --- a/geom_bottleneck/tests/data/test_638_A +++ b/bottleneck/tests/data/test_638_A diff --git a/geom_bottleneck/tests/data/test_638_B b/bottleneck/tests/data/test_638_B index 5750b40..5750b40 100644 --- a/geom_bottleneck/tests/data/test_638_B +++ b/bottleneck/tests/data/test_638_B diff --git a/geom_bottleneck/tests/data/test_639_A b/bottleneck/tests/data/test_639_A index 1e86c9b..1e86c9b 100644 --- a/geom_bottleneck/tests/data/test_639_A +++ b/bottleneck/tests/data/test_639_A diff --git a/geom_bottleneck/tests/data/test_639_B b/bottleneck/tests/data/test_639_B index 758fe2d..758fe2d 100644 --- a/geom_bottleneck/tests/data/test_639_B +++ b/bottleneck/tests/data/test_639_B diff --git a/geom_bottleneck/tests/data/test_640_A b/bottleneck/tests/data/test_640_A index 981248a..981248a 100644 --- a/geom_bottleneck/tests/data/test_640_A +++ b/bottleneck/tests/data/test_640_A diff --git a/geom_bottleneck/tests/data/test_640_B b/bottleneck/tests/data/test_640_B index d4f75ec..d4f75ec 100644 --- a/geom_bottleneck/tests/data/test_640_B +++ b/bottleneck/tests/data/test_640_B diff --git a/geom_bottleneck/tests/data/test_641_A b/bottleneck/tests/data/test_641_A index 04100b0..04100b0 100644 --- a/geom_bottleneck/tests/data/test_641_A +++ b/bottleneck/tests/data/test_641_A diff --git a/geom_bottleneck/tests/data/test_641_B b/bottleneck/tests/data/test_641_B index 840a640..840a640 100644 --- a/geom_bottleneck/tests/data/test_641_B +++ b/bottleneck/tests/data/test_641_B diff --git a/geom_bottleneck/tests/data/test_642_A b/bottleneck/tests/data/test_642_A index a7da9ec..a7da9ec 100644 --- a/geom_bottleneck/tests/data/test_642_A +++ b/bottleneck/tests/data/test_642_A diff --git a/geom_bottleneck/tests/data/test_642_B b/bottleneck/tests/data/test_642_B index e25e427..e25e427 100644 --- a/geom_bottleneck/tests/data/test_642_B +++ b/bottleneck/tests/data/test_642_B diff --git a/geom_bottleneck/tests/data/test_643_A b/bottleneck/tests/data/test_643_A index e818bdc..e818bdc 100644 --- a/geom_bottleneck/tests/data/test_643_A +++ b/bottleneck/tests/data/test_643_A diff --git a/geom_bottleneck/tests/data/test_643_B b/bottleneck/tests/data/test_643_B index 7a5f620..7a5f620 100644 --- a/geom_bottleneck/tests/data/test_643_B +++ b/bottleneck/tests/data/test_643_B diff --git a/geom_bottleneck/tests/data/test_644_A b/bottleneck/tests/data/test_644_A index f6bc335..f6bc335 100644 --- a/geom_bottleneck/tests/data/test_644_A +++ b/bottleneck/tests/data/test_644_A diff --git a/geom_bottleneck/tests/data/test_644_B b/bottleneck/tests/data/test_644_B index 109024d..109024d 100644 --- a/geom_bottleneck/tests/data/test_644_B +++ b/bottleneck/tests/data/test_644_B diff --git a/geom_bottleneck/tests/data/test_645_A b/bottleneck/tests/data/test_645_A index 3f62c52..3f62c52 100644 --- a/geom_bottleneck/tests/data/test_645_A +++ b/bottleneck/tests/data/test_645_A diff --git a/geom_bottleneck/tests/data/test_645_B b/bottleneck/tests/data/test_645_B index f818161..f818161 100644 --- a/geom_bottleneck/tests/data/test_645_B +++ b/bottleneck/tests/data/test_645_B diff --git a/geom_bottleneck/tests/data/test_646_A b/bottleneck/tests/data/test_646_A index 7582a95..7582a95 100644 --- a/geom_bottleneck/tests/data/test_646_A +++ b/bottleneck/tests/data/test_646_A diff --git a/geom_bottleneck/tests/data/test_646_B b/bottleneck/tests/data/test_646_B index af402f8..af402f8 100644 --- a/geom_bottleneck/tests/data/test_646_B +++ b/bottleneck/tests/data/test_646_B diff --git a/geom_bottleneck/tests/data/test_647_A b/bottleneck/tests/data/test_647_A index caa678f..caa678f 100644 --- a/geom_bottleneck/tests/data/test_647_A +++ b/bottleneck/tests/data/test_647_A diff --git a/geom_bottleneck/tests/data/test_647_B b/bottleneck/tests/data/test_647_B index a135f9e..a135f9e 100644 --- a/geom_bottleneck/tests/data/test_647_B +++ b/bottleneck/tests/data/test_647_B diff --git a/geom_bottleneck/tests/data/test_648_A b/bottleneck/tests/data/test_648_A index 35e36b8..35e36b8 100644 --- a/geom_bottleneck/tests/data/test_648_A +++ b/bottleneck/tests/data/test_648_A diff --git a/geom_bottleneck/tests/data/test_648_B b/bottleneck/tests/data/test_648_B index 8a28c4a..8a28c4a 100644 --- a/geom_bottleneck/tests/data/test_648_B +++ b/bottleneck/tests/data/test_648_B diff --git a/geom_bottleneck/tests/data/test_649_A b/bottleneck/tests/data/test_649_A index 065cc77..065cc77 100644 --- a/geom_bottleneck/tests/data/test_649_A +++ b/bottleneck/tests/data/test_649_A diff --git a/geom_bottleneck/tests/data/test_649_B b/bottleneck/tests/data/test_649_B index b23411e..b23411e 100644 --- a/geom_bottleneck/tests/data/test_649_B +++ b/bottleneck/tests/data/test_649_B diff --git a/geom_bottleneck/tests/data/test_650_A b/bottleneck/tests/data/test_650_A index d87b7b4..d87b7b4 100644 --- a/geom_bottleneck/tests/data/test_650_A +++ b/bottleneck/tests/data/test_650_A diff --git a/geom_bottleneck/tests/data/test_650_B b/bottleneck/tests/data/test_650_B index f379676..f379676 100644 --- a/geom_bottleneck/tests/data/test_650_B +++ b/bottleneck/tests/data/test_650_B diff --git a/geom_bottleneck/tests/data/test_651_A b/bottleneck/tests/data/test_651_A index ecf506a..ecf506a 100644 --- a/geom_bottleneck/tests/data/test_651_A +++ b/bottleneck/tests/data/test_651_A diff --git a/geom_bottleneck/tests/data/test_651_B b/bottleneck/tests/data/test_651_B index f05128d..f05128d 100644 --- a/geom_bottleneck/tests/data/test_651_B +++ b/bottleneck/tests/data/test_651_B diff --git a/geom_bottleneck/tests/data/test_652_A b/bottleneck/tests/data/test_652_A index 52d5bdf..52d5bdf 100644 --- a/geom_bottleneck/tests/data/test_652_A +++ b/bottleneck/tests/data/test_652_A diff --git a/geom_bottleneck/tests/data/test_652_B b/bottleneck/tests/data/test_652_B index 2b12de5..2b12de5 100644 --- a/geom_bottleneck/tests/data/test_652_B +++ b/bottleneck/tests/data/test_652_B diff --git a/geom_bottleneck/tests/data/test_653_A b/bottleneck/tests/data/test_653_A index b4bbdd3..b4bbdd3 100644 --- a/geom_bottleneck/tests/data/test_653_A +++ b/bottleneck/tests/data/test_653_A diff --git a/geom_bottleneck/tests/data/test_653_B b/bottleneck/tests/data/test_653_B index f349693..f349693 100644 --- a/geom_bottleneck/tests/data/test_653_B +++ b/bottleneck/tests/data/test_653_B diff --git a/geom_bottleneck/tests/data/test_654_A b/bottleneck/tests/data/test_654_A index d090ad8..d090ad8 100644 --- a/geom_bottleneck/tests/data/test_654_A +++ b/bottleneck/tests/data/test_654_A diff --git a/geom_bottleneck/tests/data/test_654_B b/bottleneck/tests/data/test_654_B index f9944d7..f9944d7 100644 --- a/geom_bottleneck/tests/data/test_654_B +++ b/bottleneck/tests/data/test_654_B diff --git a/geom_bottleneck/tests/data/test_655_A b/bottleneck/tests/data/test_655_A index 9105397..9105397 100644 --- a/geom_bottleneck/tests/data/test_655_A +++ b/bottleneck/tests/data/test_655_A diff --git a/geom_bottleneck/tests/data/test_655_B b/bottleneck/tests/data/test_655_B index 9aa2ab6..9aa2ab6 100644 --- a/geom_bottleneck/tests/data/test_655_B +++ b/bottleneck/tests/data/test_655_B diff --git a/geom_bottleneck/tests/data/test_656_A b/bottleneck/tests/data/test_656_A index bcdfd3c..bcdfd3c 100644 --- a/geom_bottleneck/tests/data/test_656_A +++ b/bottleneck/tests/data/test_656_A diff --git a/geom_bottleneck/tests/data/test_656_B b/bottleneck/tests/data/test_656_B index 5ee0ab0..5ee0ab0 100644 --- a/geom_bottleneck/tests/data/test_656_B +++ b/bottleneck/tests/data/test_656_B diff --git a/geom_bottleneck/tests/data/test_657_A b/bottleneck/tests/data/test_657_A index 7d39a99..7d39a99 100644 --- a/geom_bottleneck/tests/data/test_657_A +++ b/bottleneck/tests/data/test_657_A diff --git a/geom_bottleneck/tests/data/test_657_B b/bottleneck/tests/data/test_657_B index 3b9d726..3b9d726 100644 --- a/geom_bottleneck/tests/data/test_657_B +++ b/bottleneck/tests/data/test_657_B diff --git a/geom_bottleneck/tests/data/test_658_A b/bottleneck/tests/data/test_658_A index 33f8b08..33f8b08 100644 --- a/geom_bottleneck/tests/data/test_658_A +++ b/bottleneck/tests/data/test_658_A diff --git a/geom_bottleneck/tests/data/test_658_B b/bottleneck/tests/data/test_658_B index b131e5d..b131e5d 100644 --- a/geom_bottleneck/tests/data/test_658_B +++ b/bottleneck/tests/data/test_658_B diff --git a/geom_bottleneck/tests/data/test_659_A b/bottleneck/tests/data/test_659_A index 974d216..974d216 100644 --- a/geom_bottleneck/tests/data/test_659_A +++ b/bottleneck/tests/data/test_659_A diff --git a/geom_bottleneck/tests/data/test_659_B b/bottleneck/tests/data/test_659_B index c3cfbeb..c3cfbeb 100644 --- a/geom_bottleneck/tests/data/test_659_B +++ b/bottleneck/tests/data/test_659_B diff --git a/geom_bottleneck/tests/data/test_660_A b/bottleneck/tests/data/test_660_A index 1c408f3..1c408f3 100644 --- a/geom_bottleneck/tests/data/test_660_A +++ b/bottleneck/tests/data/test_660_A diff --git a/geom_bottleneck/tests/data/test_660_B b/bottleneck/tests/data/test_660_B index 5fffa69..5fffa69 100644 --- a/geom_bottleneck/tests/data/test_660_B +++ b/bottleneck/tests/data/test_660_B diff --git a/geom_bottleneck/tests/data/test_661_A b/bottleneck/tests/data/test_661_A index df0d8ad..df0d8ad 100644 --- a/geom_bottleneck/tests/data/test_661_A +++ b/bottleneck/tests/data/test_661_A diff --git a/geom_bottleneck/tests/data/test_661_B b/bottleneck/tests/data/test_661_B index 56cfa0c..56cfa0c 100644 --- a/geom_bottleneck/tests/data/test_661_B +++ b/bottleneck/tests/data/test_661_B diff --git a/geom_bottleneck/tests/data/test_662_A b/bottleneck/tests/data/test_662_A index cb65a38..cb65a38 100644 --- a/geom_bottleneck/tests/data/test_662_A +++ b/bottleneck/tests/data/test_662_A diff --git a/geom_bottleneck/tests/data/test_662_B b/bottleneck/tests/data/test_662_B index 92f0ee6..92f0ee6 100644 --- a/geom_bottleneck/tests/data/test_662_B +++ b/bottleneck/tests/data/test_662_B diff --git a/geom_bottleneck/tests/data/test_663_A b/bottleneck/tests/data/test_663_A index ed35031..ed35031 100644 --- a/geom_bottleneck/tests/data/test_663_A +++ b/bottleneck/tests/data/test_663_A diff --git a/geom_bottleneck/tests/data/test_663_B b/bottleneck/tests/data/test_663_B index 6a6126c..6a6126c 100644 --- a/geom_bottleneck/tests/data/test_663_B +++ b/bottleneck/tests/data/test_663_B diff --git a/geom_bottleneck/tests/data/test_664_A b/bottleneck/tests/data/test_664_A index 59f6bfa..59f6bfa 100644 --- a/geom_bottleneck/tests/data/test_664_A +++ b/bottleneck/tests/data/test_664_A diff --git a/geom_bottleneck/tests/data/test_664_B b/bottleneck/tests/data/test_664_B index 6b34a5f..6b34a5f 100644 --- a/geom_bottleneck/tests/data/test_664_B +++ b/bottleneck/tests/data/test_664_B diff --git a/geom_bottleneck/tests/data/test_665_A b/bottleneck/tests/data/test_665_A index ff6ce72..ff6ce72 100644 --- a/geom_bottleneck/tests/data/test_665_A +++ b/bottleneck/tests/data/test_665_A diff --git a/geom_bottleneck/tests/data/test_665_B b/bottleneck/tests/data/test_665_B index 9a5d4a9..9a5d4a9 100644 --- a/geom_bottleneck/tests/data/test_665_B +++ b/bottleneck/tests/data/test_665_B diff --git a/geom_bottleneck/tests/data/test_666_A b/bottleneck/tests/data/test_666_A index 455e262..455e262 100644 --- a/geom_bottleneck/tests/data/test_666_A +++ b/bottleneck/tests/data/test_666_A diff --git a/geom_bottleneck/tests/data/test_666_B b/bottleneck/tests/data/test_666_B index 0c9069e..0c9069e 100644 --- a/geom_bottleneck/tests/data/test_666_B +++ b/bottleneck/tests/data/test_666_B diff --git a/geom_bottleneck/tests/data/test_667_A b/bottleneck/tests/data/test_667_A index 054d14e..054d14e 100644 --- a/geom_bottleneck/tests/data/test_667_A +++ b/bottleneck/tests/data/test_667_A diff --git a/geom_bottleneck/tests/data/test_667_B b/bottleneck/tests/data/test_667_B index a4a432a..a4a432a 100644 --- a/geom_bottleneck/tests/data/test_667_B +++ b/bottleneck/tests/data/test_667_B diff --git a/geom_bottleneck/tests/data/test_668_A b/bottleneck/tests/data/test_668_A index 00c5554..00c5554 100644 --- a/geom_bottleneck/tests/data/test_668_A +++ b/bottleneck/tests/data/test_668_A diff --git a/geom_bottleneck/tests/data/test_668_B b/bottleneck/tests/data/test_668_B index 5b7e07c..5b7e07c 100644 --- a/geom_bottleneck/tests/data/test_668_B +++ b/bottleneck/tests/data/test_668_B diff --git a/geom_bottleneck/tests/data/test_669_A b/bottleneck/tests/data/test_669_A index 2abb014..2abb014 100644 --- a/geom_bottleneck/tests/data/test_669_A +++ b/bottleneck/tests/data/test_669_A diff --git a/geom_bottleneck/tests/data/test_669_B b/bottleneck/tests/data/test_669_B index 5694ce9..5694ce9 100644 --- a/geom_bottleneck/tests/data/test_669_B +++ b/bottleneck/tests/data/test_669_B diff --git a/geom_bottleneck/tests/data/test_670_A b/bottleneck/tests/data/test_670_A index e7ae4f1..e7ae4f1 100644 --- a/geom_bottleneck/tests/data/test_670_A +++ b/bottleneck/tests/data/test_670_A diff --git a/geom_bottleneck/tests/data/test_670_B b/bottleneck/tests/data/test_670_B index 8f6b057..8f6b057 100644 --- a/geom_bottleneck/tests/data/test_670_B +++ b/bottleneck/tests/data/test_670_B diff --git a/geom_bottleneck/tests/data/test_671_A b/bottleneck/tests/data/test_671_A index 8ac70f3..8ac70f3 100644 --- a/geom_bottleneck/tests/data/test_671_A +++ b/bottleneck/tests/data/test_671_A diff --git a/geom_bottleneck/tests/data/test_671_B b/bottleneck/tests/data/test_671_B index bcb5f1b..bcb5f1b 100644 --- a/geom_bottleneck/tests/data/test_671_B +++ b/bottleneck/tests/data/test_671_B diff --git a/geom_bottleneck/tests/data/test_672_A b/bottleneck/tests/data/test_672_A index 4ca2b19..4ca2b19 100644 --- a/geom_bottleneck/tests/data/test_672_A +++ b/bottleneck/tests/data/test_672_A diff --git a/geom_bottleneck/tests/data/test_672_B b/bottleneck/tests/data/test_672_B index 29b8d76..29b8d76 100644 --- a/geom_bottleneck/tests/data/test_672_B +++ b/bottleneck/tests/data/test_672_B diff --git a/geom_bottleneck/tests/data/test_673_A b/bottleneck/tests/data/test_673_A index f6e6e4a..f6e6e4a 100644 --- a/geom_bottleneck/tests/data/test_673_A +++ b/bottleneck/tests/data/test_673_A diff --git a/geom_bottleneck/tests/data/test_673_B b/bottleneck/tests/data/test_673_B index 01ac9c7..01ac9c7 100644 --- a/geom_bottleneck/tests/data/test_673_B +++ b/bottleneck/tests/data/test_673_B diff --git a/geom_bottleneck/tests/data/test_674_A b/bottleneck/tests/data/test_674_A index 8bbf6ad..8bbf6ad 100644 --- a/geom_bottleneck/tests/data/test_674_A +++ b/bottleneck/tests/data/test_674_A diff --git a/geom_bottleneck/tests/data/test_674_B b/bottleneck/tests/data/test_674_B index ddebd4c..ddebd4c 100644 --- a/geom_bottleneck/tests/data/test_674_B +++ b/bottleneck/tests/data/test_674_B diff --git a/geom_bottleneck/tests/data/test_675_A b/bottleneck/tests/data/test_675_A index 30b36bb..30b36bb 100644 --- a/geom_bottleneck/tests/data/test_675_A +++ b/bottleneck/tests/data/test_675_A diff --git a/geom_bottleneck/tests/data/test_675_B b/bottleneck/tests/data/test_675_B index c0722ef..c0722ef 100644 --- a/geom_bottleneck/tests/data/test_675_B +++ b/bottleneck/tests/data/test_675_B diff --git a/geom_bottleneck/tests/data/test_676_A b/bottleneck/tests/data/test_676_A index b43ef5e..b43ef5e 100644 --- a/geom_bottleneck/tests/data/test_676_A +++ b/bottleneck/tests/data/test_676_A diff --git a/geom_bottleneck/tests/data/test_676_B b/bottleneck/tests/data/test_676_B index 59b2fb6..59b2fb6 100644 --- a/geom_bottleneck/tests/data/test_676_B +++ b/bottleneck/tests/data/test_676_B diff --git a/geom_bottleneck/tests/data/test_677_A b/bottleneck/tests/data/test_677_A index 4d9d36e..4d9d36e 100644 --- a/geom_bottleneck/tests/data/test_677_A +++ b/bottleneck/tests/data/test_677_A diff --git a/geom_bottleneck/tests/data/test_677_B b/bottleneck/tests/data/test_677_B index 4edf573..4edf573 100644 --- a/geom_bottleneck/tests/data/test_677_B +++ b/bottleneck/tests/data/test_677_B diff --git a/geom_bottleneck/tests/data/test_678_A b/bottleneck/tests/data/test_678_A index 54ab668..54ab668 100644 --- a/geom_bottleneck/tests/data/test_678_A +++ b/bottleneck/tests/data/test_678_A diff --git a/geom_bottleneck/tests/data/test_678_B b/bottleneck/tests/data/test_678_B index f695f5f..f695f5f 100644 --- a/geom_bottleneck/tests/data/test_678_B +++ b/bottleneck/tests/data/test_678_B diff --git a/geom_bottleneck/tests/data/test_679_A b/bottleneck/tests/data/test_679_A index 33e4ce8..33e4ce8 100644 --- a/geom_bottleneck/tests/data/test_679_A +++ b/bottleneck/tests/data/test_679_A diff --git a/geom_bottleneck/tests/data/test_679_B b/bottleneck/tests/data/test_679_B index a99ec77..a99ec77 100644 --- a/geom_bottleneck/tests/data/test_679_B +++ b/bottleneck/tests/data/test_679_B diff --git a/geom_bottleneck/tests/data/test_680_A b/bottleneck/tests/data/test_680_A index 4bb43a8..4bb43a8 100644 --- a/geom_bottleneck/tests/data/test_680_A +++ b/bottleneck/tests/data/test_680_A diff --git a/geom_bottleneck/tests/data/test_680_B b/bottleneck/tests/data/test_680_B index efb704f..efb704f 100644 --- a/geom_bottleneck/tests/data/test_680_B +++ b/bottleneck/tests/data/test_680_B diff --git a/geom_bottleneck/tests/data/test_681_A b/bottleneck/tests/data/test_681_A index 5eb7d6a..5eb7d6a 100644 --- a/geom_bottleneck/tests/data/test_681_A +++ b/bottleneck/tests/data/test_681_A diff --git a/geom_bottleneck/tests/data/test_681_B b/bottleneck/tests/data/test_681_B index 092ddc5..092ddc5 100644 --- a/geom_bottleneck/tests/data/test_681_B +++ b/bottleneck/tests/data/test_681_B diff --git a/geom_bottleneck/tests/data/test_682_A b/bottleneck/tests/data/test_682_A index 7898cba..7898cba 100644 --- a/geom_bottleneck/tests/data/test_682_A +++ b/bottleneck/tests/data/test_682_A diff --git a/geom_bottleneck/tests/data/test_682_B b/bottleneck/tests/data/test_682_B index f5b1d81..f5b1d81 100644 --- a/geom_bottleneck/tests/data/test_682_B +++ b/bottleneck/tests/data/test_682_B diff --git a/geom_bottleneck/tests/data/test_683_A b/bottleneck/tests/data/test_683_A index 3661bfc..3661bfc 100644 --- a/geom_bottleneck/tests/data/test_683_A +++ b/bottleneck/tests/data/test_683_A diff --git a/geom_bottleneck/tests/data/test_683_B b/bottleneck/tests/data/test_683_B index 62c998b..62c998b 100644 --- a/geom_bottleneck/tests/data/test_683_B +++ b/bottleneck/tests/data/test_683_B diff --git a/geom_bottleneck/tests/data/test_684_A b/bottleneck/tests/data/test_684_A index b22afe3..b22afe3 100644 --- a/geom_bottleneck/tests/data/test_684_A +++ b/bottleneck/tests/data/test_684_A diff --git a/geom_bottleneck/tests/data/test_684_B b/bottleneck/tests/data/test_684_B index cbede63..cbede63 100644 --- a/geom_bottleneck/tests/data/test_684_B +++ b/bottleneck/tests/data/test_684_B diff --git a/geom_bottleneck/tests/data/test_685_A b/bottleneck/tests/data/test_685_A index c4bd0e9..c4bd0e9 100644 --- a/geom_bottleneck/tests/data/test_685_A +++ b/bottleneck/tests/data/test_685_A diff --git a/geom_bottleneck/tests/data/test_685_B b/bottleneck/tests/data/test_685_B index 984dd98..984dd98 100644 --- a/geom_bottleneck/tests/data/test_685_B +++ b/bottleneck/tests/data/test_685_B diff --git a/geom_bottleneck/tests/data/test_686_A b/bottleneck/tests/data/test_686_A index e498d5c..e498d5c 100644 --- a/geom_bottleneck/tests/data/test_686_A +++ b/bottleneck/tests/data/test_686_A diff --git a/geom_bottleneck/tests/data/test_686_B b/bottleneck/tests/data/test_686_B index 56ada59..56ada59 100644 --- a/geom_bottleneck/tests/data/test_686_B +++ b/bottleneck/tests/data/test_686_B diff --git a/geom_bottleneck/tests/data/test_687_A b/bottleneck/tests/data/test_687_A index c31c2d2..c31c2d2 100644 --- a/geom_bottleneck/tests/data/test_687_A +++ b/bottleneck/tests/data/test_687_A diff --git a/geom_bottleneck/tests/data/test_687_B b/bottleneck/tests/data/test_687_B index 471eeed..471eeed 100644 --- a/geom_bottleneck/tests/data/test_687_B +++ b/bottleneck/tests/data/test_687_B diff --git a/geom_bottleneck/tests/data/test_688_A b/bottleneck/tests/data/test_688_A index 7396099..7396099 100644 --- a/geom_bottleneck/tests/data/test_688_A +++ b/bottleneck/tests/data/test_688_A diff --git a/geom_bottleneck/tests/data/test_688_B b/bottleneck/tests/data/test_688_B index e133e74..e133e74 100644 --- a/geom_bottleneck/tests/data/test_688_B +++ b/bottleneck/tests/data/test_688_B diff --git a/geom_bottleneck/tests/data/test_689_A b/bottleneck/tests/data/test_689_A index 72febe7..72febe7 100644 --- a/geom_bottleneck/tests/data/test_689_A +++ b/bottleneck/tests/data/test_689_A diff --git a/geom_bottleneck/tests/data/test_689_B b/bottleneck/tests/data/test_689_B index f684387..f684387 100644 --- a/geom_bottleneck/tests/data/test_689_B +++ b/bottleneck/tests/data/test_689_B diff --git a/geom_bottleneck/tests/data/test_690_A b/bottleneck/tests/data/test_690_A index 4106f49..4106f49 100644 --- a/geom_bottleneck/tests/data/test_690_A +++ b/bottleneck/tests/data/test_690_A diff --git a/geom_bottleneck/tests/data/test_690_B b/bottleneck/tests/data/test_690_B index d452cff..d452cff 100644 --- a/geom_bottleneck/tests/data/test_690_B +++ b/bottleneck/tests/data/test_690_B diff --git a/geom_bottleneck/tests/data/test_691_A b/bottleneck/tests/data/test_691_A index b6c906e..b6c906e 100644 --- a/geom_bottleneck/tests/data/test_691_A +++ b/bottleneck/tests/data/test_691_A diff --git a/geom_bottleneck/tests/data/test_691_B b/bottleneck/tests/data/test_691_B index 57e58ff..57e58ff 100644 --- a/geom_bottleneck/tests/data/test_691_B +++ b/bottleneck/tests/data/test_691_B diff --git a/geom_bottleneck/tests/data/test_692_A b/bottleneck/tests/data/test_692_A index 1686c25..1686c25 100644 --- a/geom_bottleneck/tests/data/test_692_A +++ b/bottleneck/tests/data/test_692_A diff --git a/geom_bottleneck/tests/data/test_692_B b/bottleneck/tests/data/test_692_B index bf6174a..bf6174a 100644 --- a/geom_bottleneck/tests/data/test_692_B +++ b/bottleneck/tests/data/test_692_B diff --git a/geom_bottleneck/tests/data/test_693_A b/bottleneck/tests/data/test_693_A index ea16ba6..ea16ba6 100644 --- a/geom_bottleneck/tests/data/test_693_A +++ b/bottleneck/tests/data/test_693_A diff --git a/geom_bottleneck/tests/data/test_693_B b/bottleneck/tests/data/test_693_B index 52c8f97..52c8f97 100644 --- a/geom_bottleneck/tests/data/test_693_B +++ b/bottleneck/tests/data/test_693_B diff --git a/geom_bottleneck/tests/data/test_694_A b/bottleneck/tests/data/test_694_A index e577a0f..e577a0f 100644 --- a/geom_bottleneck/tests/data/test_694_A +++ b/bottleneck/tests/data/test_694_A diff --git a/geom_bottleneck/tests/data/test_694_B b/bottleneck/tests/data/test_694_B index e406840..e406840 100644 --- a/geom_bottleneck/tests/data/test_694_B +++ b/bottleneck/tests/data/test_694_B diff --git a/geom_bottleneck/tests/data/test_695_A b/bottleneck/tests/data/test_695_A index ef9cacb..ef9cacb 100644 --- a/geom_bottleneck/tests/data/test_695_A +++ b/bottleneck/tests/data/test_695_A diff --git a/geom_bottleneck/tests/data/test_695_B b/bottleneck/tests/data/test_695_B index f2bb91b..f2bb91b 100644 --- a/geom_bottleneck/tests/data/test_695_B +++ b/bottleneck/tests/data/test_695_B diff --git a/geom_bottleneck/tests/data/test_696_A b/bottleneck/tests/data/test_696_A index 71fa19f..71fa19f 100644 --- a/geom_bottleneck/tests/data/test_696_A +++ b/bottleneck/tests/data/test_696_A diff --git a/geom_bottleneck/tests/data/test_696_B b/bottleneck/tests/data/test_696_B index a964c63..a964c63 100644 --- a/geom_bottleneck/tests/data/test_696_B +++ b/bottleneck/tests/data/test_696_B diff --git a/geom_bottleneck/tests/data/test_697_A b/bottleneck/tests/data/test_697_A index 848e417..848e417 100644 --- a/geom_bottleneck/tests/data/test_697_A +++ b/bottleneck/tests/data/test_697_A diff --git a/geom_bottleneck/tests/data/test_697_B b/bottleneck/tests/data/test_697_B index 98a8d15..98a8d15 100644 --- a/geom_bottleneck/tests/data/test_697_B +++ b/bottleneck/tests/data/test_697_B diff --git a/geom_bottleneck/tests/data/test_698_A b/bottleneck/tests/data/test_698_A index a90620d..a90620d 100644 --- a/geom_bottleneck/tests/data/test_698_A +++ b/bottleneck/tests/data/test_698_A diff --git a/geom_bottleneck/tests/data/test_698_B b/bottleneck/tests/data/test_698_B index ef52ae0..ef52ae0 100644 --- a/geom_bottleneck/tests/data/test_698_B +++ b/bottleneck/tests/data/test_698_B diff --git a/geom_bottleneck/tests/data/test_699_A b/bottleneck/tests/data/test_699_A index e00215d..e00215d 100644 --- a/geom_bottleneck/tests/data/test_699_A +++ b/bottleneck/tests/data/test_699_A diff --git a/geom_bottleneck/tests/data/test_699_B b/bottleneck/tests/data/test_699_B index 0fff210..0fff210 100644 --- a/geom_bottleneck/tests/data/test_699_B +++ b/bottleneck/tests/data/test_699_B diff --git a/geom_bottleneck/tests/data/test_700_A b/bottleneck/tests/data/test_700_A index 9425b73..9425b73 100644 --- a/geom_bottleneck/tests/data/test_700_A +++ b/bottleneck/tests/data/test_700_A diff --git a/geom_bottleneck/tests/data/test_700_B b/bottleneck/tests/data/test_700_B index 19944b2..19944b2 100644 --- a/geom_bottleneck/tests/data/test_700_B +++ b/bottleneck/tests/data/test_700_B diff --git a/geom_bottleneck/tests/data/test_701_A b/bottleneck/tests/data/test_701_A index 062d6fb..062d6fb 100644 --- a/geom_bottleneck/tests/data/test_701_A +++ b/bottleneck/tests/data/test_701_A diff --git a/geom_bottleneck/tests/data/test_701_B b/bottleneck/tests/data/test_701_B index 3149c7c..3149c7c 100644 --- a/geom_bottleneck/tests/data/test_701_B +++ b/bottleneck/tests/data/test_701_B diff --git a/geom_bottleneck/tests/data/test_702_A b/bottleneck/tests/data/test_702_A index 2a82935..2a82935 100644 --- a/geom_bottleneck/tests/data/test_702_A +++ b/bottleneck/tests/data/test_702_A diff --git a/geom_bottleneck/tests/data/test_702_B b/bottleneck/tests/data/test_702_B index c3854d5..c3854d5 100644 --- a/geom_bottleneck/tests/data/test_702_B +++ b/bottleneck/tests/data/test_702_B diff --git a/geom_bottleneck/tests/data/test_703_A b/bottleneck/tests/data/test_703_A index fb434c0..fb434c0 100644 --- a/geom_bottleneck/tests/data/test_703_A +++ b/bottleneck/tests/data/test_703_A diff --git a/geom_bottleneck/tests/data/test_703_B b/bottleneck/tests/data/test_703_B index f8af9dd..f8af9dd 100644 --- a/geom_bottleneck/tests/data/test_703_B +++ b/bottleneck/tests/data/test_703_B diff --git a/geom_bottleneck/tests/data/test_704_A b/bottleneck/tests/data/test_704_A index a89a1aa..a89a1aa 100644 --- a/geom_bottleneck/tests/data/test_704_A +++ b/bottleneck/tests/data/test_704_A diff --git a/geom_bottleneck/tests/data/test_704_B b/bottleneck/tests/data/test_704_B index 5abc5fa..5abc5fa 100644 --- a/geom_bottleneck/tests/data/test_704_B +++ b/bottleneck/tests/data/test_704_B diff --git a/geom_bottleneck/tests/data/test_705_A b/bottleneck/tests/data/test_705_A index 924a661..924a661 100644 --- a/geom_bottleneck/tests/data/test_705_A +++ b/bottleneck/tests/data/test_705_A diff --git a/geom_bottleneck/tests/data/test_705_B b/bottleneck/tests/data/test_705_B index 0681a80..0681a80 100644 --- a/geom_bottleneck/tests/data/test_705_B +++ b/bottleneck/tests/data/test_705_B diff --git a/geom_bottleneck/tests/data/test_706_A b/bottleneck/tests/data/test_706_A index 0a249be..0a249be 100644 --- a/geom_bottleneck/tests/data/test_706_A +++ b/bottleneck/tests/data/test_706_A diff --git a/geom_bottleneck/tests/data/test_706_B b/bottleneck/tests/data/test_706_B index 624923c..624923c 100644 --- a/geom_bottleneck/tests/data/test_706_B +++ b/bottleneck/tests/data/test_706_B diff --git a/geom_bottleneck/tests/data/test_707_A b/bottleneck/tests/data/test_707_A index a251b74..a251b74 100644 --- a/geom_bottleneck/tests/data/test_707_A +++ b/bottleneck/tests/data/test_707_A diff --git a/geom_bottleneck/tests/data/test_707_B b/bottleneck/tests/data/test_707_B index 2647b31..2647b31 100644 --- a/geom_bottleneck/tests/data/test_707_B +++ b/bottleneck/tests/data/test_707_B diff --git a/geom_bottleneck/tests/data/test_708_A b/bottleneck/tests/data/test_708_A index ddc601a..ddc601a 100644 --- a/geom_bottleneck/tests/data/test_708_A +++ b/bottleneck/tests/data/test_708_A diff --git a/geom_bottleneck/tests/data/test_708_B b/bottleneck/tests/data/test_708_B index 0a64a4f..0a64a4f 100644 --- a/geom_bottleneck/tests/data/test_708_B +++ b/bottleneck/tests/data/test_708_B diff --git a/geom_bottleneck/tests/data/test_709_A b/bottleneck/tests/data/test_709_A index 2d3aa30..2d3aa30 100644 --- a/geom_bottleneck/tests/data/test_709_A +++ b/bottleneck/tests/data/test_709_A diff --git a/geom_bottleneck/tests/data/test_709_B b/bottleneck/tests/data/test_709_B index c5f7233..c5f7233 100644 --- a/geom_bottleneck/tests/data/test_709_B +++ b/bottleneck/tests/data/test_709_B diff --git a/geom_bottleneck/tests/data/test_710_A b/bottleneck/tests/data/test_710_A index e611f5a..e611f5a 100644 --- a/geom_bottleneck/tests/data/test_710_A +++ b/bottleneck/tests/data/test_710_A diff --git a/geom_bottleneck/tests/data/test_710_B b/bottleneck/tests/data/test_710_B index cd9cedb..cd9cedb 100644 --- a/geom_bottleneck/tests/data/test_710_B +++ b/bottleneck/tests/data/test_710_B diff --git a/geom_bottleneck/tests/data/test_711_A b/bottleneck/tests/data/test_711_A index 900b87a..900b87a 100644 --- a/geom_bottleneck/tests/data/test_711_A +++ b/bottleneck/tests/data/test_711_A diff --git a/geom_bottleneck/tests/data/test_711_B b/bottleneck/tests/data/test_711_B index 31dd505..31dd505 100644 --- a/geom_bottleneck/tests/data/test_711_B +++ b/bottleneck/tests/data/test_711_B diff --git a/geom_bottleneck/tests/data/test_712_A b/bottleneck/tests/data/test_712_A index 15bc0a2..15bc0a2 100644 --- a/geom_bottleneck/tests/data/test_712_A +++ b/bottleneck/tests/data/test_712_A diff --git a/geom_bottleneck/tests/data/test_712_B b/bottleneck/tests/data/test_712_B index 3071ea5..3071ea5 100644 --- a/geom_bottleneck/tests/data/test_712_B +++ b/bottleneck/tests/data/test_712_B diff --git a/geom_bottleneck/tests/data/test_713_A b/bottleneck/tests/data/test_713_A index 89ee240..89ee240 100644 --- a/geom_bottleneck/tests/data/test_713_A +++ b/bottleneck/tests/data/test_713_A diff --git a/geom_bottleneck/tests/data/test_713_B b/bottleneck/tests/data/test_713_B index f2b501c..f2b501c 100644 --- a/geom_bottleneck/tests/data/test_713_B +++ b/bottleneck/tests/data/test_713_B diff --git a/geom_bottleneck/tests/data/test_714_A b/bottleneck/tests/data/test_714_A index 73ba892..73ba892 100644 --- a/geom_bottleneck/tests/data/test_714_A +++ b/bottleneck/tests/data/test_714_A diff --git a/geom_bottleneck/tests/data/test_714_B b/bottleneck/tests/data/test_714_B index c495e7a..c495e7a 100644 --- a/geom_bottleneck/tests/data/test_714_B +++ b/bottleneck/tests/data/test_714_B diff --git a/geom_bottleneck/tests/data/test_715_A b/bottleneck/tests/data/test_715_A index 70b698d..70b698d 100644 --- a/geom_bottleneck/tests/data/test_715_A +++ b/bottleneck/tests/data/test_715_A diff --git a/geom_bottleneck/tests/data/test_715_B b/bottleneck/tests/data/test_715_B index 3cdf2b3..3cdf2b3 100644 --- a/geom_bottleneck/tests/data/test_715_B +++ b/bottleneck/tests/data/test_715_B diff --git a/geom_bottleneck/tests/data/test_716_A b/bottleneck/tests/data/test_716_A index ada9ac0..ada9ac0 100644 --- a/geom_bottleneck/tests/data/test_716_A +++ b/bottleneck/tests/data/test_716_A diff --git a/geom_bottleneck/tests/data/test_716_B b/bottleneck/tests/data/test_716_B index b13c8a1..b13c8a1 100644 --- a/geom_bottleneck/tests/data/test_716_B +++ b/bottleneck/tests/data/test_716_B diff --git a/geom_bottleneck/tests/data/test_717_A b/bottleneck/tests/data/test_717_A index f23e351..f23e351 100644 --- a/geom_bottleneck/tests/data/test_717_A +++ b/bottleneck/tests/data/test_717_A diff --git a/geom_bottleneck/tests/data/test_717_B b/bottleneck/tests/data/test_717_B index 150f7ff..150f7ff 100644 --- a/geom_bottleneck/tests/data/test_717_B +++ b/bottleneck/tests/data/test_717_B diff --git a/geom_bottleneck/tests/data/test_718_A b/bottleneck/tests/data/test_718_A index 6efc756..6efc756 100644 --- a/geom_bottleneck/tests/data/test_718_A +++ b/bottleneck/tests/data/test_718_A diff --git a/geom_bottleneck/tests/data/test_718_B b/bottleneck/tests/data/test_718_B index 4e45db1..4e45db1 100644 --- a/geom_bottleneck/tests/data/test_718_B +++ b/bottleneck/tests/data/test_718_B diff --git a/geom_bottleneck/tests/data/test_719_A b/bottleneck/tests/data/test_719_A index 3512e1f..3512e1f 100644 --- a/geom_bottleneck/tests/data/test_719_A +++ b/bottleneck/tests/data/test_719_A diff --git a/geom_bottleneck/tests/data/test_719_B b/bottleneck/tests/data/test_719_B index 028f44a..028f44a 100644 --- a/geom_bottleneck/tests/data/test_719_B +++ b/bottleneck/tests/data/test_719_B diff --git a/geom_bottleneck/tests/data/test_720_A b/bottleneck/tests/data/test_720_A index 57e2829..57e2829 100644 --- a/geom_bottleneck/tests/data/test_720_A +++ b/bottleneck/tests/data/test_720_A diff --git a/geom_bottleneck/tests/data/test_720_B b/bottleneck/tests/data/test_720_B index f3f2675..f3f2675 100644 --- a/geom_bottleneck/tests/data/test_720_B +++ b/bottleneck/tests/data/test_720_B diff --git a/geom_bottleneck/tests/data/test_721_A b/bottleneck/tests/data/test_721_A index f8a7f29..f8a7f29 100644 --- a/geom_bottleneck/tests/data/test_721_A +++ b/bottleneck/tests/data/test_721_A diff --git a/geom_bottleneck/tests/data/test_721_B b/bottleneck/tests/data/test_721_B index 35b828c..35b828c 100644 --- a/geom_bottleneck/tests/data/test_721_B +++ b/bottleneck/tests/data/test_721_B diff --git a/geom_bottleneck/tests/data/test_722_A b/bottleneck/tests/data/test_722_A index 6e0719f..6e0719f 100644 --- a/geom_bottleneck/tests/data/test_722_A +++ b/bottleneck/tests/data/test_722_A diff --git a/geom_bottleneck/tests/data/test_722_B b/bottleneck/tests/data/test_722_B index 0fd37cc..0fd37cc 100644 --- a/geom_bottleneck/tests/data/test_722_B +++ b/bottleneck/tests/data/test_722_B diff --git a/geom_bottleneck/tests/data/test_723_A b/bottleneck/tests/data/test_723_A index ad94fdd..ad94fdd 100644 --- a/geom_bottleneck/tests/data/test_723_A +++ b/bottleneck/tests/data/test_723_A diff --git a/geom_bottleneck/tests/data/test_723_B b/bottleneck/tests/data/test_723_B index 247a17e..247a17e 100644 --- a/geom_bottleneck/tests/data/test_723_B +++ b/bottleneck/tests/data/test_723_B diff --git a/geom_bottleneck/tests/data/test_724_A b/bottleneck/tests/data/test_724_A index f9a6bcf..f9a6bcf 100644 --- a/geom_bottleneck/tests/data/test_724_A +++ b/bottleneck/tests/data/test_724_A diff --git a/geom_bottleneck/tests/data/test_724_B b/bottleneck/tests/data/test_724_B index 71d03b3..71d03b3 100644 --- a/geom_bottleneck/tests/data/test_724_B +++ b/bottleneck/tests/data/test_724_B diff --git a/geom_bottleneck/tests/data/test_725_A b/bottleneck/tests/data/test_725_A index 1e20d9e..1e20d9e 100644 --- a/geom_bottleneck/tests/data/test_725_A +++ b/bottleneck/tests/data/test_725_A diff --git a/geom_bottleneck/tests/data/test_725_B b/bottleneck/tests/data/test_725_B index a215c1e..a215c1e 100644 --- a/geom_bottleneck/tests/data/test_725_B +++ b/bottleneck/tests/data/test_725_B diff --git a/geom_bottleneck/tests/data/test_726_A b/bottleneck/tests/data/test_726_A index dd9500a..dd9500a 100644 --- a/geom_bottleneck/tests/data/test_726_A +++ b/bottleneck/tests/data/test_726_A diff --git a/geom_bottleneck/tests/data/test_726_B b/bottleneck/tests/data/test_726_B index b3d3e50..b3d3e50 100644 --- a/geom_bottleneck/tests/data/test_726_B +++ b/bottleneck/tests/data/test_726_B diff --git a/geom_bottleneck/tests/data/test_727_A b/bottleneck/tests/data/test_727_A index dae9ff3..dae9ff3 100644 --- a/geom_bottleneck/tests/data/test_727_A +++ b/bottleneck/tests/data/test_727_A diff --git a/geom_bottleneck/tests/data/test_727_B b/bottleneck/tests/data/test_727_B index 551d523..551d523 100644 --- a/geom_bottleneck/tests/data/test_727_B +++ b/bottleneck/tests/data/test_727_B diff --git a/geom_bottleneck/tests/data/test_728_A b/bottleneck/tests/data/test_728_A index 8074ce8..8074ce8 100644 --- a/geom_bottleneck/tests/data/test_728_A +++ b/bottleneck/tests/data/test_728_A diff --git a/geom_bottleneck/tests/data/test_728_B b/bottleneck/tests/data/test_728_B index 6d1448a..6d1448a 100644 --- a/geom_bottleneck/tests/data/test_728_B +++ b/bottleneck/tests/data/test_728_B diff --git a/geom_bottleneck/tests/data/test_729_A b/bottleneck/tests/data/test_729_A index f9de136..f9de136 100644 --- a/geom_bottleneck/tests/data/test_729_A +++ b/bottleneck/tests/data/test_729_A diff --git a/geom_bottleneck/tests/data/test_729_B b/bottleneck/tests/data/test_729_B index d34621f..d34621f 100644 --- a/geom_bottleneck/tests/data/test_729_B +++ b/bottleneck/tests/data/test_729_B diff --git a/geom_bottleneck/tests/data/test_730_A b/bottleneck/tests/data/test_730_A index 433cbd8..433cbd8 100644 --- a/geom_bottleneck/tests/data/test_730_A +++ b/bottleneck/tests/data/test_730_A diff --git a/geom_bottleneck/tests/data/test_730_B b/bottleneck/tests/data/test_730_B index 1b46964..1b46964 100644 --- a/geom_bottleneck/tests/data/test_730_B +++ b/bottleneck/tests/data/test_730_B diff --git a/geom_bottleneck/tests/data/test_731_A b/bottleneck/tests/data/test_731_A index 38d42cd..38d42cd 100644 --- a/geom_bottleneck/tests/data/test_731_A +++ b/bottleneck/tests/data/test_731_A diff --git a/geom_bottleneck/tests/data/test_731_B b/bottleneck/tests/data/test_731_B index 3017d7a..3017d7a 100644 --- a/geom_bottleneck/tests/data/test_731_B +++ b/bottleneck/tests/data/test_731_B diff --git a/geom_bottleneck/tests/data/test_732_A b/bottleneck/tests/data/test_732_A index 75a48cf..75a48cf 100644 --- a/geom_bottleneck/tests/data/test_732_A +++ b/bottleneck/tests/data/test_732_A diff --git a/geom_bottleneck/tests/data/test_732_B b/bottleneck/tests/data/test_732_B index fada3b9..fada3b9 100644 --- a/geom_bottleneck/tests/data/test_732_B +++ b/bottleneck/tests/data/test_732_B diff --git a/geom_bottleneck/tests/data/test_733_A b/bottleneck/tests/data/test_733_A index d97ae0b..d97ae0b 100644 --- a/geom_bottleneck/tests/data/test_733_A +++ b/bottleneck/tests/data/test_733_A diff --git a/geom_bottleneck/tests/data/test_733_B b/bottleneck/tests/data/test_733_B index 529c7de..529c7de 100644 --- a/geom_bottleneck/tests/data/test_733_B +++ b/bottleneck/tests/data/test_733_B diff --git a/geom_bottleneck/tests/data/test_734_A b/bottleneck/tests/data/test_734_A index 9aec4b4..9aec4b4 100644 --- a/geom_bottleneck/tests/data/test_734_A +++ b/bottleneck/tests/data/test_734_A diff --git a/geom_bottleneck/tests/data/test_734_B b/bottleneck/tests/data/test_734_B index 4cb7206..4cb7206 100644 --- a/geom_bottleneck/tests/data/test_734_B +++ b/bottleneck/tests/data/test_734_B diff --git a/geom_bottleneck/tests/data/test_735_A b/bottleneck/tests/data/test_735_A index f364a21..f364a21 100644 --- a/geom_bottleneck/tests/data/test_735_A +++ b/bottleneck/tests/data/test_735_A diff --git a/geom_bottleneck/tests/data/test_735_B b/bottleneck/tests/data/test_735_B index 0f93850..0f93850 100644 --- a/geom_bottleneck/tests/data/test_735_B +++ b/bottleneck/tests/data/test_735_B diff --git a/geom_bottleneck/tests/data/test_736_A b/bottleneck/tests/data/test_736_A index d89c563..d89c563 100644 --- a/geom_bottleneck/tests/data/test_736_A +++ b/bottleneck/tests/data/test_736_A diff --git a/geom_bottleneck/tests/data/test_736_B b/bottleneck/tests/data/test_736_B index 25427f3..25427f3 100644 --- a/geom_bottleneck/tests/data/test_736_B +++ b/bottleneck/tests/data/test_736_B diff --git a/geom_bottleneck/tests/data/test_737_A b/bottleneck/tests/data/test_737_A index 2fbdf41..2fbdf41 100644 --- a/geom_bottleneck/tests/data/test_737_A +++ b/bottleneck/tests/data/test_737_A diff --git a/geom_bottleneck/tests/data/test_737_B b/bottleneck/tests/data/test_737_B index 42348d5..42348d5 100644 --- a/geom_bottleneck/tests/data/test_737_B +++ b/bottleneck/tests/data/test_737_B diff --git a/geom_bottleneck/tests/data/test_738_A b/bottleneck/tests/data/test_738_A index d56b09b..d56b09b 100644 --- a/geom_bottleneck/tests/data/test_738_A +++ b/bottleneck/tests/data/test_738_A diff --git a/geom_bottleneck/tests/data/test_738_B b/bottleneck/tests/data/test_738_B index 834b2cf..834b2cf 100644 --- a/geom_bottleneck/tests/data/test_738_B +++ b/bottleneck/tests/data/test_738_B diff --git a/geom_bottleneck/tests/data/test_739_A b/bottleneck/tests/data/test_739_A index 84cbd7c..84cbd7c 100644 --- a/geom_bottleneck/tests/data/test_739_A +++ b/bottleneck/tests/data/test_739_A diff --git a/geom_bottleneck/tests/data/test_739_B b/bottleneck/tests/data/test_739_B index 85afe3e..85afe3e 100644 --- a/geom_bottleneck/tests/data/test_739_B +++ b/bottleneck/tests/data/test_739_B diff --git a/geom_bottleneck/tests/data/test_740_A b/bottleneck/tests/data/test_740_A index a99113a..a99113a 100644 --- a/geom_bottleneck/tests/data/test_740_A +++ b/bottleneck/tests/data/test_740_A diff --git a/geom_bottleneck/tests/data/test_740_B b/bottleneck/tests/data/test_740_B index 5aac504..5aac504 100644 --- a/geom_bottleneck/tests/data/test_740_B +++ b/bottleneck/tests/data/test_740_B diff --git a/geom_bottleneck/tests/data/test_741_A b/bottleneck/tests/data/test_741_A index 7c3f3fc..7c3f3fc 100644 --- a/geom_bottleneck/tests/data/test_741_A +++ b/bottleneck/tests/data/test_741_A diff --git a/geom_bottleneck/tests/data/test_741_B b/bottleneck/tests/data/test_741_B index 9f8d386..9f8d386 100644 --- a/geom_bottleneck/tests/data/test_741_B +++ b/bottleneck/tests/data/test_741_B diff --git a/geom_bottleneck/tests/data/test_742_A b/bottleneck/tests/data/test_742_A index 9effd4c..9effd4c 100644 --- a/geom_bottleneck/tests/data/test_742_A +++ b/bottleneck/tests/data/test_742_A diff --git a/geom_bottleneck/tests/data/test_742_B b/bottleneck/tests/data/test_742_B index f17965b..f17965b 100644 --- a/geom_bottleneck/tests/data/test_742_B +++ b/bottleneck/tests/data/test_742_B diff --git a/geom_bottleneck/tests/data/test_743_A b/bottleneck/tests/data/test_743_A index 3a40cfb..3a40cfb 100644 --- a/geom_bottleneck/tests/data/test_743_A +++ b/bottleneck/tests/data/test_743_A diff --git a/geom_bottleneck/tests/data/test_743_B b/bottleneck/tests/data/test_743_B index 482d6dd..482d6dd 100644 --- a/geom_bottleneck/tests/data/test_743_B +++ b/bottleneck/tests/data/test_743_B diff --git a/geom_bottleneck/tests/data/test_744_A b/bottleneck/tests/data/test_744_A index 25c3e55..25c3e55 100644 --- a/geom_bottleneck/tests/data/test_744_A +++ b/bottleneck/tests/data/test_744_A diff --git a/geom_bottleneck/tests/data/test_744_B b/bottleneck/tests/data/test_744_B index da30f30..da30f30 100644 --- a/geom_bottleneck/tests/data/test_744_B +++ b/bottleneck/tests/data/test_744_B diff --git a/geom_bottleneck/tests/data/test_745_A b/bottleneck/tests/data/test_745_A index f8ef7e6..f8ef7e6 100644 --- a/geom_bottleneck/tests/data/test_745_A +++ b/bottleneck/tests/data/test_745_A diff --git a/geom_bottleneck/tests/data/test_745_B b/bottleneck/tests/data/test_745_B index f6d32b5..f6d32b5 100644 --- a/geom_bottleneck/tests/data/test_745_B +++ b/bottleneck/tests/data/test_745_B diff --git a/geom_bottleneck/tests/data/test_746_A b/bottleneck/tests/data/test_746_A index dbd677e..dbd677e 100644 --- a/geom_bottleneck/tests/data/test_746_A +++ b/bottleneck/tests/data/test_746_A diff --git a/geom_bottleneck/tests/data/test_746_B b/bottleneck/tests/data/test_746_B index 9d02f4b..9d02f4b 100644 --- a/geom_bottleneck/tests/data/test_746_B +++ b/bottleneck/tests/data/test_746_B diff --git a/geom_bottleneck/tests/data/test_747_A b/bottleneck/tests/data/test_747_A index c7886f8..c7886f8 100644 --- a/geom_bottleneck/tests/data/test_747_A +++ b/bottleneck/tests/data/test_747_A diff --git a/geom_bottleneck/tests/data/test_747_B b/bottleneck/tests/data/test_747_B index 1ca1b5e..1ca1b5e 100644 --- a/geom_bottleneck/tests/data/test_747_B +++ b/bottleneck/tests/data/test_747_B diff --git a/geom_bottleneck/tests/data/test_748_A b/bottleneck/tests/data/test_748_A index 5fe22c2..5fe22c2 100644 --- a/geom_bottleneck/tests/data/test_748_A +++ b/bottleneck/tests/data/test_748_A diff --git a/geom_bottleneck/tests/data/test_748_B b/bottleneck/tests/data/test_748_B index 2e69002..2e69002 100644 --- a/geom_bottleneck/tests/data/test_748_B +++ b/bottleneck/tests/data/test_748_B diff --git a/geom_bottleneck/tests/data/test_749_A b/bottleneck/tests/data/test_749_A index b3bf068..b3bf068 100644 --- a/geom_bottleneck/tests/data/test_749_A +++ b/bottleneck/tests/data/test_749_A diff --git a/geom_bottleneck/tests/data/test_749_B b/bottleneck/tests/data/test_749_B index b181d57..b181d57 100644 --- a/geom_bottleneck/tests/data/test_749_B +++ b/bottleneck/tests/data/test_749_B diff --git a/geom_bottleneck/tests/data/test_750_A b/bottleneck/tests/data/test_750_A index 3bd3e77..3bd3e77 100644 --- a/geom_bottleneck/tests/data/test_750_A +++ b/bottleneck/tests/data/test_750_A diff --git a/geom_bottleneck/tests/data/test_750_B b/bottleneck/tests/data/test_750_B index 837ed3d..837ed3d 100644 --- a/geom_bottleneck/tests/data/test_750_B +++ b/bottleneck/tests/data/test_750_B diff --git a/geom_bottleneck/tests/data/test_751_A b/bottleneck/tests/data/test_751_A index adb0fe7..adb0fe7 100644 --- a/geom_bottleneck/tests/data/test_751_A +++ b/bottleneck/tests/data/test_751_A diff --git a/geom_bottleneck/tests/data/test_751_B b/bottleneck/tests/data/test_751_B index 1ed1651..1ed1651 100644 --- a/geom_bottleneck/tests/data/test_751_B +++ b/bottleneck/tests/data/test_751_B diff --git a/geom_bottleneck/tests/data/test_752_A b/bottleneck/tests/data/test_752_A index 4b54da2..4b54da2 100644 --- a/geom_bottleneck/tests/data/test_752_A +++ b/bottleneck/tests/data/test_752_A diff --git a/geom_bottleneck/tests/data/test_752_B b/bottleneck/tests/data/test_752_B index 9c05ec9..9c05ec9 100644 --- a/geom_bottleneck/tests/data/test_752_B +++ b/bottleneck/tests/data/test_752_B diff --git a/geom_bottleneck/tests/data/test_753_A b/bottleneck/tests/data/test_753_A index 5704668..5704668 100644 --- a/geom_bottleneck/tests/data/test_753_A +++ b/bottleneck/tests/data/test_753_A diff --git a/geom_bottleneck/tests/data/test_753_B b/bottleneck/tests/data/test_753_B index 1e845f7..1e845f7 100644 --- a/geom_bottleneck/tests/data/test_753_B +++ b/bottleneck/tests/data/test_753_B diff --git a/geom_bottleneck/tests/data/test_754_A b/bottleneck/tests/data/test_754_A index 1957784..1957784 100644 --- a/geom_bottleneck/tests/data/test_754_A +++ b/bottleneck/tests/data/test_754_A diff --git a/geom_bottleneck/tests/data/test_754_B b/bottleneck/tests/data/test_754_B index 4463862..4463862 100644 --- a/geom_bottleneck/tests/data/test_754_B +++ b/bottleneck/tests/data/test_754_B diff --git a/geom_bottleneck/tests/data/test_755_A b/bottleneck/tests/data/test_755_A index d05546d..d05546d 100644 --- a/geom_bottleneck/tests/data/test_755_A +++ b/bottleneck/tests/data/test_755_A diff --git a/geom_bottleneck/tests/data/test_755_B b/bottleneck/tests/data/test_755_B index 47b372a..47b372a 100644 --- a/geom_bottleneck/tests/data/test_755_B +++ b/bottleneck/tests/data/test_755_B diff --git a/geom_bottleneck/tests/data/test_756_A b/bottleneck/tests/data/test_756_A index bac3296..bac3296 100644 --- a/geom_bottleneck/tests/data/test_756_A +++ b/bottleneck/tests/data/test_756_A diff --git a/geom_bottleneck/tests/data/test_756_B b/bottleneck/tests/data/test_756_B index 0579dd8..0579dd8 100644 --- a/geom_bottleneck/tests/data/test_756_B +++ b/bottleneck/tests/data/test_756_B diff --git a/geom_bottleneck/tests/data/test_757_A b/bottleneck/tests/data/test_757_A index 3d0e16e..3d0e16e 100644 --- a/geom_bottleneck/tests/data/test_757_A +++ b/bottleneck/tests/data/test_757_A diff --git a/geom_bottleneck/tests/data/test_757_B b/bottleneck/tests/data/test_757_B index 7ccedc5..7ccedc5 100644 --- a/geom_bottleneck/tests/data/test_757_B +++ b/bottleneck/tests/data/test_757_B diff --git a/geom_bottleneck/tests/data/test_758_A b/bottleneck/tests/data/test_758_A index fdabcdd..fdabcdd 100644 --- a/geom_bottleneck/tests/data/test_758_A +++ b/bottleneck/tests/data/test_758_A diff --git a/geom_bottleneck/tests/data/test_758_B b/bottleneck/tests/data/test_758_B index 4fb7f60..4fb7f60 100644 --- a/geom_bottleneck/tests/data/test_758_B +++ b/bottleneck/tests/data/test_758_B diff --git a/geom_bottleneck/tests/data/test_759_A b/bottleneck/tests/data/test_759_A index dcf3a28..dcf3a28 100644 --- a/geom_bottleneck/tests/data/test_759_A +++ b/bottleneck/tests/data/test_759_A diff --git a/geom_bottleneck/tests/data/test_759_B b/bottleneck/tests/data/test_759_B index e094e35..e094e35 100644 --- a/geom_bottleneck/tests/data/test_759_B +++ b/bottleneck/tests/data/test_759_B diff --git a/geom_bottleneck/tests/data/test_760_A b/bottleneck/tests/data/test_760_A index 38e77f3..38e77f3 100644 --- a/geom_bottleneck/tests/data/test_760_A +++ b/bottleneck/tests/data/test_760_A diff --git a/geom_bottleneck/tests/data/test_760_B b/bottleneck/tests/data/test_760_B index 1bb3547..1bb3547 100644 --- a/geom_bottleneck/tests/data/test_760_B +++ b/bottleneck/tests/data/test_760_B diff --git a/geom_bottleneck/tests/data/test_761_A b/bottleneck/tests/data/test_761_A index 4690752..4690752 100644 --- a/geom_bottleneck/tests/data/test_761_A +++ b/bottleneck/tests/data/test_761_A diff --git a/geom_bottleneck/tests/data/test_761_B b/bottleneck/tests/data/test_761_B index 9978d2c..9978d2c 100644 --- a/geom_bottleneck/tests/data/test_761_B +++ b/bottleneck/tests/data/test_761_B diff --git a/geom_bottleneck/tests/data/test_762_A b/bottleneck/tests/data/test_762_A index 7918ab6..7918ab6 100644 --- a/geom_bottleneck/tests/data/test_762_A +++ b/bottleneck/tests/data/test_762_A diff --git a/geom_bottleneck/tests/data/test_762_B b/bottleneck/tests/data/test_762_B index d36f033..d36f033 100644 --- a/geom_bottleneck/tests/data/test_762_B +++ b/bottleneck/tests/data/test_762_B diff --git a/geom_bottleneck/tests/data/test_763_A b/bottleneck/tests/data/test_763_A index 73d90de..73d90de 100644 --- a/geom_bottleneck/tests/data/test_763_A +++ b/bottleneck/tests/data/test_763_A diff --git a/geom_bottleneck/tests/data/test_763_B b/bottleneck/tests/data/test_763_B index 09d159c..09d159c 100644 --- a/geom_bottleneck/tests/data/test_763_B +++ b/bottleneck/tests/data/test_763_B diff --git a/geom_bottleneck/tests/data/test_764_A b/bottleneck/tests/data/test_764_A index 8dead93..8dead93 100644 --- a/geom_bottleneck/tests/data/test_764_A +++ b/bottleneck/tests/data/test_764_A diff --git a/geom_bottleneck/tests/data/test_764_B b/bottleneck/tests/data/test_764_B index 014198d..014198d 100644 --- a/geom_bottleneck/tests/data/test_764_B +++ b/bottleneck/tests/data/test_764_B diff --git a/geom_bottleneck/tests/data/test_765_A b/bottleneck/tests/data/test_765_A index 666d2fe..666d2fe 100644 --- a/geom_bottleneck/tests/data/test_765_A +++ b/bottleneck/tests/data/test_765_A diff --git a/geom_bottleneck/tests/data/test_765_B b/bottleneck/tests/data/test_765_B index c0be6d4..c0be6d4 100644 --- a/geom_bottleneck/tests/data/test_765_B +++ b/bottleneck/tests/data/test_765_B diff --git a/geom_bottleneck/tests/data/test_766_A b/bottleneck/tests/data/test_766_A index 48d55d9..48d55d9 100644 --- a/geom_bottleneck/tests/data/test_766_A +++ b/bottleneck/tests/data/test_766_A diff --git a/geom_bottleneck/tests/data/test_766_B b/bottleneck/tests/data/test_766_B index 9943c61..9943c61 100644 --- a/geom_bottleneck/tests/data/test_766_B +++ b/bottleneck/tests/data/test_766_B diff --git a/geom_bottleneck/tests/data/test_767_A b/bottleneck/tests/data/test_767_A index badb767..badb767 100644 --- a/geom_bottleneck/tests/data/test_767_A +++ b/bottleneck/tests/data/test_767_A diff --git a/geom_bottleneck/tests/data/test_767_B b/bottleneck/tests/data/test_767_B index 3eb4c39..3eb4c39 100644 --- a/geom_bottleneck/tests/data/test_767_B +++ b/bottleneck/tests/data/test_767_B diff --git a/geom_bottleneck/tests/data/test_768_A b/bottleneck/tests/data/test_768_A index 69b6425..69b6425 100644 --- a/geom_bottleneck/tests/data/test_768_A +++ b/bottleneck/tests/data/test_768_A diff --git a/geom_bottleneck/tests/data/test_768_B b/bottleneck/tests/data/test_768_B index a0e8eb0..a0e8eb0 100644 --- a/geom_bottleneck/tests/data/test_768_B +++ b/bottleneck/tests/data/test_768_B diff --git a/geom_bottleneck/tests/data/test_769_A b/bottleneck/tests/data/test_769_A index 08a46bd..08a46bd 100644 --- a/geom_bottleneck/tests/data/test_769_A +++ b/bottleneck/tests/data/test_769_A diff --git a/geom_bottleneck/tests/data/test_769_B b/bottleneck/tests/data/test_769_B index ce18190..ce18190 100644 --- a/geom_bottleneck/tests/data/test_769_B +++ b/bottleneck/tests/data/test_769_B diff --git a/geom_bottleneck/tests/data/test_770_A b/bottleneck/tests/data/test_770_A index edfdf26..edfdf26 100644 --- a/geom_bottleneck/tests/data/test_770_A +++ b/bottleneck/tests/data/test_770_A diff --git a/geom_bottleneck/tests/data/test_770_B b/bottleneck/tests/data/test_770_B index cd59228..cd59228 100644 --- a/geom_bottleneck/tests/data/test_770_B +++ b/bottleneck/tests/data/test_770_B diff --git a/geom_bottleneck/tests/data/test_771_A b/bottleneck/tests/data/test_771_A index 9c3f4ba..9c3f4ba 100644 --- a/geom_bottleneck/tests/data/test_771_A +++ b/bottleneck/tests/data/test_771_A diff --git a/geom_bottleneck/tests/data/test_771_B b/bottleneck/tests/data/test_771_B index 8c07a06..8c07a06 100644 --- a/geom_bottleneck/tests/data/test_771_B +++ b/bottleneck/tests/data/test_771_B diff --git a/geom_bottleneck/tests/data/test_772_A b/bottleneck/tests/data/test_772_A index 034ed92..034ed92 100644 --- a/geom_bottleneck/tests/data/test_772_A +++ b/bottleneck/tests/data/test_772_A diff --git a/geom_bottleneck/tests/data/test_772_B b/bottleneck/tests/data/test_772_B index bc29bff..bc29bff 100644 --- a/geom_bottleneck/tests/data/test_772_B +++ b/bottleneck/tests/data/test_772_B diff --git a/geom_bottleneck/tests/data/test_773_A b/bottleneck/tests/data/test_773_A index 0601e04..0601e04 100644 --- a/geom_bottleneck/tests/data/test_773_A +++ b/bottleneck/tests/data/test_773_A diff --git a/geom_bottleneck/tests/data/test_773_B b/bottleneck/tests/data/test_773_B index 004d2d6..004d2d6 100644 --- a/geom_bottleneck/tests/data/test_773_B +++ b/bottleneck/tests/data/test_773_B diff --git a/geom_bottleneck/tests/data/test_774_A b/bottleneck/tests/data/test_774_A index 3e211a0..3e211a0 100644 --- a/geom_bottleneck/tests/data/test_774_A +++ b/bottleneck/tests/data/test_774_A diff --git a/geom_bottleneck/tests/data/test_774_B b/bottleneck/tests/data/test_774_B index 3cf3985..3cf3985 100644 --- a/geom_bottleneck/tests/data/test_774_B +++ b/bottleneck/tests/data/test_774_B diff --git a/geom_bottleneck/tests/data/test_775_A b/bottleneck/tests/data/test_775_A index 5676eb4..5676eb4 100644 --- a/geom_bottleneck/tests/data/test_775_A +++ b/bottleneck/tests/data/test_775_A diff --git a/geom_bottleneck/tests/data/test_775_B b/bottleneck/tests/data/test_775_B index 5c4e8bc..5c4e8bc 100644 --- a/geom_bottleneck/tests/data/test_775_B +++ b/bottleneck/tests/data/test_775_B diff --git a/geom_bottleneck/tests/data/test_776_A b/bottleneck/tests/data/test_776_A index 49370ff..49370ff 100644 --- a/geom_bottleneck/tests/data/test_776_A +++ b/bottleneck/tests/data/test_776_A diff --git a/geom_bottleneck/tests/data/test_776_B b/bottleneck/tests/data/test_776_B index 575a2d9..575a2d9 100644 --- a/geom_bottleneck/tests/data/test_776_B +++ b/bottleneck/tests/data/test_776_B diff --git a/geom_bottleneck/tests/data/test_777_A b/bottleneck/tests/data/test_777_A index eb1c980..eb1c980 100644 --- a/geom_bottleneck/tests/data/test_777_A +++ b/bottleneck/tests/data/test_777_A diff --git a/geom_bottleneck/tests/data/test_777_B b/bottleneck/tests/data/test_777_B index eb9c8ee..eb9c8ee 100644 --- a/geom_bottleneck/tests/data/test_777_B +++ b/bottleneck/tests/data/test_777_B diff --git a/geom_bottleneck/tests/data/test_778_A b/bottleneck/tests/data/test_778_A index 8392b2a..8392b2a 100644 --- a/geom_bottleneck/tests/data/test_778_A +++ b/bottleneck/tests/data/test_778_A diff --git a/geom_bottleneck/tests/data/test_778_B b/bottleneck/tests/data/test_778_B index 017b08d..017b08d 100644 --- a/geom_bottleneck/tests/data/test_778_B +++ b/bottleneck/tests/data/test_778_B diff --git a/geom_bottleneck/tests/data/test_779_A b/bottleneck/tests/data/test_779_A index 221d574..221d574 100644 --- a/geom_bottleneck/tests/data/test_779_A +++ b/bottleneck/tests/data/test_779_A diff --git a/geom_bottleneck/tests/data/test_779_B b/bottleneck/tests/data/test_779_B index 113003e..113003e 100644 --- a/geom_bottleneck/tests/data/test_779_B +++ b/bottleneck/tests/data/test_779_B diff --git a/geom_bottleneck/tests/data/test_780_A b/bottleneck/tests/data/test_780_A index 3d9a22c..3d9a22c 100644 --- a/geom_bottleneck/tests/data/test_780_A +++ b/bottleneck/tests/data/test_780_A diff --git a/geom_bottleneck/tests/data/test_780_B b/bottleneck/tests/data/test_780_B index defbae9..defbae9 100644 --- a/geom_bottleneck/tests/data/test_780_B +++ b/bottleneck/tests/data/test_780_B diff --git a/geom_bottleneck/tests/data/test_781_A b/bottleneck/tests/data/test_781_A index 72201a7..72201a7 100644 --- a/geom_bottleneck/tests/data/test_781_A +++ b/bottleneck/tests/data/test_781_A diff --git a/geom_bottleneck/tests/data/test_781_B b/bottleneck/tests/data/test_781_B index 85c8683..85c8683 100644 --- a/geom_bottleneck/tests/data/test_781_B +++ b/bottleneck/tests/data/test_781_B diff --git a/geom_bottleneck/tests/data/test_782_A b/bottleneck/tests/data/test_782_A index b376509..b376509 100644 --- a/geom_bottleneck/tests/data/test_782_A +++ b/bottleneck/tests/data/test_782_A diff --git a/geom_bottleneck/tests/data/test_782_B b/bottleneck/tests/data/test_782_B index 9fba291..9fba291 100644 --- a/geom_bottleneck/tests/data/test_782_B +++ b/bottleneck/tests/data/test_782_B diff --git a/geom_bottleneck/tests/data/test_783_A b/bottleneck/tests/data/test_783_A index 83593db..83593db 100644 --- a/geom_bottleneck/tests/data/test_783_A +++ b/bottleneck/tests/data/test_783_A diff --git a/geom_bottleneck/tests/data/test_783_B b/bottleneck/tests/data/test_783_B index d169a48..d169a48 100644 --- a/geom_bottleneck/tests/data/test_783_B +++ b/bottleneck/tests/data/test_783_B diff --git a/geom_bottleneck/tests/data/test_784_A b/bottleneck/tests/data/test_784_A index b10df8b..b10df8b 100644 --- a/geom_bottleneck/tests/data/test_784_A +++ b/bottleneck/tests/data/test_784_A diff --git a/geom_bottleneck/tests/data/test_784_B b/bottleneck/tests/data/test_784_B index ef2b466..ef2b466 100644 --- a/geom_bottleneck/tests/data/test_784_B +++ b/bottleneck/tests/data/test_784_B diff --git a/geom_bottleneck/tests/data/test_785_A b/bottleneck/tests/data/test_785_A index 3cdfaba..3cdfaba 100644 --- a/geom_bottleneck/tests/data/test_785_A +++ b/bottleneck/tests/data/test_785_A diff --git a/geom_bottleneck/tests/data/test_785_B b/bottleneck/tests/data/test_785_B index 32fe176..32fe176 100644 --- a/geom_bottleneck/tests/data/test_785_B +++ b/bottleneck/tests/data/test_785_B diff --git a/geom_bottleneck/tests/data/test_786_A b/bottleneck/tests/data/test_786_A index 2d9fcec..2d9fcec 100644 --- a/geom_bottleneck/tests/data/test_786_A +++ b/bottleneck/tests/data/test_786_A diff --git a/geom_bottleneck/tests/data/test_786_B b/bottleneck/tests/data/test_786_B index 417ee4b..417ee4b 100644 --- a/geom_bottleneck/tests/data/test_786_B +++ b/bottleneck/tests/data/test_786_B diff --git a/geom_bottleneck/tests/data/test_787_A b/bottleneck/tests/data/test_787_A index 7c056b6..7c056b6 100644 --- a/geom_bottleneck/tests/data/test_787_A +++ b/bottleneck/tests/data/test_787_A diff --git a/geom_bottleneck/tests/data/test_787_B b/bottleneck/tests/data/test_787_B index ddc126a..ddc126a 100644 --- a/geom_bottleneck/tests/data/test_787_B +++ b/bottleneck/tests/data/test_787_B diff --git a/geom_bottleneck/tests/data/test_788_A b/bottleneck/tests/data/test_788_A index 61a58b0..61a58b0 100644 --- a/geom_bottleneck/tests/data/test_788_A +++ b/bottleneck/tests/data/test_788_A diff --git a/geom_bottleneck/tests/data/test_788_B b/bottleneck/tests/data/test_788_B index d0782d9..d0782d9 100644 --- a/geom_bottleneck/tests/data/test_788_B +++ b/bottleneck/tests/data/test_788_B diff --git a/geom_bottleneck/tests/data/test_789_A b/bottleneck/tests/data/test_789_A index 4805534..4805534 100644 --- a/geom_bottleneck/tests/data/test_789_A +++ b/bottleneck/tests/data/test_789_A diff --git a/geom_bottleneck/tests/data/test_789_B b/bottleneck/tests/data/test_789_B index 808dab9..808dab9 100644 --- a/geom_bottleneck/tests/data/test_789_B +++ b/bottleneck/tests/data/test_789_B diff --git a/geom_bottleneck/tests/data/test_790_A b/bottleneck/tests/data/test_790_A index 231f25c..231f25c 100644 --- a/geom_bottleneck/tests/data/test_790_A +++ b/bottleneck/tests/data/test_790_A diff --git a/geom_bottleneck/tests/data/test_790_B b/bottleneck/tests/data/test_790_B index 0892cfe..0892cfe 100644 --- a/geom_bottleneck/tests/data/test_790_B +++ b/bottleneck/tests/data/test_790_B diff --git a/geom_bottleneck/tests/data/test_791_A b/bottleneck/tests/data/test_791_A index e12631e..e12631e 100644 --- a/geom_bottleneck/tests/data/test_791_A +++ b/bottleneck/tests/data/test_791_A diff --git a/geom_bottleneck/tests/data/test_791_B b/bottleneck/tests/data/test_791_B index 62aa958..62aa958 100644 --- a/geom_bottleneck/tests/data/test_791_B +++ b/bottleneck/tests/data/test_791_B diff --git a/geom_bottleneck/tests/data/test_792_A b/bottleneck/tests/data/test_792_A index 3b73b46..3b73b46 100644 --- a/geom_bottleneck/tests/data/test_792_A +++ b/bottleneck/tests/data/test_792_A diff --git a/geom_bottleneck/tests/data/test_792_B b/bottleneck/tests/data/test_792_B index 517ff30..517ff30 100644 --- a/geom_bottleneck/tests/data/test_792_B +++ b/bottleneck/tests/data/test_792_B diff --git a/geom_bottleneck/tests/data/test_793_A b/bottleneck/tests/data/test_793_A index d9b85ae..d9b85ae 100644 --- a/geom_bottleneck/tests/data/test_793_A +++ b/bottleneck/tests/data/test_793_A diff --git a/geom_bottleneck/tests/data/test_793_B b/bottleneck/tests/data/test_793_B index 66180dd..66180dd 100644 --- a/geom_bottleneck/tests/data/test_793_B +++ b/bottleneck/tests/data/test_793_B diff --git a/geom_bottleneck/tests/data/test_794_A b/bottleneck/tests/data/test_794_A index 3d5401c..3d5401c 100644 --- a/geom_bottleneck/tests/data/test_794_A +++ b/bottleneck/tests/data/test_794_A diff --git a/geom_bottleneck/tests/data/test_794_B b/bottleneck/tests/data/test_794_B index 26be9a3..26be9a3 100644 --- a/geom_bottleneck/tests/data/test_794_B +++ b/bottleneck/tests/data/test_794_B diff --git a/geom_bottleneck/tests/data/test_795_A b/bottleneck/tests/data/test_795_A index 7c73f4d..7c73f4d 100644 --- a/geom_bottleneck/tests/data/test_795_A +++ b/bottleneck/tests/data/test_795_A diff --git a/geom_bottleneck/tests/data/test_795_B b/bottleneck/tests/data/test_795_B index afc371b..afc371b 100644 --- a/geom_bottleneck/tests/data/test_795_B +++ b/bottleneck/tests/data/test_795_B diff --git a/geom_bottleneck/tests/data/test_796_A b/bottleneck/tests/data/test_796_A index a326a52..a326a52 100644 --- a/geom_bottleneck/tests/data/test_796_A +++ b/bottleneck/tests/data/test_796_A diff --git a/geom_bottleneck/tests/data/test_796_B b/bottleneck/tests/data/test_796_B index 86d2cf9..86d2cf9 100644 --- a/geom_bottleneck/tests/data/test_796_B +++ b/bottleneck/tests/data/test_796_B diff --git a/geom_bottleneck/tests/data/test_797_A b/bottleneck/tests/data/test_797_A index b5149bf..b5149bf 100644 --- a/geom_bottleneck/tests/data/test_797_A +++ b/bottleneck/tests/data/test_797_A diff --git a/geom_bottleneck/tests/data/test_797_B b/bottleneck/tests/data/test_797_B index 45ba81b..45ba81b 100644 --- a/geom_bottleneck/tests/data/test_797_B +++ b/bottleneck/tests/data/test_797_B diff --git a/geom_bottleneck/tests/data/test_798_A b/bottleneck/tests/data/test_798_A index a053ddd..a053ddd 100644 --- a/geom_bottleneck/tests/data/test_798_A +++ b/bottleneck/tests/data/test_798_A diff --git a/geom_bottleneck/tests/data/test_798_B b/bottleneck/tests/data/test_798_B index 69c921b..69c921b 100644 --- a/geom_bottleneck/tests/data/test_798_B +++ b/bottleneck/tests/data/test_798_B diff --git a/geom_bottleneck/tests/data/test_799_A b/bottleneck/tests/data/test_799_A index 374e56a..374e56a 100644 --- a/geom_bottleneck/tests/data/test_799_A +++ b/bottleneck/tests/data/test_799_A diff --git a/geom_bottleneck/tests/data/test_799_B b/bottleneck/tests/data/test_799_B index f92c370..f92c370 100644 --- a/geom_bottleneck/tests/data/test_799_B +++ b/bottleneck/tests/data/test_799_B diff --git a/geom_bottleneck/tests/data/test_800_A b/bottleneck/tests/data/test_800_A index 36aab61..36aab61 100644 --- a/geom_bottleneck/tests/data/test_800_A +++ b/bottleneck/tests/data/test_800_A diff --git a/geom_bottleneck/tests/data/test_800_B b/bottleneck/tests/data/test_800_B index 2496bcb..2496bcb 100644 --- a/geom_bottleneck/tests/data/test_800_B +++ b/bottleneck/tests/data/test_800_B diff --git a/geom_bottleneck/tests/data/test_801_A b/bottleneck/tests/data/test_801_A index 66ed176..66ed176 100644 --- a/geom_bottleneck/tests/data/test_801_A +++ b/bottleneck/tests/data/test_801_A diff --git a/geom_bottleneck/tests/data/test_801_B b/bottleneck/tests/data/test_801_B index 4376fcf..4376fcf 100644 --- a/geom_bottleneck/tests/data/test_801_B +++ b/bottleneck/tests/data/test_801_B diff --git a/geom_bottleneck/tests/data/test_802_A b/bottleneck/tests/data/test_802_A index 6bfdeda..6bfdeda 100644 --- a/geom_bottleneck/tests/data/test_802_A +++ b/bottleneck/tests/data/test_802_A diff --git a/geom_bottleneck/tests/data/test_802_B b/bottleneck/tests/data/test_802_B index eaec985..eaec985 100644 --- a/geom_bottleneck/tests/data/test_802_B +++ b/bottleneck/tests/data/test_802_B diff --git a/geom_bottleneck/tests/data/test_803_A b/bottleneck/tests/data/test_803_A index 501248d..501248d 100644 --- a/geom_bottleneck/tests/data/test_803_A +++ b/bottleneck/tests/data/test_803_A diff --git a/geom_bottleneck/tests/data/test_803_B b/bottleneck/tests/data/test_803_B index 42dadd9..42dadd9 100644 --- a/geom_bottleneck/tests/data/test_803_B +++ b/bottleneck/tests/data/test_803_B diff --git a/geom_bottleneck/tests/data/test_804_A b/bottleneck/tests/data/test_804_A index 6af9294..6af9294 100644 --- a/geom_bottleneck/tests/data/test_804_A +++ b/bottleneck/tests/data/test_804_A diff --git a/geom_bottleneck/tests/data/test_804_B b/bottleneck/tests/data/test_804_B index 8470b65..8470b65 100644 --- a/geom_bottleneck/tests/data/test_804_B +++ b/bottleneck/tests/data/test_804_B diff --git a/geom_bottleneck/tests/data/test_805_A b/bottleneck/tests/data/test_805_A index 45a3198..45a3198 100644 --- a/geom_bottleneck/tests/data/test_805_A +++ b/bottleneck/tests/data/test_805_A diff --git a/geom_bottleneck/tests/data/test_805_B b/bottleneck/tests/data/test_805_B index 4967cfd..4967cfd 100644 --- a/geom_bottleneck/tests/data/test_805_B +++ b/bottleneck/tests/data/test_805_B diff --git a/geom_bottleneck/tests/data/test_806_A b/bottleneck/tests/data/test_806_A index 8eb1e33..8eb1e33 100644 --- a/geom_bottleneck/tests/data/test_806_A +++ b/bottleneck/tests/data/test_806_A diff --git a/geom_bottleneck/tests/data/test_806_B b/bottleneck/tests/data/test_806_B index 27727b2..27727b2 100644 --- a/geom_bottleneck/tests/data/test_806_B +++ b/bottleneck/tests/data/test_806_B diff --git a/geom_bottleneck/tests/data/test_807_A b/bottleneck/tests/data/test_807_A index 4979b7d..4979b7d 100644 --- a/geom_bottleneck/tests/data/test_807_A +++ b/bottleneck/tests/data/test_807_A diff --git a/geom_bottleneck/tests/data/test_807_B b/bottleneck/tests/data/test_807_B index 67610cb..67610cb 100644 --- a/geom_bottleneck/tests/data/test_807_B +++ b/bottleneck/tests/data/test_807_B diff --git a/geom_bottleneck/tests/data/test_808_A b/bottleneck/tests/data/test_808_A index b35d354..b35d354 100644 --- a/geom_bottleneck/tests/data/test_808_A +++ b/bottleneck/tests/data/test_808_A diff --git a/geom_bottleneck/tests/data/test_808_B b/bottleneck/tests/data/test_808_B index fb783cb..fb783cb 100644 --- a/geom_bottleneck/tests/data/test_808_B +++ b/bottleneck/tests/data/test_808_B diff --git a/geom_bottleneck/tests/data/test_809_A b/bottleneck/tests/data/test_809_A index e578429..e578429 100644 --- a/geom_bottleneck/tests/data/test_809_A +++ b/bottleneck/tests/data/test_809_A diff --git a/geom_bottleneck/tests/data/test_809_B b/bottleneck/tests/data/test_809_B index e4deda8..e4deda8 100644 --- a/geom_bottleneck/tests/data/test_809_B +++ b/bottleneck/tests/data/test_809_B diff --git a/geom_bottleneck/tests/data/test_810_A b/bottleneck/tests/data/test_810_A index b7da658..b7da658 100644 --- a/geom_bottleneck/tests/data/test_810_A +++ b/bottleneck/tests/data/test_810_A diff --git a/geom_bottleneck/tests/data/test_810_B b/bottleneck/tests/data/test_810_B index 06e2af4..06e2af4 100644 --- a/geom_bottleneck/tests/data/test_810_B +++ b/bottleneck/tests/data/test_810_B diff --git a/geom_bottleneck/tests/data/test_811_A b/bottleneck/tests/data/test_811_A index 708fc33..708fc33 100644 --- a/geom_bottleneck/tests/data/test_811_A +++ b/bottleneck/tests/data/test_811_A diff --git a/geom_bottleneck/tests/data/test_811_B b/bottleneck/tests/data/test_811_B index 69bffab..69bffab 100644 --- a/geom_bottleneck/tests/data/test_811_B +++ b/bottleneck/tests/data/test_811_B diff --git a/geom_bottleneck/tests/data/test_812_A b/bottleneck/tests/data/test_812_A index f592f5f..f592f5f 100644 --- a/geom_bottleneck/tests/data/test_812_A +++ b/bottleneck/tests/data/test_812_A diff --git a/geom_bottleneck/tests/data/test_812_B b/bottleneck/tests/data/test_812_B index 7e37dec..7e37dec 100644 --- a/geom_bottleneck/tests/data/test_812_B +++ b/bottleneck/tests/data/test_812_B diff --git a/geom_bottleneck/tests/data/test_813_A b/bottleneck/tests/data/test_813_A index 94bbbc3..94bbbc3 100644 --- a/geom_bottleneck/tests/data/test_813_A +++ b/bottleneck/tests/data/test_813_A diff --git a/geom_bottleneck/tests/data/test_813_B b/bottleneck/tests/data/test_813_B index 54ce63b..54ce63b 100644 --- a/geom_bottleneck/tests/data/test_813_B +++ b/bottleneck/tests/data/test_813_B diff --git a/geom_bottleneck/tests/data/test_814_A b/bottleneck/tests/data/test_814_A index 3eb0a25..3eb0a25 100644 --- a/geom_bottleneck/tests/data/test_814_A +++ b/bottleneck/tests/data/test_814_A diff --git a/geom_bottleneck/tests/data/test_814_B b/bottleneck/tests/data/test_814_B index a65d82f..a65d82f 100644 --- a/geom_bottleneck/tests/data/test_814_B +++ b/bottleneck/tests/data/test_814_B diff --git a/geom_bottleneck/tests/data/test_815_A b/bottleneck/tests/data/test_815_A index ae366c6..ae366c6 100644 --- a/geom_bottleneck/tests/data/test_815_A +++ b/bottleneck/tests/data/test_815_A diff --git a/geom_bottleneck/tests/data/test_815_B b/bottleneck/tests/data/test_815_B index 6d11d46..6d11d46 100644 --- a/geom_bottleneck/tests/data/test_815_B +++ b/bottleneck/tests/data/test_815_B diff --git a/geom_bottleneck/tests/data/test_816_A b/bottleneck/tests/data/test_816_A index 54dc128..54dc128 100644 --- a/geom_bottleneck/tests/data/test_816_A +++ b/bottleneck/tests/data/test_816_A diff --git a/geom_bottleneck/tests/data/test_816_B b/bottleneck/tests/data/test_816_B index 56f00ce..56f00ce 100644 --- a/geom_bottleneck/tests/data/test_816_B +++ b/bottleneck/tests/data/test_816_B diff --git a/geom_bottleneck/tests/data/test_817_A b/bottleneck/tests/data/test_817_A index 8c01be3..8c01be3 100644 --- a/geom_bottleneck/tests/data/test_817_A +++ b/bottleneck/tests/data/test_817_A diff --git a/geom_bottleneck/tests/data/test_817_B b/bottleneck/tests/data/test_817_B index 1aa1eaa..1aa1eaa 100644 --- a/geom_bottleneck/tests/data/test_817_B +++ b/bottleneck/tests/data/test_817_B diff --git a/geom_bottleneck/tests/data/test_818_A b/bottleneck/tests/data/test_818_A index 44ac7de..44ac7de 100644 --- a/geom_bottleneck/tests/data/test_818_A +++ b/bottleneck/tests/data/test_818_A diff --git a/geom_bottleneck/tests/data/test_818_B b/bottleneck/tests/data/test_818_B index 83c706c..83c706c 100644 --- a/geom_bottleneck/tests/data/test_818_B +++ b/bottleneck/tests/data/test_818_B diff --git a/geom_bottleneck/tests/data/test_819_A b/bottleneck/tests/data/test_819_A index 1065f24..1065f24 100644 --- a/geom_bottleneck/tests/data/test_819_A +++ b/bottleneck/tests/data/test_819_A diff --git a/geom_bottleneck/tests/data/test_819_B b/bottleneck/tests/data/test_819_B index f1c8ba3..f1c8ba3 100644 --- a/geom_bottleneck/tests/data/test_819_B +++ b/bottleneck/tests/data/test_819_B diff --git a/geom_bottleneck/tests/data/test_820_A b/bottleneck/tests/data/test_820_A index 1f23572..1f23572 100644 --- a/geom_bottleneck/tests/data/test_820_A +++ b/bottleneck/tests/data/test_820_A diff --git a/geom_bottleneck/tests/data/test_820_B b/bottleneck/tests/data/test_820_B index 3465e1b..3465e1b 100644 --- a/geom_bottleneck/tests/data/test_820_B +++ b/bottleneck/tests/data/test_820_B diff --git a/geom_bottleneck/tests/data/test_821_A b/bottleneck/tests/data/test_821_A index ab4fa20..ab4fa20 100644 --- a/geom_bottleneck/tests/data/test_821_A +++ b/bottleneck/tests/data/test_821_A diff --git a/geom_bottleneck/tests/data/test_821_B b/bottleneck/tests/data/test_821_B index 36073ce..36073ce 100644 --- a/geom_bottleneck/tests/data/test_821_B +++ b/bottleneck/tests/data/test_821_B diff --git a/geom_bottleneck/tests/data/test_822_A b/bottleneck/tests/data/test_822_A index 38b5219..38b5219 100644 --- a/geom_bottleneck/tests/data/test_822_A +++ b/bottleneck/tests/data/test_822_A diff --git a/geom_bottleneck/tests/data/test_822_B b/bottleneck/tests/data/test_822_B index c61c33e..c61c33e 100644 --- a/geom_bottleneck/tests/data/test_822_B +++ b/bottleneck/tests/data/test_822_B diff --git a/geom_bottleneck/tests/data/test_823_A b/bottleneck/tests/data/test_823_A index 5d441a2..5d441a2 100644 --- a/geom_bottleneck/tests/data/test_823_A +++ b/bottleneck/tests/data/test_823_A diff --git a/geom_bottleneck/tests/data/test_823_B b/bottleneck/tests/data/test_823_B index e1ae113..e1ae113 100644 --- a/geom_bottleneck/tests/data/test_823_B +++ b/bottleneck/tests/data/test_823_B diff --git a/geom_bottleneck/tests/data/test_824_A b/bottleneck/tests/data/test_824_A index 3bfc169..3bfc169 100644 --- a/geom_bottleneck/tests/data/test_824_A +++ b/bottleneck/tests/data/test_824_A diff --git a/geom_bottleneck/tests/data/test_824_B b/bottleneck/tests/data/test_824_B index 192df92..192df92 100644 --- a/geom_bottleneck/tests/data/test_824_B +++ b/bottleneck/tests/data/test_824_B diff --git a/geom_bottleneck/tests/data/test_825_A b/bottleneck/tests/data/test_825_A index 5dc0d10..5dc0d10 100644 --- a/geom_bottleneck/tests/data/test_825_A +++ b/bottleneck/tests/data/test_825_A diff --git a/geom_bottleneck/tests/data/test_825_B b/bottleneck/tests/data/test_825_B index e440801..e440801 100644 --- a/geom_bottleneck/tests/data/test_825_B +++ b/bottleneck/tests/data/test_825_B diff --git a/geom_bottleneck/tests/data/test_826_A b/bottleneck/tests/data/test_826_A index 8fbcf93..8fbcf93 100644 --- a/geom_bottleneck/tests/data/test_826_A +++ b/bottleneck/tests/data/test_826_A diff --git a/geom_bottleneck/tests/data/test_826_B b/bottleneck/tests/data/test_826_B index 10fe424..10fe424 100644 --- a/geom_bottleneck/tests/data/test_826_B +++ b/bottleneck/tests/data/test_826_B diff --git a/geom_bottleneck/tests/data/test_827_A b/bottleneck/tests/data/test_827_A index c1c63c9..c1c63c9 100644 --- a/geom_bottleneck/tests/data/test_827_A +++ b/bottleneck/tests/data/test_827_A diff --git a/geom_bottleneck/tests/data/test_827_B b/bottleneck/tests/data/test_827_B index 57ea673..57ea673 100644 --- a/geom_bottleneck/tests/data/test_827_B +++ b/bottleneck/tests/data/test_827_B diff --git a/geom_bottleneck/tests/data/test_828_A b/bottleneck/tests/data/test_828_A index ee02128..ee02128 100644 --- a/geom_bottleneck/tests/data/test_828_A +++ b/bottleneck/tests/data/test_828_A diff --git a/geom_bottleneck/tests/data/test_828_B b/bottleneck/tests/data/test_828_B index 92fae09..92fae09 100644 --- a/geom_bottleneck/tests/data/test_828_B +++ b/bottleneck/tests/data/test_828_B diff --git a/geom_bottleneck/tests/data/test_829_A b/bottleneck/tests/data/test_829_A index fceb407..fceb407 100644 --- a/geom_bottleneck/tests/data/test_829_A +++ b/bottleneck/tests/data/test_829_A diff --git a/geom_bottleneck/tests/data/test_829_B b/bottleneck/tests/data/test_829_B index 85f538c..85f538c 100644 --- a/geom_bottleneck/tests/data/test_829_B +++ b/bottleneck/tests/data/test_829_B diff --git a/geom_bottleneck/tests/data/test_830_A b/bottleneck/tests/data/test_830_A index fd54955..fd54955 100644 --- a/geom_bottleneck/tests/data/test_830_A +++ b/bottleneck/tests/data/test_830_A diff --git a/geom_bottleneck/tests/data/test_830_B b/bottleneck/tests/data/test_830_B index 5b9d84b..5b9d84b 100644 --- a/geom_bottleneck/tests/data/test_830_B +++ b/bottleneck/tests/data/test_830_B diff --git a/geom_bottleneck/tests/data/test_831_A b/bottleneck/tests/data/test_831_A index fe09be1..fe09be1 100644 --- a/geom_bottleneck/tests/data/test_831_A +++ b/bottleneck/tests/data/test_831_A diff --git a/geom_bottleneck/tests/data/test_831_B b/bottleneck/tests/data/test_831_B index 1f4d148..1f4d148 100644 --- a/geom_bottleneck/tests/data/test_831_B +++ b/bottleneck/tests/data/test_831_B diff --git a/geom_bottleneck/tests/data/test_832_A b/bottleneck/tests/data/test_832_A index 79d3383..79d3383 100644 --- a/geom_bottleneck/tests/data/test_832_A +++ b/bottleneck/tests/data/test_832_A diff --git a/geom_bottleneck/tests/data/test_832_B b/bottleneck/tests/data/test_832_B index 9106904..9106904 100644 --- a/geom_bottleneck/tests/data/test_832_B +++ b/bottleneck/tests/data/test_832_B diff --git a/geom_bottleneck/tests/data/test_833_A b/bottleneck/tests/data/test_833_A index 1dbdd95..1dbdd95 100644 --- a/geom_bottleneck/tests/data/test_833_A +++ b/bottleneck/tests/data/test_833_A diff --git a/geom_bottleneck/tests/data/test_833_B b/bottleneck/tests/data/test_833_B index a325070..a325070 100644 --- a/geom_bottleneck/tests/data/test_833_B +++ b/bottleneck/tests/data/test_833_B diff --git a/geom_bottleneck/tests/data/test_834_A b/bottleneck/tests/data/test_834_A index 7088d54..7088d54 100644 --- a/geom_bottleneck/tests/data/test_834_A +++ b/bottleneck/tests/data/test_834_A diff --git a/geom_bottleneck/tests/data/test_834_B b/bottleneck/tests/data/test_834_B index 5dd4204..5dd4204 100644 --- a/geom_bottleneck/tests/data/test_834_B +++ b/bottleneck/tests/data/test_834_B diff --git a/geom_bottleneck/tests/data/test_835_A b/bottleneck/tests/data/test_835_A index 47e934b..47e934b 100644 --- a/geom_bottleneck/tests/data/test_835_A +++ b/bottleneck/tests/data/test_835_A diff --git a/geom_bottleneck/tests/data/test_835_B b/bottleneck/tests/data/test_835_B index 9a3edbe..9a3edbe 100644 --- a/geom_bottleneck/tests/data/test_835_B +++ b/bottleneck/tests/data/test_835_B diff --git a/geom_bottleneck/tests/data/test_836_A b/bottleneck/tests/data/test_836_A index 1a9885f..1a9885f 100644 --- a/geom_bottleneck/tests/data/test_836_A +++ b/bottleneck/tests/data/test_836_A diff --git a/geom_bottleneck/tests/data/test_836_B b/bottleneck/tests/data/test_836_B index 8335ddf..8335ddf 100644 --- a/geom_bottleneck/tests/data/test_836_B +++ b/bottleneck/tests/data/test_836_B diff --git a/geom_bottleneck/tests/data/test_837_A b/bottleneck/tests/data/test_837_A index 8d3facc..8d3facc 100644 --- a/geom_bottleneck/tests/data/test_837_A +++ b/bottleneck/tests/data/test_837_A diff --git a/geom_bottleneck/tests/data/test_837_B b/bottleneck/tests/data/test_837_B index 8439a1f..8439a1f 100644 --- a/geom_bottleneck/tests/data/test_837_B +++ b/bottleneck/tests/data/test_837_B diff --git a/geom_bottleneck/tests/data/test_838_A b/bottleneck/tests/data/test_838_A index 9f6e83e..9f6e83e 100644 --- a/geom_bottleneck/tests/data/test_838_A +++ b/bottleneck/tests/data/test_838_A diff --git a/geom_bottleneck/tests/data/test_838_B b/bottleneck/tests/data/test_838_B index 227776e..227776e 100644 --- a/geom_bottleneck/tests/data/test_838_B +++ b/bottleneck/tests/data/test_838_B diff --git a/geom_bottleneck/tests/data/test_839_A b/bottleneck/tests/data/test_839_A index 073be3c..073be3c 100644 --- a/geom_bottleneck/tests/data/test_839_A +++ b/bottleneck/tests/data/test_839_A diff --git a/geom_bottleneck/tests/data/test_839_B b/bottleneck/tests/data/test_839_B index ca5ee3e..ca5ee3e 100644 --- a/geom_bottleneck/tests/data/test_839_B +++ b/bottleneck/tests/data/test_839_B diff --git a/geom_bottleneck/tests/data/test_840_A b/bottleneck/tests/data/test_840_A index 02ed823..02ed823 100644 --- a/geom_bottleneck/tests/data/test_840_A +++ b/bottleneck/tests/data/test_840_A diff --git a/geom_bottleneck/tests/data/test_840_B b/bottleneck/tests/data/test_840_B index 4bd5737..4bd5737 100644 --- a/geom_bottleneck/tests/data/test_840_B +++ b/bottleneck/tests/data/test_840_B diff --git a/geom_bottleneck/tests/data/test_841_A b/bottleneck/tests/data/test_841_A index d6b2c08..d6b2c08 100644 --- a/geom_bottleneck/tests/data/test_841_A +++ b/bottleneck/tests/data/test_841_A diff --git a/geom_bottleneck/tests/data/test_841_B b/bottleneck/tests/data/test_841_B index 9775dd8..9775dd8 100644 --- a/geom_bottleneck/tests/data/test_841_B +++ b/bottleneck/tests/data/test_841_B diff --git a/geom_bottleneck/tests/data/test_842_A b/bottleneck/tests/data/test_842_A index 49124dc..49124dc 100644 --- a/geom_bottleneck/tests/data/test_842_A +++ b/bottleneck/tests/data/test_842_A diff --git a/geom_bottleneck/tests/data/test_842_B b/bottleneck/tests/data/test_842_B index 36715f2..36715f2 100644 --- a/geom_bottleneck/tests/data/test_842_B +++ b/bottleneck/tests/data/test_842_B diff --git a/geom_bottleneck/tests/data/test_843_A b/bottleneck/tests/data/test_843_A index aa5cea9..aa5cea9 100644 --- a/geom_bottleneck/tests/data/test_843_A +++ b/bottleneck/tests/data/test_843_A diff --git a/geom_bottleneck/tests/data/test_843_B b/bottleneck/tests/data/test_843_B index b14eed6..b14eed6 100644 --- a/geom_bottleneck/tests/data/test_843_B +++ b/bottleneck/tests/data/test_843_B diff --git a/geom_bottleneck/tests/data/test_844_A b/bottleneck/tests/data/test_844_A index 753b2fc..753b2fc 100644 --- a/geom_bottleneck/tests/data/test_844_A +++ b/bottleneck/tests/data/test_844_A diff --git a/geom_bottleneck/tests/data/test_844_B b/bottleneck/tests/data/test_844_B index 373d26c..373d26c 100644 --- a/geom_bottleneck/tests/data/test_844_B +++ b/bottleneck/tests/data/test_844_B diff --git a/geom_bottleneck/tests/data/test_845_A b/bottleneck/tests/data/test_845_A index 2015fbb..2015fbb 100644 --- a/geom_bottleneck/tests/data/test_845_A +++ b/bottleneck/tests/data/test_845_A diff --git a/geom_bottleneck/tests/data/test_845_B b/bottleneck/tests/data/test_845_B index b053f52..b053f52 100644 --- a/geom_bottleneck/tests/data/test_845_B +++ b/bottleneck/tests/data/test_845_B diff --git a/geom_bottleneck/tests/data/test_846_A b/bottleneck/tests/data/test_846_A index 520c6d4..520c6d4 100644 --- a/geom_bottleneck/tests/data/test_846_A +++ b/bottleneck/tests/data/test_846_A diff --git a/geom_bottleneck/tests/data/test_846_B b/bottleneck/tests/data/test_846_B index 3046f20..3046f20 100644 --- a/geom_bottleneck/tests/data/test_846_B +++ b/bottleneck/tests/data/test_846_B diff --git a/geom_bottleneck/tests/data/test_847_A b/bottleneck/tests/data/test_847_A index ee5c8c1..ee5c8c1 100644 --- a/geom_bottleneck/tests/data/test_847_A +++ b/bottleneck/tests/data/test_847_A diff --git a/geom_bottleneck/tests/data/test_847_B b/bottleneck/tests/data/test_847_B index de6f45a..de6f45a 100644 --- a/geom_bottleneck/tests/data/test_847_B +++ b/bottleneck/tests/data/test_847_B diff --git a/geom_bottleneck/tests/data/test_848_A b/bottleneck/tests/data/test_848_A index e9e603b..e9e603b 100644 --- a/geom_bottleneck/tests/data/test_848_A +++ b/bottleneck/tests/data/test_848_A diff --git a/geom_bottleneck/tests/data/test_848_B b/bottleneck/tests/data/test_848_B index 00005be..00005be 100644 --- a/geom_bottleneck/tests/data/test_848_B +++ b/bottleneck/tests/data/test_848_B diff --git a/geom_bottleneck/tests/data/test_849_A b/bottleneck/tests/data/test_849_A index 7938a96..7938a96 100644 --- a/geom_bottleneck/tests/data/test_849_A +++ b/bottleneck/tests/data/test_849_A diff --git a/geom_bottleneck/tests/data/test_849_B b/bottleneck/tests/data/test_849_B index 21da75d..21da75d 100644 --- a/geom_bottleneck/tests/data/test_849_B +++ b/bottleneck/tests/data/test_849_B diff --git a/geom_bottleneck/tests/data/test_850_A b/bottleneck/tests/data/test_850_A index dfb2165..dfb2165 100644 --- a/geom_bottleneck/tests/data/test_850_A +++ b/bottleneck/tests/data/test_850_A diff --git a/geom_bottleneck/tests/data/test_850_B b/bottleneck/tests/data/test_850_B index 573788d..573788d 100644 --- a/geom_bottleneck/tests/data/test_850_B +++ b/bottleneck/tests/data/test_850_B diff --git a/geom_bottleneck/tests/data/test_851_A b/bottleneck/tests/data/test_851_A index 0a2f88e..0a2f88e 100644 --- a/geom_bottleneck/tests/data/test_851_A +++ b/bottleneck/tests/data/test_851_A diff --git a/geom_bottleneck/tests/data/test_851_B b/bottleneck/tests/data/test_851_B index 8e4b97e..8e4b97e 100644 --- a/geom_bottleneck/tests/data/test_851_B +++ b/bottleneck/tests/data/test_851_B diff --git a/geom_bottleneck/tests/data/test_852_A b/bottleneck/tests/data/test_852_A index 3d8f706..3d8f706 100644 --- a/geom_bottleneck/tests/data/test_852_A +++ b/bottleneck/tests/data/test_852_A diff --git a/geom_bottleneck/tests/data/test_852_B b/bottleneck/tests/data/test_852_B index 9de826f..9de826f 100644 --- a/geom_bottleneck/tests/data/test_852_B +++ b/bottleneck/tests/data/test_852_B diff --git a/geom_bottleneck/tests/data/test_853_A b/bottleneck/tests/data/test_853_A index bcf5afe..bcf5afe 100644 --- a/geom_bottleneck/tests/data/test_853_A +++ b/bottleneck/tests/data/test_853_A diff --git a/geom_bottleneck/tests/data/test_853_B b/bottleneck/tests/data/test_853_B index d294f05..d294f05 100644 --- a/geom_bottleneck/tests/data/test_853_B +++ b/bottleneck/tests/data/test_853_B diff --git a/geom_bottleneck/tests/data/test_854_A b/bottleneck/tests/data/test_854_A index 4765953..4765953 100644 --- a/geom_bottleneck/tests/data/test_854_A +++ b/bottleneck/tests/data/test_854_A diff --git a/geom_bottleneck/tests/data/test_854_B b/bottleneck/tests/data/test_854_B index aa949eb..aa949eb 100644 --- a/geom_bottleneck/tests/data/test_854_B +++ b/bottleneck/tests/data/test_854_B diff --git a/geom_bottleneck/tests/data/test_855_A b/bottleneck/tests/data/test_855_A index ab7ec0b..ab7ec0b 100644 --- a/geom_bottleneck/tests/data/test_855_A +++ b/bottleneck/tests/data/test_855_A diff --git a/geom_bottleneck/tests/data/test_855_B b/bottleneck/tests/data/test_855_B index be6ff94..be6ff94 100644 --- a/geom_bottleneck/tests/data/test_855_B +++ b/bottleneck/tests/data/test_855_B diff --git a/geom_bottleneck/tests/data/test_856_A b/bottleneck/tests/data/test_856_A index 3cbfae3..3cbfae3 100644 --- a/geom_bottleneck/tests/data/test_856_A +++ b/bottleneck/tests/data/test_856_A diff --git a/geom_bottleneck/tests/data/test_856_B b/bottleneck/tests/data/test_856_B index ec34ae9..ec34ae9 100644 --- a/geom_bottleneck/tests/data/test_856_B +++ b/bottleneck/tests/data/test_856_B diff --git a/geom_bottleneck/tests/data/test_857_A b/bottleneck/tests/data/test_857_A index 6bbbf0b..6bbbf0b 100644 --- a/geom_bottleneck/tests/data/test_857_A +++ b/bottleneck/tests/data/test_857_A diff --git a/geom_bottleneck/tests/data/test_857_B b/bottleneck/tests/data/test_857_B index 2d0ac7d..2d0ac7d 100644 --- a/geom_bottleneck/tests/data/test_857_B +++ b/bottleneck/tests/data/test_857_B diff --git a/geom_bottleneck/tests/data/test_858_A b/bottleneck/tests/data/test_858_A index 1d3b9ad..1d3b9ad 100644 --- a/geom_bottleneck/tests/data/test_858_A +++ b/bottleneck/tests/data/test_858_A diff --git a/geom_bottleneck/tests/data/test_858_B b/bottleneck/tests/data/test_858_B index a982114..a982114 100644 --- a/geom_bottleneck/tests/data/test_858_B +++ b/bottleneck/tests/data/test_858_B diff --git a/geom_bottleneck/tests/data/test_859_A b/bottleneck/tests/data/test_859_A index 24bd533..24bd533 100644 --- a/geom_bottleneck/tests/data/test_859_A +++ b/bottleneck/tests/data/test_859_A diff --git a/geom_bottleneck/tests/data/test_859_B b/bottleneck/tests/data/test_859_B index ac8c3b7..ac8c3b7 100644 --- a/geom_bottleneck/tests/data/test_859_B +++ b/bottleneck/tests/data/test_859_B diff --git a/geom_bottleneck/tests/data/test_860_A b/bottleneck/tests/data/test_860_A index bef7e26..bef7e26 100644 --- a/geom_bottleneck/tests/data/test_860_A +++ b/bottleneck/tests/data/test_860_A diff --git a/geom_bottleneck/tests/data/test_860_B b/bottleneck/tests/data/test_860_B index 36f7915..36f7915 100644 --- a/geom_bottleneck/tests/data/test_860_B +++ b/bottleneck/tests/data/test_860_B diff --git a/geom_bottleneck/tests/data/test_861_A b/bottleneck/tests/data/test_861_A index 1058733..1058733 100644 --- a/geom_bottleneck/tests/data/test_861_A +++ b/bottleneck/tests/data/test_861_A diff --git a/geom_bottleneck/tests/data/test_861_B b/bottleneck/tests/data/test_861_B index a6a11d7..a6a11d7 100644 --- a/geom_bottleneck/tests/data/test_861_B +++ b/bottleneck/tests/data/test_861_B diff --git a/geom_bottleneck/tests/data/test_862_A b/bottleneck/tests/data/test_862_A index d37d3ef..d37d3ef 100644 --- a/geom_bottleneck/tests/data/test_862_A +++ b/bottleneck/tests/data/test_862_A diff --git a/geom_bottleneck/tests/data/test_862_B b/bottleneck/tests/data/test_862_B index a18168e..a18168e 100644 --- a/geom_bottleneck/tests/data/test_862_B +++ b/bottleneck/tests/data/test_862_B diff --git a/geom_bottleneck/tests/data/test_863_A b/bottleneck/tests/data/test_863_A index 011d452..011d452 100644 --- a/geom_bottleneck/tests/data/test_863_A +++ b/bottleneck/tests/data/test_863_A diff --git a/geom_bottleneck/tests/data/test_863_B b/bottleneck/tests/data/test_863_B index d9daaae..d9daaae 100644 --- a/geom_bottleneck/tests/data/test_863_B +++ b/bottleneck/tests/data/test_863_B diff --git a/geom_bottleneck/tests/data/test_864_A b/bottleneck/tests/data/test_864_A index f82ed50..f82ed50 100644 --- a/geom_bottleneck/tests/data/test_864_A +++ b/bottleneck/tests/data/test_864_A diff --git a/geom_bottleneck/tests/data/test_864_B b/bottleneck/tests/data/test_864_B index 0b56a95..0b56a95 100644 --- a/geom_bottleneck/tests/data/test_864_B +++ b/bottleneck/tests/data/test_864_B diff --git a/geom_bottleneck/tests/data/test_865_A b/bottleneck/tests/data/test_865_A index 7453ead..7453ead 100644 --- a/geom_bottleneck/tests/data/test_865_A +++ b/bottleneck/tests/data/test_865_A diff --git a/geom_bottleneck/tests/data/test_865_B b/bottleneck/tests/data/test_865_B index 265e3bd..265e3bd 100644 --- a/geom_bottleneck/tests/data/test_865_B +++ b/bottleneck/tests/data/test_865_B diff --git a/geom_bottleneck/tests/data/test_866_A b/bottleneck/tests/data/test_866_A index a05ad71..a05ad71 100644 --- a/geom_bottleneck/tests/data/test_866_A +++ b/bottleneck/tests/data/test_866_A diff --git a/geom_bottleneck/tests/data/test_866_B b/bottleneck/tests/data/test_866_B index c3e0b3a..c3e0b3a 100644 --- a/geom_bottleneck/tests/data/test_866_B +++ b/bottleneck/tests/data/test_866_B diff --git a/geom_bottleneck/tests/data/test_867_A b/bottleneck/tests/data/test_867_A index 0e5ca13..0e5ca13 100644 --- a/geom_bottleneck/tests/data/test_867_A +++ b/bottleneck/tests/data/test_867_A diff --git a/geom_bottleneck/tests/data/test_867_B b/bottleneck/tests/data/test_867_B index c8eb5e0..c8eb5e0 100644 --- a/geom_bottleneck/tests/data/test_867_B +++ b/bottleneck/tests/data/test_867_B diff --git a/geom_bottleneck/tests/data/test_868_A b/bottleneck/tests/data/test_868_A index 0a0fad2..0a0fad2 100644 --- a/geom_bottleneck/tests/data/test_868_A +++ b/bottleneck/tests/data/test_868_A diff --git a/geom_bottleneck/tests/data/test_868_B b/bottleneck/tests/data/test_868_B index 00c87b2..00c87b2 100644 --- a/geom_bottleneck/tests/data/test_868_B +++ b/bottleneck/tests/data/test_868_B diff --git a/geom_bottleneck/tests/data/test_869_A b/bottleneck/tests/data/test_869_A index fa16527..fa16527 100644 --- a/geom_bottleneck/tests/data/test_869_A +++ b/bottleneck/tests/data/test_869_A diff --git a/geom_bottleneck/tests/data/test_869_B b/bottleneck/tests/data/test_869_B index 7ffd8c9..7ffd8c9 100644 --- a/geom_bottleneck/tests/data/test_869_B +++ b/bottleneck/tests/data/test_869_B diff --git a/geom_bottleneck/tests/data/test_870_A b/bottleneck/tests/data/test_870_A index 72422f7..72422f7 100644 --- a/geom_bottleneck/tests/data/test_870_A +++ b/bottleneck/tests/data/test_870_A diff --git a/geom_bottleneck/tests/data/test_870_B b/bottleneck/tests/data/test_870_B index db4847d..db4847d 100644 --- a/geom_bottleneck/tests/data/test_870_B +++ b/bottleneck/tests/data/test_870_B diff --git a/geom_bottleneck/tests/data/test_871_A b/bottleneck/tests/data/test_871_A index 08ce8b2..08ce8b2 100644 --- a/geom_bottleneck/tests/data/test_871_A +++ b/bottleneck/tests/data/test_871_A diff --git a/geom_bottleneck/tests/data/test_871_B b/bottleneck/tests/data/test_871_B index 23c1dd8..23c1dd8 100644 --- a/geom_bottleneck/tests/data/test_871_B +++ b/bottleneck/tests/data/test_871_B diff --git a/geom_bottleneck/tests/data/test_872_A b/bottleneck/tests/data/test_872_A index 9647bed..9647bed 100644 --- a/geom_bottleneck/tests/data/test_872_A +++ b/bottleneck/tests/data/test_872_A diff --git a/geom_bottleneck/tests/data/test_872_B b/bottleneck/tests/data/test_872_B index 1c58840..1c58840 100644 --- a/geom_bottleneck/tests/data/test_872_B +++ b/bottleneck/tests/data/test_872_B diff --git a/geom_bottleneck/tests/data/test_873_A b/bottleneck/tests/data/test_873_A index d9e1da9..d9e1da9 100644 --- a/geom_bottleneck/tests/data/test_873_A +++ b/bottleneck/tests/data/test_873_A diff --git a/geom_bottleneck/tests/data/test_873_B b/bottleneck/tests/data/test_873_B index a9f3ea1..a9f3ea1 100644 --- a/geom_bottleneck/tests/data/test_873_B +++ b/bottleneck/tests/data/test_873_B diff --git a/geom_bottleneck/tests/data/test_874_A b/bottleneck/tests/data/test_874_A index 4d66819..4d66819 100644 --- a/geom_bottleneck/tests/data/test_874_A +++ b/bottleneck/tests/data/test_874_A diff --git a/geom_bottleneck/tests/data/test_874_B b/bottleneck/tests/data/test_874_B index 2142cbc..2142cbc 100644 --- a/geom_bottleneck/tests/data/test_874_B +++ b/bottleneck/tests/data/test_874_B diff --git a/geom_bottleneck/tests/data/test_875_A b/bottleneck/tests/data/test_875_A index 1748357..1748357 100644 --- a/geom_bottleneck/tests/data/test_875_A +++ b/bottleneck/tests/data/test_875_A diff --git a/geom_bottleneck/tests/data/test_875_B b/bottleneck/tests/data/test_875_B index 3a5860e..3a5860e 100644 --- a/geom_bottleneck/tests/data/test_875_B +++ b/bottleneck/tests/data/test_875_B diff --git a/geom_bottleneck/tests/data/test_876_A b/bottleneck/tests/data/test_876_A index 1b65f8d..1b65f8d 100644 --- a/geom_bottleneck/tests/data/test_876_A +++ b/bottleneck/tests/data/test_876_A diff --git a/geom_bottleneck/tests/data/test_876_B b/bottleneck/tests/data/test_876_B index 62102e9..62102e9 100644 --- a/geom_bottleneck/tests/data/test_876_B +++ b/bottleneck/tests/data/test_876_B diff --git a/geom_bottleneck/tests/data/test_877_A b/bottleneck/tests/data/test_877_A index c60479b..c60479b 100644 --- a/geom_bottleneck/tests/data/test_877_A +++ b/bottleneck/tests/data/test_877_A diff --git a/geom_bottleneck/tests/data/test_877_B b/bottleneck/tests/data/test_877_B index 728311d..728311d 100644 --- a/geom_bottleneck/tests/data/test_877_B +++ b/bottleneck/tests/data/test_877_B diff --git a/geom_bottleneck/tests/data/test_878_A b/bottleneck/tests/data/test_878_A index c8d0724..c8d0724 100644 --- a/geom_bottleneck/tests/data/test_878_A +++ b/bottleneck/tests/data/test_878_A diff --git a/geom_bottleneck/tests/data/test_878_B b/bottleneck/tests/data/test_878_B index 32723ce..32723ce 100644 --- a/geom_bottleneck/tests/data/test_878_B +++ b/bottleneck/tests/data/test_878_B diff --git a/geom_bottleneck/tests/data/test_879_A b/bottleneck/tests/data/test_879_A index 7a92be6..7a92be6 100644 --- a/geom_bottleneck/tests/data/test_879_A +++ b/bottleneck/tests/data/test_879_A diff --git a/geom_bottleneck/tests/data/test_879_B b/bottleneck/tests/data/test_879_B index f4c4a36..f4c4a36 100644 --- a/geom_bottleneck/tests/data/test_879_B +++ b/bottleneck/tests/data/test_879_B diff --git a/geom_bottleneck/tests/data/test_list.txt b/bottleneck/tests/data/test_list.txt index 24b462a..24b462a 100644 --- a/geom_bottleneck/tests/data/test_list.txt +++ b/bottleneck/tests/data/test_list.txt diff --git a/geom_bottleneck/tests/data/test_list.txt.bak b/bottleneck/tests/data/test_list.txt.bak index 71b89ed..71b89ed 100644 --- a/geom_bottleneck/tests/data/test_list.txt.bak +++ b/bottleneck/tests/data/test_list.txt.bak diff --git a/geom_bottleneck/tests/data/ws_tests/test_100_A b/bottleneck/tests/data/ws_tests/test_100_A index 8d126f0..8d126f0 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_100_A +++ b/bottleneck/tests/data/ws_tests/test_100_A diff --git a/geom_bottleneck/tests/data/ws_tests/test_100_A.pd.dipha b/bottleneck/tests/data/ws_tests/test_100_A.pd.dipha Binary files differindex e94f5fe..e94f5fe 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_100_A.pd.dipha +++ b/bottleneck/tests/data/ws_tests/test_100_A.pd.dipha diff --git a/geom_bottleneck/tests/data/ws_tests/test_100_B b/bottleneck/tests/data/ws_tests/test_100_B index 852799d..852799d 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_100_B +++ b/bottleneck/tests/data/ws_tests/test_100_B diff --git a/geom_bottleneck/tests/data/ws_tests/test_100_B.pd.dipha b/bottleneck/tests/data/ws_tests/test_100_B.pd.dipha Binary files differindex 25d6734..25d6734 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_100_B.pd.dipha +++ b/bottleneck/tests/data/ws_tests/test_100_B.pd.dipha diff --git a/geom_bottleneck/tests/data/ws_tests/test_200_A b/bottleneck/tests/data/ws_tests/test_200_A index 164b71d..164b71d 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_200_A +++ b/bottleneck/tests/data/ws_tests/test_200_A diff --git a/geom_bottleneck/tests/data/ws_tests/test_200_B b/bottleneck/tests/data/ws_tests/test_200_B index 761943d..761943d 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_200_B +++ b/bottleneck/tests/data/ws_tests/test_200_B diff --git a/geom_bottleneck/tests/data/ws_tests/test_5000_A b/bottleneck/tests/data/ws_tests/test_5000_A index 094c6e0..094c6e0 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_5000_A +++ b/bottleneck/tests/data/ws_tests/test_5000_A diff --git a/geom_bottleneck/tests/data/ws_tests/test_5000_B b/bottleneck/tests/data/ws_tests/test_5000_B index 5f6e43c..5f6e43c 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_5000_B +++ b/bottleneck/tests/data/ws_tests/test_5000_B diff --git a/geom_bottleneck/tests/data/ws_tests/test_5_A b/bottleneck/tests/data/ws_tests/test_5_A index 51cff1c..51cff1c 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_5_A +++ b/bottleneck/tests/data/ws_tests/test_5_A diff --git a/geom_bottleneck/tests/data/ws_tests/test_5_A.pd.dipha b/bottleneck/tests/data/ws_tests/test_5_A.pd.dipha Binary files differindex be84441..be84441 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_5_A.pd.dipha +++ b/bottleneck/tests/data/ws_tests/test_5_A.pd.dipha diff --git a/geom_bottleneck/tests/data/ws_tests/test_5_B b/bottleneck/tests/data/ws_tests/test_5_B index be62ed3..be62ed3 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_5_B +++ b/bottleneck/tests/data/ws_tests/test_5_B diff --git a/geom_bottleneck/tests/data/ws_tests/test_5_B.pd.dipha b/bottleneck/tests/data/ws_tests/test_5_B.pd.dipha Binary files differindex 14ca67c..14ca67c 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_5_B.pd.dipha +++ b/bottleneck/tests/data/ws_tests/test_5_B.pd.dipha diff --git a/geom_bottleneck/tests/data/ws_tests/test_diag1_A b/bottleneck/tests/data/ws_tests/test_diag1_A index f7f90ff..f7f90ff 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_diag1_A +++ b/bottleneck/tests/data/ws_tests/test_diag1_A diff --git a/geom_bottleneck/tests/data/ws_tests/test_diag1_A.pd.dipha b/bottleneck/tests/data/ws_tests/test_diag1_A.pd.dipha Binary files differindex fa4a4d9..fa4a4d9 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_diag1_A.pd.dipha +++ b/bottleneck/tests/data/ws_tests/test_diag1_A.pd.dipha diff --git a/geom_bottleneck/tests/data/ws_tests/test_diag1_B b/bottleneck/tests/data/ws_tests/test_diag1_B index a167a4f..a167a4f 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_diag1_B +++ b/bottleneck/tests/data/ws_tests/test_diag1_B diff --git a/geom_bottleneck/tests/data/ws_tests/test_diag1_B.pd.dipha b/bottleneck/tests/data/ws_tests/test_diag1_B.pd.dipha Binary files differindex 621a55f..621a55f 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_diag1_B.pd.dipha +++ b/bottleneck/tests/data/ws_tests/test_diag1_B.pd.dipha diff --git a/geom_bottleneck/tests/data/ws_tests/test_diag2_A b/bottleneck/tests/data/ws_tests/test_diag2_A index a167a4f..a167a4f 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_diag2_A +++ b/bottleneck/tests/data/ws_tests/test_diag2_A diff --git a/geom_bottleneck/tests/data/ws_tests/test_diag2_A.pd.dipha b/bottleneck/tests/data/ws_tests/test_diag2_A.pd.dipha Binary files differindex 621a55f..621a55f 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_diag2_A.pd.dipha +++ b/bottleneck/tests/data/ws_tests/test_diag2_A.pd.dipha diff --git a/geom_bottleneck/tests/data/ws_tests/test_diag2_B b/bottleneck/tests/data/ws_tests/test_diag2_B index a167a4f..a167a4f 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_diag2_B +++ b/bottleneck/tests/data/ws_tests/test_diag2_B diff --git a/geom_bottleneck/tests/data/ws_tests/test_diag2_B.pd.dipha b/bottleneck/tests/data/ws_tests/test_diag2_B.pd.dipha Binary files differindex 621a55f..621a55f 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_diag2_B.pd.dipha +++ b/bottleneck/tests/data/ws_tests/test_diag2_B.pd.dipha diff --git a/geom_bottleneck/tests/data/ws_tests/test_diag3_A b/bottleneck/tests/data/ws_tests/test_diag3_A index 151d4b1..151d4b1 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_diag3_A +++ b/bottleneck/tests/data/ws_tests/test_diag3_A diff --git a/geom_bottleneck/tests/data/ws_tests/test_diag3_A.pd.dipha b/bottleneck/tests/data/ws_tests/test_diag3_A.pd.dipha Binary files differindex 0dbfb89..0dbfb89 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_diag3_A.pd.dipha +++ b/bottleneck/tests/data/ws_tests/test_diag3_A.pd.dipha diff --git a/geom_bottleneck/tests/data/ws_tests/test_diag3_B b/bottleneck/tests/data/ws_tests/test_diag3_B index bb8655a..bb8655a 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_diag3_B +++ b/bottleneck/tests/data/ws_tests/test_diag3_B diff --git a/geom_bottleneck/tests/data/ws_tests/test_diag3_B.pd.dipha b/bottleneck/tests/data/ws_tests/test_diag3_B.pd.dipha Binary files differindex 3fbfd90..3fbfd90 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_diag3_B.pd.dipha +++ b/bottleneck/tests/data/ws_tests/test_diag3_B.pd.dipha diff --git a/geom_bottleneck/tests/data/ws_tests/test_list.txt b/bottleneck/tests/data/ws_tests/test_list.txt index 27340d8..27340d8 100644 --- a/geom_bottleneck/tests/data/ws_tests/test_list.txt +++ b/bottleneck/tests/data/ws_tests/test_list.txt diff --git a/geom_bottleneck/tests/test_hera_bottleneck.cpp b/bottleneck/tests/test_hera_bottleneck.cpp index f22e415..f22e415 100644 --- a/geom_bottleneck/tests/test_hera_bottleneck.cpp +++ b/bottleneck/tests/test_hera_bottleneck.cpp diff --git a/geom_bottleneck/tests/tests_main.cpp b/bottleneck/tests/tests_main.cpp index d24407e..d24407e 100644 --- a/geom_bottleneck/tests/tests_main.cpp +++ b/bottleneck/tests/tests_main.cpp diff --git a/geom_matching/.gitignore b/geom_matching/.gitignore deleted file mode 100644 index d9458fb..0000000 --- a/geom_matching/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -/*.cfg -wasserstein/build/ -*.gitattributes -*.opensdf -*.sdf -*.suo -*.vcxproj -*.filters -*.log -*.tlog -*.lastbuildstate -*.obj -*.idb -*.pdb -*.exe -*.ilk -*.user -*.out -*.output -*.pyc -*.*~* -*.swp -*.nfs* -*.pdf -*.o -*.d -*.dll -*.lib -*.exe -makeout -tags diff --git a/matching/CMakeLists.txt b/matching/CMakeLists.txt new file mode 100644 index 0000000..a391d84 --- /dev/null +++ b/matching/CMakeLists.txt @@ -0,0 +1,56 @@ +project(matching_distance) +cmake_minimum_required(VERSION 3.5.1) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +include(GenerateExportHeader) +find_package(Boost REQUIRED) + +# Default to Release + +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif (NOT CMAKE_BUILD_TYPE) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include + SYSTEM ${BOOST_INCLUDE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../bottleneck/include) + +set(CMAKE_CXX_STANDARD 14) + + +if (NOT WIN32) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS} -Wall -Wextra ") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -ggdb -D_GLIBCXX_DEBUG") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} -O2 -g -ggdb") +endif (NOT WIN32) + +file(GLOB BT_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/../bottleneck/include/*.h ${CMAKE_CURRENT_SOURCE_DIR}/../bottleneck/include/*.hpp) +file(GLOB MD_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h ${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp) + +file(GLOB SRC_TEST_FILES ${CMAKE_CURRENT_SOURCE_DIR}/tests/*.cpp) + +find_package(Threads) +set(libraries ${libraries} "stdc++fs" ${CMAKE_THREAD_LIBS_INIT}) + + +find_package(OpenMP) +if (OPENMP_FOUND) + set(libraries ${libraries} ${OpenMP_CXX_LIBRARIES}) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") +endif() + + +add_executable(matching_dist "example/matching_dist.cpp" ${MD_HEADERS} ${BT_HEADERS} ) +target_link_libraries(matching_dist PUBLIC ${libraries}) + +add_executable(module_example "example/module_example.cpp" ${MD_HEADERS} ${BT_HEADERS} ) +target_link_libraries(module_example PUBLIC ${libraries}) + + +add_executable(matching_distance_test ${SRC_TEST_FILES} ${BT_HEADERS} ${MD_HEADERS}) +target_link_libraries(matching_distance_test PUBLIC ${libraries}) diff --git a/matching/README.md b/matching/README.md new file mode 100644 index 0000000..fc97441 --- /dev/null +++ b/matching/README.md @@ -0,0 +1,69 @@ +# Matching distance between bifiltrations and 2-persistence modules. + +## Accompanying paper +M. Kerber, A. Nigmetov, +Efficient Approximation of the Matching Distance for 2-parameter persistence. +SoCG 2020. + +Bug reports can be sent to "anigmetov EMAIL SIGN lbl DOT gov". + +## Dependencies + +* Your compiler must support C++11. +* Boost. + +## Usage: + +1. To use a standalone command-line utility matching_dist: + +`./matching_dist -d dimension -e relative_error file1 file2` + +If `relative_error` is not specified, the default 0.1 is used. +If `dimension` is not specified, the default value is 0. +Run `./matching_dist` without parameters to see other options. + +The output is an approximation of the exact distance (which is assumed to be non-zero). +Precisely: if *d_exact* is the true distance and *d_approx* is the output, then + +> | d_exact - d_approx | / d_exact < relative_error. + +Files file1 and file2 must contain 1-critical bi-filtrations in a plain text format which is similar to PHAT. The first line of a file must say *bifiltration_phat_like*. The second line contains the total number of simplices *N*. The next *N* lines contain simplices in the format *dim x y boundary*. +* *dim*: the dimension of the simplex +* *x, y*: coordinates of the critical value +* *boundary*: indices of simplices forming the boundary of the current simplex. Indices are separated by space. +* Simplices are indexed starting from 0. + +For example, the bi-filtration of a segment with vertices appearing at (0,0) and the 1-segment appearing at (3,4) shall be written as: + +> bifiltration_phat_like +> 3 +> \# lines starting with \# are ignored +> \# vertex A has dimension 0, hence no boundary, its index is 0 +> 0 0 0 +> \# vertex B has index 1 +> 0 0 0 +> \# 1-dimensional simplex {A, B} +> 1 3 4 0 1 + +2. To use from your code. + +Here you can compute the matching distance either between bi-filtrations or between persistence modules. +First, you need to include `#include "matching_distance.h"` Practically every class you need is parameterized by Real type, which should be either float or double. The header provides two functions called `matching_distance.` +See `example/module_example.cpp` for additional details. + +## License + +See `licence.txt` in the repository root folder. + +## Building + +CMakeLists.txt can be used to build the command-line utility in the standard +way. On Linux/Mac/Windows with Cygwin: +> `mkdir build` +> `cd build` +> `cmake ..` +> `make` + +On Windows with Visual Studio: use `cmake-gui` to create the solution in build directory and build it with VS. + +The library itself is header-only and does not require separate compilation. diff --git a/matching/example/matching_dist.cpp b/matching/example/matching_dist.cpp new file mode 100644 index 0000000..734f6cc --- /dev/null +++ b/matching/example/matching_dist.cpp @@ -0,0 +1,393 @@ +#include "common_defs.h"
+
+#include <iostream>
+#include <string>
+#include <cassert>
+#include <experimental/filesystem>
+
+#ifdef MD_EXPERIMENTAL_TIMING
+#include <chrono>
+#endif
+
+#include "opts/opts.h"
+#include "spdlog/spdlog.h"
+#include "spdlog/fmt/ostr.h"
+
+#include "matching_distance.h"
+
+using Real = double;
+
+using namespace md;
+
+namespace fs = std::experimental::filesystem;
+
+#ifdef PRINT_HEAT_MAP
+void print_heat_map(const md::HeatMaps<Real>& hms, std::string fname, const CalculationParams<Real>& params)
+{
+ spd::debug("Entered print_heat_map");
+ std::set<Real> mu_vals, lambda_vals;
+ auto hm_iter = hms.end();
+ --hm_iter;
+ int max_level = hm_iter->first;
+
+ int level_cardinality = 4;
+ for(int i = 0; i < params.initialization_depth; ++i) {
+ level_cardinality *= 4;
+ }
+ for(int i = params.initialization_depth + 1; i <= max_level; ++i) {
+ spd::debug("hms.at({}).size = {}, must be {}", i, hms.at(i).size(), level_cardinality);
+ assert(static_cast<decltype(level_cardinality)>(hms.at(i).size()) == level_cardinality);
+ level_cardinality *= 4;
+ }
+
+ std::map<std::pair<Real, Real>, Real> hm_x_flat, hm_x_steep, hm_y_flat, hm_y_steep;
+
+ for(const auto& dual_point_value_pair : hms.at(max_level)) {
+ const DualPoint& k = dual_point_value_pair.first;
+ spd::debug("HM DP: {}", k);
+ mu_vals.insert(k.mu());
+ lambda_vals.insert(k.lambda());
+ }
+
+ std::vector<Real> lambda_vals_vec(lambda_vals.begin(), lambda_vals.end());
+ std::vector<Real> mu_vals_vec(mu_vals.begin(), mu_vals.end());
+
+ std::ofstream ofs {fname};
+ if (not ofs.good()) {
+ std::cerr << "Cannot write heat map to file " << fname << std::endl;
+ throw std::runtime_error("Cannot open file for writing heat map");
+ }
+
+ std::vector<std::vector<Real>> heatmap_to_print(2 * mu_vals_vec.size(),
+ std::vector<Real>(2 * lambda_vals_vec.size(), 0.0));
+
+ for(auto axis_type : {AxisType::x_type, AxisType::y_type}) {
+ bool is_x_type = axis_type == AxisType::x_type;
+ for(auto angle_type : {AngleType::flat, AngleType::steep}) {
+ bool is_flat = angle_type == AngleType::flat;
+
+ int mu_idx_begin, mu_idx_end;
+
+ if (is_x_type) {
+ mu_idx_begin = mu_vals_vec.size() - 1;
+ mu_idx_end = -1;
+ } else {
+ mu_idx_begin = 0;
+ mu_idx_end = mu_vals_vec.size();
+ }
+
+ int lambda_idx_begin, lambda_idx_end;
+
+ if (is_flat) {
+ lambda_idx_begin = 0;
+ lambda_idx_end = lambda_vals_vec.size();
+ } else {
+ lambda_idx_begin = lambda_vals_vec.size() - 1;
+ lambda_idx_end = -1;
+ }
+
+ int mu_idx_final = is_x_type ? 0 : mu_vals_vec.size();
+
+ for(int mu_idx = mu_idx_begin; mu_idx != mu_idx_end; (mu_idx_begin < mu_idx_end) ? mu_idx++ : mu_idx--) {
+ Real mu = mu_vals_vec.at(mu_idx);
+
+ if (mu == 0.0 and axis_type == AxisType::x_type)
+ continue;
+
+ int lambda_idx_final = is_flat ? 0 : lambda_vals_vec.size();
+
+ for(int lambda_idx = lambda_idx_begin;
+ lambda_idx != lambda_idx_end;
+ (lambda_idx_begin < lambda_idx_end) ? lambda_idx++ : lambda_idx--) {
+
+ Real lambda = lambda_vals_vec.at(lambda_idx);
+
+ if (lambda == 0.0 and angle_type == AngleType::flat)
+ continue;
+
+ DualPoint dp(axis_type, angle_type, lambda, mu);
+ Real dist_value = hms.at(max_level).at(dp);
+
+ heatmap_to_print.at(mu_idx_final).at(lambda_idx_final) = dist_value;
+
+// fmt::print("HM, dp = {}, mu_idx_final = {}, lambda_idx_final = {}, value = {}\n", dp, mu_idx_final,
+// lambda_idx_final, dist_value);
+
+ lambda_idx_final++;
+ }
+ mu_idx_final++;
+ }
+ }
+ }
+
+ for(size_t m_idx = 0; m_idx < heatmap_to_print.size(); ++m_idx) {
+ for(size_t l_idx = 0; l_idx < heatmap_to_print.at(m_idx).size(); ++l_idx) {
+ ofs << heatmap_to_print.at(m_idx).at(l_idx) << " ";
+ }
+ ofs << std::endl;
+ }
+
+ ofs.close();
+ spd::debug("Exit print_heat_map");
+}
+#endif
+
+int main(int argc, char** argv)
+{
+ spdlog::set_level(spdlog::level::info);
+
+ using opts::Option;
+ using opts::PosOption;
+ opts::Options ops;
+
+ CalculationParams<Real> params;
+
+ bool help = false;
+
+#ifdef MD_EXPERIMENTAL_TIMING
+ bool no_stop_asap = false;
+#endif
+
+
+#ifdef PRINT_HEAT_MAP
+ bool heatmap_only = false;
+#endif
+
+ // default values are the best for practical use
+ // if compiled with MD_EXPERIMENTAL_TIMING, user can supply
+ // different bounds and traverse strategies
+ // separated by commas, all combinations will be timed.
+ // See corresponding >> operators in matching_distance.h
+ // for possible values.
+ std::string bounds_list_str = "local_combined";
+ std::string traverse_list_str = "BFS";
+
+ ops >> Option('m', "max-iterations", params.max_depth, "maximal number of iterations (refinements)")
+ >> Option('e', "max-error", params.delta, "error threshold")
+ >> Option('d', "dim", params.dim, "dim")
+ >> Option('i', "initial-depth", params.initialization_depth, "initialization depth")
+#ifdef MD_EXPERIMENTAL_TIMING
+ >> Option("no-stop-asap", no_stop_asap,
+ "don't stop looping over points, if cell cannot be pruned (asap is on by default)")
+ >> Option("bounds", bounds_list_str, "bounds to use, separated by ,")
+ >> Option("traverse", traverse_list_str, "traverse strategy to use, separated by ,")
+#endif
+#ifdef PRINT_HEAT_MAP
+ >> Option("heatmap-only", heatmap_only, "only save heatmap (bruteforce)")
+#endif
+ >> Option('h', "help", help, "show help message");
+
+ std::string fname_a;
+ std::string fname_b;
+
+ if (!ops.parse(argc, argv) || help || !(ops >> PosOption(fname_a) >> PosOption(fname_b))) {
+ std::cerr << "Usage: " << argv[0] << " bifiltration-file-1 bifiltration-file-2\n" << ops << std::endl;
+ return 1;
+ }
+
+#ifdef MD_EXPERIMENTAL_TIMING
+ params.stop_asap = not no_stop_asap;
+#else
+ params.stop_asap = true;
+#endif
+
+ auto bounds_list = split_by_delim(bounds_list_str, ',');
+ auto traverse_list = split_by_delim(traverse_list_str, ',');
+
+ Bifiltration<Real> bif_a(fname_a);
+ Bifiltration<Real> bif_b(fname_b);
+
+ bif_a.sanity_check();
+ bif_b.sanity_check();
+
+ spd::debug("Read bifiltrations {} {}", fname_a, fname_b);
+
+ std::vector<BoundStrategy> bound_strategies;
+ std::vector<TraverseStrategy> traverse_strategies;
+
+ for(std::string s : bounds_list) {
+ bound_strategies.push_back(bs_from_string(s));
+ }
+
+ for(std::string s : traverse_list) {
+ traverse_strategies.push_back(ts_from_string(s));
+ }
+
+
+#ifdef MD_EXPERIMENTAL_TIMING
+
+ for(auto bs : bound_strategies) {
+ for(auto ts : traverse_strategies) {
+ spd::info("Will test combination {} {}", bs, ts);
+ }
+ }
+
+ struct ExperimentResult {
+ CalculationParams<Real> params {CalculationParams<Real>()};
+ int n_hera_calls {0};
+ double total_milliseconds_elapsed {0};
+ Real distance {0};
+ Real actual_error {std::numeric_limits<double>::max()};
+ int actual_max_depth {0};
+
+ int x_wins {0};
+ int y_wins {0};
+ int ad_wins {0};
+
+ int seconds_elapsed() const
+ {
+ return static_cast<int>(total_milliseconds_elapsed / 1000);
+ }
+
+ double savings_ratio_old() const
+ {
+ long int max_possible_calls = 0;
+ long int calls_on_level = 4;
+ for(int i = 0; i <= actual_max_depth; ++i) {
+ max_possible_calls += calls_on_level;
+ calls_on_level *= 4;
+ }
+ return static_cast<double>(n_hera_calls) / static_cast<double>(max_possible_calls);
+ }
+
+ double savings_ratio() const
+ {
+ return static_cast<double>(n_hera_calls) / calls_on_actual_max_depth();
+ }
+
+ long long int calls_on_actual_max_depth() const
+ {
+ long long int result = 1;
+ for(int i = 0; i < actual_max_depth; ++i) {
+ result *= 4;
+ }
+ return result;
+ }
+
+ ExperimentResult() { }
+
+ ExperimentResult(CalculationParams<Real> p, int nhc, double tme, double d)
+ :
+ params(p), n_hera_calls(nhc), total_milliseconds_elapsed(tme), distance(d) { }
+ };
+
+ const int n_repetitions = 1;
+
+#ifdef PRINT_HEAT_MAP
+ if (heatmap_only) {
+ bound_strategies.clear();
+ bound_strategies.push_back(BoundStrategy::bruteforce);
+ traverse_strategies.clear();
+ traverse_strategies.push_back(TraverseStrategy::breadth_first);
+ }
+#endif
+
+ std::map<std::tuple<BoundStrategy, TraverseStrategy>, ExperimentResult> results;
+ for(BoundStrategy bound_strategy : bound_strategies) {
+ for(TraverseStrategy traverse_strategy : traverse_strategies) {
+ CalculationParams<Real> params_experiment;
+ params_experiment.bound_strategy = bound_strategy;
+ params_experiment.traverse_strategy = traverse_strategy;
+ params_experiment.max_depth = params.max_depth;
+ params_experiment.initialization_depth = params.initialization_depth;
+ params_experiment.delta = params.delta;
+ params_experiment.dim = params.dim;
+ params_experiment.hera_epsilon = params.hera_epsilon;
+ params_experiment.stop_asap = params.stop_asap;
+
+ if (traverse_strategy == TraverseStrategy::depth_first and bound_strategy == BoundStrategy::bruteforce)
+ continue;
+
+ // if bruteforce, clamp max iterations number to 7,
+ // save user-provided max_iters in user_max_iters and restore it later.
+ // remember: params is passed by reference to return real relative error and heat map
+
+ int user_max_iters = params.max_depth;
+#ifdef PRINT_HEAT_MAP
+ if (bound_strategy == BoundStrategy::bruteforce and not heatmap_only) {
+ params_experiment.max_depth = std::min(7, params.max_depth);
+ }
+#endif
+ double total_milliseconds_elapsed = 0;
+ int total_n_hera_calls = 0;
+ Real dist;
+ for(int i = 0; i < n_repetitions; ++i) {
+ spd::debug("Processing bound_strategy {}, traverse_strategy {}, iteration = {}", bound_strategy,
+ traverse_strategy, i);
+ auto t1 = std::chrono::high_resolution_clock().now();
+ dist = matching_distance(bif_a, bif_b, params_experiment);
+ auto t2 = std::chrono::high_resolution_clock().now();
+ total_milliseconds_elapsed += std::chrono::duration_cast<std::chrono::milliseconds>(
+ t2 - t1).count();
+ total_n_hera_calls += params_experiment.n_hera_calls;
+ }
+
+ auto key = std::make_tuple(bound_strategy, traverse_strategy);
+ results[key].params = params_experiment;
+ results[key].n_hera_calls = total_n_hera_calls / n_repetitions;
+ results[key].total_milliseconds_elapsed = total_milliseconds_elapsed / n_repetitions;
+ results[key].distance = dist;
+ results[key].actual_error = params_experiment.actual_error;
+ results[key].actual_max_depth = params_experiment.actual_max_depth;
+
+ spd::info(
+ "Done (bound = {}, traverse = {}), n_hera_calls = {}, time = {} sec, d = {}, error = {}, savings = {}, max_depth = {}",
+ bound_strategy, traverse_strategy, results[key].n_hera_calls, results[key].seconds_elapsed(),
+ dist,
+ params_experiment.actual_error, results[key].savings_ratio(), results[key].actual_max_depth);
+
+ if (bound_strategy == BoundStrategy::bruteforce) { params_experiment.max_depth = user_max_iters; }
+
+#ifdef PRINT_HEAT_MAP
+ if (bound_strategy == BoundStrategy::bruteforce) {
+ fs::path fname_a_path {fname_a.c_str()};
+ fs::path fname_b_path {fname_b.c_str()};
+ fs::path fname_a_wo = fname_a_path.filename();
+ fs::path fname_b_wo = fname_b_path.filename();
+ std::string heat_map_fname = fmt::format("{0}_{1}_dim_{2}_weighted_values_xyp.txt", fname_a_wo.string(),
+ fname_b_wo.string(), params_experiment.dim);
+ fs::path path_hm = fname_a_path.replace_filename(fs::path(heat_map_fname.c_str()));
+ spd::debug("Saving heatmap to {}", heat_map_fname);
+ print_heat_map(params_experiment.heat_maps, path_hm.string(), params);
+ }
+#endif
+ spd::debug("Finished processing bound_strategy {}", bound_strategy);
+ }
+ }
+
+// std::cout << "File_1;File_2;Boundstrategy;TraverseStrategy;InitalDepth;NHeraCalls;SavingsRatio;Time;Distance;Error;PushStrategy;MaxDepth;CallsOnMaxDepth;Delta;Dimension" << std::endl;
+ for(auto bs : bound_strategies) {
+ for(auto ts : traverse_strategies) {
+ auto key = std::make_tuple(bs, ts);
+
+ fs::path fname_a_path {fname_a.c_str()};
+ fs::path fname_b_path {fname_b.c_str()};
+ fs::path fname_a_wo = fname_a_path.filename();
+ fs::path fname_b_wo = fname_b_path.filename();
+
+ std::cout << fname_a_wo.string() << ";" << fname_b_wo.string() << ";" << bs << ";" << ts << ";";
+ std::cout << results[key].params.initialization_depth << ";";
+ std::cout << results[key].n_hera_calls << ";"
+ << results[key].savings_ratio() << ";"
+ << results[key].total_milliseconds_elapsed << ";"
+ << results[key].distance << ";"
+ << results[key].actual_error << ";"
+ << "xyp" << ";"
+ << results[key].actual_max_depth << ";"
+ << results[key].calls_on_actual_max_depth() << ";"
+ << params.delta << ";"
+ << params.dim
+ << std::endl;
+ }
+ }
+#else
+ params.bound_strategy = bound_strategies.back();
+ params.traverse_strategy = traverse_strategies.back();
+
+ spd::debug("Will use {} bound, {} traverse strategy", params.bound_strategy, params.traverse_strategy);
+
+ Real dist = matching_distance<Real>(bif_a, bif_b, params);
+ std::cout << dist << std::endl;
+#endif
+ return 0;
+}
diff --git a/matching/example/module_example.cpp b/matching/example/module_example.cpp new file mode 100644 index 0000000..c160c21 --- /dev/null +++ b/matching/example/module_example.cpp @@ -0,0 +1,68 @@ +#include <iostream> +#include "matching_distance.h" + +using namespace md; + +int main(int argc, char** argv) +{ + // create generators. + // A generator is a point in plane, + // generators are stored in a vector of points: + PointVec<double> gens_a; + + // module A will have one generator that appears at point (0, 0) + gens_a.emplace_back(0, 0); + + // relations are stored in a vector of relations + using RelationVec = ModulePresentation<double>::RelVec; + RelationVec rels_a; + + // A relation is a struct with position and column + using Relation = ModulePresentation<double>::Relation; + + // at this point the relation rel_a_1 will appear: + Point<double> rel_a_1_position { 1, 1 }; + + // vector IndexVec contains non-zero indices of the corresponding relation + // (we work over Z/2). Since we have one generator only, the relation + // contains only one entry, 0 + IndexVec rel_a_1_components { 0 }; + + // construct a relation from position and column: + Relation rel_a_1 { rel_a_1_position, rel_a_1_components }; + + // and add it to a vector of relations + rels_a.push_back(rel_a_1); + + // after populating vectors of generators and relations + // construct a module: + ModulePresentation<double> module_a { gens_a, rels_a }; + + + // same for module_b. It will also have just one + // generator and one relation, but at different positions. + + PointVec<double> gens_b; + gens_b.emplace_back(1, 1); + + RelationVec rels_b; + + Point<double> rel_b_1_position { 2, 2 }; + IndexVec rel_b_1_components { 0 }; + + rels_b.emplace_back(rel_b_1_position, rel_b_1_components); + + ModulePresentation<double> module_b { gens_b, rels_b }; + + // create CalculationParams + CalculationParams<double> params; + // set relative error to 10 % : + params.delta = 0.1; + // go at most 8 levels deep in quadtree: + params.max_depth = 8; + + double dist = matching_distance(module_a, module_b, params); + std::cout << "dist = " << dist << std::endl; + + return 0; +} diff --git a/matching/include/bifiltration.h b/matching/include/bifiltration.h new file mode 100644 index 0000000..4dd8662 --- /dev/null +++ b/matching/include/bifiltration.h @@ -0,0 +1,140 @@ +#ifndef MATCHING_DISTANCE_BIFILTRATION_H +#define MATCHING_DISTANCE_BIFILTRATION_H + +#include <string> +#include <ostream> +#include <iostream> +#include <fstream> +#include <sstream> +#include <cassert> + +#include "common_util.h" +#include "box.h" +#include "simplex.h" +#include "dual_point.h" +#include "phat/boundary_matrix.h" +#include "phat/compute_persistence_pairs.h" + +#include "spdlog/spdlog.h" +#include "spdlog/fmt/fmt.h" +#include "spdlog/fmt/ostr.h" + +#include "common_util.h" + +namespace md { + + template<class Real> + class Bifiltration { + public: + using SimplexVector = std::vector<Simplex<Real>>; + + Bifiltration() = default; + + Bifiltration(const Bifiltration&) = default; + + Bifiltration(Bifiltration&&) = default; + + Bifiltration& operator=(const Bifiltration& other)& = default; + + Bifiltration& operator=(Bifiltration&& other) = default; + + Bifiltration(const std::string& fname); // read from file + + template<class Iter> + Bifiltration(Iter begin, Iter end) + : simplices_(begin, end) + { + init(); + } + + Diagram<Real> weighted_slice_diagram(const DualPoint<Real>& line, int dim) const; + + SimplexVector simplices() const { return simplices_; } + + // translate all points by vector (a,a) + void translate(Real a); + + // return minimal value of x- and y-coordinates + // among all simplices + Real minimal_coordinate() const; + + // return box that contains positions of all simplices + Box<Real> bounding_box() const; + + void sanity_check() const; + + int maximal_dim() const { return maximal_dim_; } + + Real max_x() const; + + Real max_y() const; + + Real min_x() const; + + Real min_y() const; + + void add_simplex(Index _id, Point<Real> birth, int _dim, const Column& _bdry); + + void save(const std::string& filename, BifiltrationFormat format = BifiltrationFormat::rivet); // save to file + + void scale(Real lambda); + + private: + SimplexVector simplices_; + + Box<Real> bounding_box_; + int maximal_dim_ {-1}; + + void init(); + + void rivet_format_reader(std::ifstream&); + + void phat_like_format_reader(std::ifstream&); + + // in Rene format each simplex knows IDs of its boundary facets + // postprocess_phat_like_format fills vector of IDs of boundary facets + // in each simplex + void postprocess_phat_like_format(); + + // in Rivet format each simplex knows its vertices, + // postprocess_rivet_format fills vector of IDs of boundary facets + // in each simplex + void postprocess_rivet_format(); + + }; + + template<class Real> + std::ostream& operator<<(std::ostream& os, const Bifiltration<Real>& bif); + + template<class Real> + class BifiltrationProxy { + public: + BifiltrationProxy(const Bifiltration<Real>& bif, int dim = 0); + // return critical values of simplices that are important for current dimension (dim and dim+1) + PointVec<Real> positions() const; + // set current dimension + int set_dim(int new_dim); + + // wrappers of Bifiltration + int maximal_dim() const; + void translate(Real a); + Real minimal_coordinate() const; + Box<Real> bounding_box() const; + Real max_x() const; + Real max_y() const; + Real min_x() const; + Real min_y() const; + Diagram<Real> weighted_slice_diagram(const DualPoint<Real>& slice) const; + + private: + int dim_ { 0 }; + mutable PointVec<Real> cached_positions_; + Bifiltration<Real> bif_; + + void cache_positions() const; + }; +} + +#include "bifiltration.hpp" + +#endif //MATCHING_DISTANCE_BIFILTRATION_H diff --git a/matching/include/bifiltration.hpp b/matching/include/bifiltration.hpp new file mode 100644 index 0000000..9e2a82e --- /dev/null +++ b/matching/include/bifiltration.hpp @@ -0,0 +1,421 @@ +namespace md { + + template<class Real> + void Bifiltration<Real>::init() + { + auto lower_left = max_point<Real>(); + auto upper_right = min_point<Real>(); + for(const auto& simplex : simplices_) { + lower_left = greatest_lower_bound<>(lower_left, simplex.position()); + upper_right = least_upper_bound<>(upper_right, simplex.position()); + maximal_dim_ = std::max(maximal_dim_, simplex.dim()); + } + bounding_box_ = Box<Real>(lower_left, upper_right); + } + + template<class Real> + Bifiltration<Real>::Bifiltration(const std::string& fname) + { + std::ifstream ifstr {fname.c_str()}; + if (!ifstr.good()) { + std::string error_message = fmt::format("Cannot open file {0}", fname); + std::cerr << error_message << std::endl; + throw std::runtime_error(error_message); + } + + BifiltrationFormat input_format; + + std::string s; + + while(ignore_line(s)) { + std::getline(ifstr, s); + } + + if (s == "bifiltration") { + input_format = BifiltrationFormat::rivet; + } else if (s == "bifiltration_phat_like") { + input_format = BifiltrationFormat::phat_like; + } else { + std::cerr << "Unknown format: '" << s << "' in file " << fname << std::endl; + throw std::runtime_error("unknown bifiltration format"); + } + + switch(input_format) { + case BifiltrationFormat::rivet : + rivet_format_reader(ifstr); + break; + case BifiltrationFormat::phat_like : + phat_like_format_reader(ifstr); + break; + } + + ifstr.close(); + + init(); + } + + template<class Real> + void Bifiltration<Real>::rivet_format_reader(std::ifstream& ifstr) + { + std::string s; + // read axes names, ignore them + std::getline(ifstr, s); + std::getline(ifstr, s); + + Index index = 0; + while(std::getline(ifstr, s)) { + if (!ignore_line(s)) { + simplices_.emplace_back(index++, s, BifiltrationFormat::rivet); + } + } + } + + template<class Real> + void Bifiltration<Real>::phat_like_format_reader(std::ifstream& ifstr) + { + spd::debug("Enter phat_like_format_reader"); + // read stream line by line; do not use >> operator + std::string s; + std::getline(ifstr, s); + + // first line contains number of simplices + long n_simplices = std::stol(s); + + // all other lines represent a simplex + Index index = 0; + while(index < n_simplices) { + std::getline(ifstr, s); + if (!ignore_line(s)) { + simplices_.emplace_back(index++, s, BifiltrationFormat::phat_like); + } + } + spd::debug("Read {} simplices from file", n_simplices); + } + + template<class Real> + void Bifiltration<Real>::scale(Real lambda) + { + for(auto& s : simplices_) { + s.scale(lambda); + } + init(); + } + + template<class Real> + void Bifiltration<Real>::sanity_check() const + { +#ifdef DEBUG + spd::debug("Enter Bifiltration<Real>::sanity_check"); + // check that boundary has correct number of simplices, + // each bounding simplex has correct dim + // and appears in the filtration before the simplex it bounds + for(const auto& s : simplices_) { + assert(s.dim() >= 0); + assert(s.dim() == 0 or s.dim() + 1 == (int) s.boundary().size()); + for(auto bdry_idx : s.boundary()) { + Simplex bdry_simplex = simplices()[bdry_idx]; + assert(bdry_simplex.dim() == s.dim() - 1); + assert(bdry_simplex.position().is_less(s.position(), false)); + } + } + spd::debug("Exit Bifiltration<Real>::sanity_check"); +#endif + } + + template<class Real> + Diagram<Real> Bifiltration<Real>::weighted_slice_diagram(const DualPoint<Real>& line, int dim) const + { + DiagramKeeper<Real> dgm; + + // make a copy for now; I want slice_diagram to be const + std::vector<Simplex<Real>> simplices(simplices_); + +// std::vector<Simplex> simplices; +// simplices.reserve(simplices_.size() / 2); +// for(const auto& s : simplices_) { +// if (s.dim() <= dim + 1 and s.dim() >= dim) +// simplices.emplace_back(s); +// } + + spd::debug("Enter slice diagram, line = {}, simplices.size = {}", line, simplices.size()); + + for(auto& simplex : simplices) { + Real value = line.weighted_push(simplex.position()); +// spd::debug("in slice_diagram, simplex = {}, value = {}\n", simplex, value); + simplex.set_value(value); + } + + std::sort(simplices.begin(), simplices.end(), + [](const Simplex<Real>& a, const Simplex<Real>& b) { return a.value() < b.value(); }); + std::map<Index, Index> index_map; + for(Index i = 0; i < (int) simplices.size(); i++) { + index_map[simplices[i].id()] = i; + } + + phat::boundary_matrix<> phat_matrix; + phat_matrix.set_num_cols(simplices.size()); + std::vector<Index> bd_in_slice_filtration; + for(Index i = 0; i < (int) simplices.size(); i++) { + phat_matrix.set_dim(i, simplices[i].dim()); + bd_in_slice_filtration.clear(); + //std::cout << "new col" << i << std::endl; + for(int j = 0; j < (int) simplices[i].boundary().size(); j++) { + // F[i] contains the indices of its facet wrt to the + // original filtration. We have to express it, however, + // wrt to the filtration along the slice. That is why + // we need the index_map + //std::cout << "Found " << F[i].bd[j] << ", returning " << index_map[F[i].bd[j]] << std::endl; + bd_in_slice_filtration.push_back(index_map[simplices[i].boundary()[j]]); + } + std::sort(bd_in_slice_filtration.begin(), bd_in_slice_filtration.end()); + phat_matrix.set_col(i, bd_in_slice_filtration); + } + phat::persistence_pairs phat_persistence_pairs; + phat::compute_persistence_pairs<phat::twist_reduction>(phat_persistence_pairs, phat_matrix); + + dgm.clear(); + constexpr Real real_inf = std::numeric_limits<Real>::infinity(); + for(long i = 0; i < (long) phat_persistence_pairs.get_num_pairs(); i++) { + std::pair<phat::index, phat::index> new_pair = phat_persistence_pairs.get_pair(i); + bool is_finite_pair = new_pair.second != phat::k_infinity_index; + Real birth = simplices.at(new_pair.first).value(); + Real death = is_finite_pair ? simplices.at(new_pair.second).value() : real_inf; + int dim = simplices[new_pair.first].dim(); + assert(dim + 1 == simplices[new_pair.second].dim()); + if (birth != death) { + dgm.add_point(dim, birth, death); + } + } + + spdlog::debug("Exiting slice_diagram, #dgm[0] = {}", dgm.get_diagram(0).size()); + + return dgm.get_diagram(dim); + } + + template<class Real> + Box<Real> Bifiltration<Real>::bounding_box() const + { + return bounding_box_; + } + + template<class Real> + Real Bifiltration<Real>::minimal_coordinate() const + { + return std::min(bounding_box_.lower_left().x, bounding_box_.lower_left().y); + } + + template<class Real> + void Bifiltration<Real>::translate(Real a) + { + bounding_box_.translate(a); + for(auto& simplex : simplices_) { + simplex.translate(a); + } + } + + template<class Real> + Real Bifiltration<Real>::max_x() const + { + if (simplices_.empty()) + return 1; + auto me = std::max_element(simplices_.cbegin(), simplices_.cend(), + [](const auto& s_a, const auto& s_b) { return s_a.position().x < s_b.position().x; }); + assert(me != simplices_.cend()); + return me->position().x; + } + + template<class Real> + Real Bifiltration<Real>::max_y() const + { + if (simplices_.empty()) + return 1; + auto me = std::max_element(simplices_.cbegin(), simplices_.cend(), + [](const auto& s_a, const auto& s_b) { return s_a.position().y < s_b.position().y; }); + assert(me != simplices_.cend()); + return me->position().y; + } + + template<class Real> + Real Bifiltration<Real>::min_x() const + { + if (simplices_.empty()) + return 0; + auto me = std::min_element(simplices_.cbegin(), simplices_.cend(), + [](const auto& s_a, const auto& s_b) { return s_a.position().x < s_b.position().x; }); + assert(me != simplices_.cend()); + return me->position().x; + } + + template<class Real> + Real Bifiltration<Real>::min_y() const + { + if (simplices_.empty()) + return 0; + auto me = std::min_element(simplices_.cbegin(), simplices_.cend(), + [](const auto& s_a, const auto& s_b) { return s_a.position().y < s_b.position().y; }); + assert(me != simplices_.cend()); + return me->position().y; + } + + template<class Real> + void Bifiltration<Real>::add_simplex(Index _id, Point<Real> birth, int _dim, const Column& _bdry) + { + simplices_.emplace_back(_id, birth, _dim, _bdry); + } + + template<class Real> + void Bifiltration<Real>::save(const std::string& filename, md::BifiltrationFormat format) + { + switch(format) { + case BifiltrationFormat::rivet: + throw std::runtime_error("Not implemented"); + break; + case BifiltrationFormat::phat_like: { + std::ofstream f(filename); + if (not f.good()) { + std::cerr << "Bifiltration::save: cannot open file " << filename << std::endl; + throw std::runtime_error("Cannot open file for writing "); + } + f << simplices_.size() << "\n"; + + for(const auto& s : simplices_) { + f << s.dim() << " " << s.position().x << " " << s.position().y << " "; + for(int b : s.boundary()) { + f << b << " "; + } + f << std::endl; + } + + } + break; + } + } + + template<class Real> + void Bifiltration<Real>::postprocess_rivet_format() + { + std::map<Column, Index> facets_to_ids; + + // fill the map + for(Index i = 0; i < (Index) simplices_.size(); ++i) { + assert(simplices_[i].id() == i); + facets_to_ids[simplices_[i].vertices_] = i; + } + +// for(const auto& s : simplices_) { +// facets_to_ids[s] = s.id(); +// } + + // main loop + for(auto& s : simplices_) { + assert(not s.vertices_.empty()); + assert(s.facet_indices_.empty()); + Column facet_indices; + for(Index i = 0; i <= s.dim(); ++i) { + Column facet; + for(Index j : s.vertices_) { + if (j != i) + facet.push_back(j); + } + auto facet_index = facets_to_ids.at(facet); + facet_indices.push_back(facet_index); + } + s.facet_indices_ = facet_indices; + } // loop over simplices + } + + template<class Real> + std::ostream& operator<<(std::ostream& os, const Bifiltration<Real>& bif) + { + os << "Bifiltration [" << std::endl; + for(const auto& s : bif.simplices()) { + os << s << std::endl; + } + os << "]" << std::endl; + return os; + } + + template<class Real> + BifiltrationProxy<Real>::BifiltrationProxy(const Bifiltration<Real>& bif, int dim) + : + dim_(dim), + bif_(bif) + { + cache_positions(); + } + + template<class Real> + void BifiltrationProxy<Real>::cache_positions() const + { + cached_positions_.clear(); + for(const auto& simplex : bif_.simplices()) { + if (simplex.dim() == dim_ or simplex.dim() == dim_ + 1) + cached_positions_.push_back(simplex.position()); + } + } + + template<class Real> + PointVec<Real> + BifiltrationProxy<Real>::positions() const + { + if (cached_positions_.empty()) { + cache_positions(); + } + return cached_positions_; + } + + // translate all points by vector (a,a) + template<class Real> + void BifiltrationProxy<Real>::translate(Real a) + { + bif_.translate(a); + } + + // return minimal value of x- and y-coordinates + // among all simplices + template<class Real> + Real BifiltrationProxy<Real>::minimal_coordinate() const + { + return bif_.minimal_coordinate(); + } + + // return box that contains positions of all simplices + template<class Real> + Box<Real> BifiltrationProxy<Real>::bounding_box() const + { + return bif_.bounding_box(); + } + + template<class Real> + Real BifiltrationProxy<Real>::max_x() const + { + return bif_.max_x(); + } + + template<class Real> + Real BifiltrationProxy<Real>::max_y() const + { + return bif_.max_y(); + } + + template<class Real> + Real BifiltrationProxy<Real>::min_x() const + { + return bif_.min_x(); + } + + template<class Real> + Real BifiltrationProxy<Real>::min_y() const + { + return bif_.min_y(); + } + + + template<class Real> + Diagram<Real> BifiltrationProxy<Real>::weighted_slice_diagram(const DualPoint<Real>& slice) const + { + return bif_.weighted_slice_diagram(slice, dim_); + } + +} + diff --git a/matching/include/box.h b/matching/include/box.h new file mode 100644 index 0000000..4243667 --- /dev/null +++ b/matching/include/box.h @@ -0,0 +1,59 @@ +#ifndef MATCHING_DISTANCE_BOX_H +#define MATCHING_DISTANCE_BOX_H + +#include <cassert> +#include <limits> + +#include "common_util.h" + +namespace md { + + template<class Real_> + struct Box { + public: + using Real = Real_; + private: + Point<Real> ll; + Point<Real> ur; + + public: + Box(Point<Real> ll = Point<Real>(), Point<Real> ur = Point<Real>()) + :ll(ll), ur(ur) + { + } + + Box(Point<Real> center, Real width, Real height) : + ll(Point<Real>(center.x - 0.5 * width, center.y - 0.5 * height)), + ur(Point<Real>(center.x + 0.5 * width, center.y + 0.5 * height)) + { + } + + + inline double width() const { return ur.x - ll.x; } + + inline double height() const { return ur.y - ll.y; } + + inline Point<Real> lower_left() const { return ll; } + inline Point<Real> upper_right() const { return ur; } + inline Point<Real> center() const { return Point<Real>((ll.x + ur.x) / 2, (ll.y + ur.y) / 2); } + + inline bool operator==(const Box& p) + { + return this->ll == p.ll && this->ur == p.ur; + } + + std::vector<Box> refine() const; + + std::vector<Point<Real>> corners() const; + + void translate(Real a); + }; + + template<class Real> + std::ostream& operator<<(std::ostream& os, const Box<Real>& box); + +} // namespace md + +#include "box.hpp" + +#endif //MATCHING_DISTANCE_BOX_H diff --git a/matching/include/box.hpp b/matching/include/box.hpp new file mode 100644 index 0000000..f551d84 --- /dev/null +++ b/matching/include/box.hpp @@ -0,0 +1,52 @@ +namespace md { + + template<class Real> + std::ostream& operator<<(std::ostream& os, const Box<Real>& box) + { + os << "Box(lower_left = " << box.lower_left() << ", upper_right = " << box.upper_right() << ")"; + return os; + } + + template<class Real> + void Box<Real>::translate(Real a) + { + ll.x += a; + ll.y += a; + ur.x += a; + ur.y += a; + } + + template<class Real> + std::vector<Box<Real>> Box<Real>::refine() const + { + std::vector<Box<Real>> result; + +// 1 | 2 +// 0 | 3 + + Point<Real> new_ll = lower_left(); + Point<Real> new_ur = center(); + result.emplace_back(new_ll, new_ur); + + new_ll.y = center().y; + new_ur.y = ur.y; + result.emplace_back(new_ll, new_ur); + + new_ll = center(); + new_ur = upper_right(); + result.emplace_back(new_ll, new_ur); + + new_ll.y = ll.y; + new_ur.y = center().y; + result.emplace_back(new_ll, new_ur); + + return result; + } + + template<class Real> + std::vector<Point<Real>> Box<Real>::corners() const + { + return {ll, Point<Real>(ll.x, ur.y), ur, Point<Real>(ur.x, ll.y)}; + }; + +} diff --git a/matching/include/catch/catch.hpp b/matching/include/catch/catch.hpp new file mode 100644 index 0000000..bdc2f74 --- /dev/null +++ b/matching/include/catch/catch.hpp @@ -0,0 +1,13359 @@ +/* + * Catch v2.3.0 + * Generated: 2018-07-23 10:09:14.936841 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2018 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +// start catch.hpp + + +#define CATCH_VERSION_MAJOR 2 +#define CATCH_VERSION_MINOR 3 +#define CATCH_VERSION_PATCH 0 + +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif + +// start catch_suppress_warnings.h + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" +# endif +#elif defined __GNUC__ + // GCC likes to warn on REQUIREs, and we cannot suppress them + // locally because g++'s support for _Pragma is lacking in older, + // still supported, versions +# pragma GCC diagnostic ignored "-Wparentheses" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic ignored "-Wpadded" +#endif +// end catch_suppress_warnings.h +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +# define CATCH_CONFIG_ALL_PARTS +#endif + +// In the impl file, we want to have access to all parts of the headers +// Can also be used to sanely support PCHs +#if defined(CATCH_CONFIG_ALL_PARTS) +# define CATCH_CONFIG_EXTERNAL_INTERFACES +# if defined(CATCH_CONFIG_DISABLE_MATCHERS) +# undef CATCH_CONFIG_DISABLE_MATCHERS +# endif +# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +# endif +#endif + +#if !defined(CATCH_CONFIG_IMPL_ONLY) +// start catch_platform.h + +#ifdef __APPLE__ +# include <TargetConditionals.h> +# if TARGET_OS_OSX == 1 +# define CATCH_PLATFORM_MAC +# elif TARGET_OS_IPHONE == 1 +# define CATCH_PLATFORM_IPHONE +# endif + +#elif defined(linux) || defined(__linux) || defined(__linux__) +# define CATCH_PLATFORM_LINUX + +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) +# define CATCH_PLATFORM_WINDOWS +#endif + +// end catch_platform.h + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// start catch_user_interfaces.h + +namespace Catch { + unsigned int rngSeed(); +} + +// end catch_user_interfaces.h +// start catch_tag_alias_autoregistrar.h + +// start catch_common.h + +// start catch_compiler_capabilities.h + +// Detect a number of compiler features - by compiler +// The following features are defined: +// +// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? +// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? +// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + +// In general each macro has a _NO_<feature name> form +// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +#ifdef __cplusplus + +# if __cplusplus >= 201402L +# define CATCH_CPP14_OR_GREATER +# endif + +# if __cplusplus >= 201703L +# define CATCH_CPP17_OR_GREATER +# endif + +#endif + +#if defined(CATCH_CPP17_OR_GREATER) +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +#ifdef __clang__ + +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic push" ) \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ + _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") +# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic pop" ) + +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic push" ) \ + _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) +# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic pop" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic push" ) \ + _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) +# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic pop" ) + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Assume that non-Windows platforms support posix signals by default +#if !defined(CATCH_PLATFORM_WINDOWS) + #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS +#endif + +//////////////////////////////////////////////////////////////////////////////// +// We know some environments not to support full POSIX signals +#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) + #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +#endif + +#ifdef __OS400__ +# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +# define CATCH_CONFIG_COLOUR_NONE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Android somehow still does not support std::to_string +#if defined(__ANDROID__) +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Not all Windows environments support SEH properly +#if defined(__MINGW32__) +# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH +#endif + +//////////////////////////////////////////////////////////////////////////////// +// PS4 +#if defined(__ORBIS__) +# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Cygwin +#ifdef __CYGWIN__ + +// Required for some versions of Cygwin to declare gettimeofday +// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin +# define _BSD_SOURCE + +#endif // __CYGWIN__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +# if _MSC_VER >= 1900 // Visual Studio 2015 or newer +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +# endif + +// Universal Windows platform does not support SEH +// Or console colours (or console at all...) +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +# define CATCH_CONFIG_COLOUR_NONE +# else +# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH +# endif + +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// + +// DJGPP +#ifdef __DJGPP__ +# define CATCH_INTERNAL_CONFIG_NO_WCHAR +#endif // __DJGPP__ + +//////////////////////////////////////////////////////////////////////////////// + +// Use of __COUNTER__ is suppressed during code analysis in +// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly +// handled by it. +// Otherwise all supported compilers support COUNTER macro, +// but user still might want to turn it off +#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) + #define CATCH_INTERNAL_CONFIG_COUNTER +#endif + +#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) +# define CATCH_CONFIG_COUNTER +#endif +#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) +# define CATCH_CONFIG_WINDOWS_SEH +#endif +// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. +#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) +# define CATCH_CONFIG_POSIX_SIGNALS +#endif +// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. +#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) +# define CATCH_CONFIG_WCHAR +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) +# define CATCH_CONFIG_CPP11_TO_STRING +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) +# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) +# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) +# define CATCH_CONFIG_NEW_CAPTURE +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS +# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS +# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS +#endif + +// end catch_compiler_capabilities.h +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#ifdef CATCH_CONFIG_COUNTER +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) +#else +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) +#endif + +#include <iosfwd> +#include <string> +#include <cstdint> + +namespace Catch { + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + + class NonCopyable { + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; + + protected: + NonCopyable(); + virtual ~NonCopyable(); + }; + + struct SourceLineInfo { + + SourceLineInfo() = delete; + SourceLineInfo( char const* _file, std::size_t _line ) noexcept + : file( _file ), + line( _line ) + {} + + SourceLineInfo( SourceLineInfo const& other ) = default; + SourceLineInfo( SourceLineInfo && ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo& operator = ( SourceLineInfo && ) = default; + + bool empty() const noexcept; + bool operator == ( SourceLineInfo const& other ) const noexcept; + bool operator < ( SourceLineInfo const& other ) const noexcept; + + char const* file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() const; + }; + template<typename T> + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO \ + ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) ) + +// end catch_common.h +namespace Catch { + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS + +// end catch_tag_alias_autoregistrar.h +// start catch_test_registry.h + +// start catch_interfaces_testcase.h + +#include <vector> +#include <memory> + +namespace Catch { + + class TestSpec; + + struct ITestInvoker { + virtual void invoke () const = 0; + virtual ~ITestInvoker(); + }; + + using ITestCasePtr = std::shared_ptr<ITestInvoker>; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector<TestCase> const& getAllTests() const = 0; + virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0; + }; + + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ); + +} + +// end catch_interfaces_testcase.h +// start catch_stringref.h + +#include <cstddef> +#include <string> +#include <iosfwd> + +namespace Catch { + + class StringData; + + /// A non-owning string class (similar to the forthcoming std::string_view) + /// Note that, because a StringRef may be a substring of another string, + /// it may not be null terminated. c_str() must return a null terminated + /// string, however, and so the StringRef will internally take ownership + /// (taking a copy), if necessary. In theory this ownership is not externally + /// visible - but it does mean (substring) StringRefs should not be shared between + /// threads. + class StringRef { + public: + using size_type = std::size_t; + + private: + friend struct StringRefTestAccess; + + char const* m_start; + size_type m_size; + + char* m_data = nullptr; + + void takeOwnership(); + + static constexpr char const* const s_empty = ""; + + public: // construction/ assignment + StringRef() noexcept + : StringRef( s_empty, 0 ) + {} + + StringRef( StringRef const& other ) noexcept + : m_start( other.m_start ), + m_size( other.m_size ) + {} + + StringRef( StringRef&& other ) noexcept + : m_start( other.m_start ), + m_size( other.m_size ), + m_data( other.m_data ) + { + other.m_data = nullptr; + } + + StringRef( char const* rawChars ) noexcept; + + StringRef( char const* rawChars, size_type size ) noexcept + : m_start( rawChars ), + m_size( size ) + {} + + StringRef( std::string const& stdString ) noexcept + : m_start( stdString.c_str() ), + m_size( stdString.size() ) + {} + + ~StringRef() noexcept { + delete[] m_data; + } + + auto operator = ( StringRef const &other ) noexcept -> StringRef& { + delete[] m_data; + m_data = nullptr; + m_start = other.m_start; + m_size = other.m_size; + return *this; + } + + operator std::string() const; + + void swap( StringRef& other ) noexcept; + + public: // operators + auto operator == ( StringRef const& other ) const noexcept -> bool; + auto operator != ( StringRef const& other ) const noexcept -> bool; + + auto operator[] ( size_type index ) const noexcept -> char; + + public: // named queries + auto empty() const noexcept -> bool { + return m_size == 0; + } + auto size() const noexcept -> size_type { + return m_size; + } + + auto numberOfCharacters() const noexcept -> size_type; + auto c_str() const -> char const*; + + public: // substrings and searches + auto substr( size_type start, size_type size ) const noexcept -> StringRef; + + // Returns the current start pointer. + // Note that the pointer can change when if the StringRef is a substring + auto currentData() const noexcept -> char const*; + + private: // ownership queries - may not be consistent between calls + auto isOwned() const noexcept -> bool; + auto isSubstring() const noexcept -> bool; + }; + + auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string; + auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string; + auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string; + + auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; + auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; + + inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + return StringRef( rawChars, size ); + } + +} // namespace Catch + +// end catch_stringref.h +namespace Catch { + +template<typename C> +class TestInvokerAsMethod : public ITestInvoker { + void (C::*m_testAsMethod)(); +public: + TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {} + + void invoke() const override { + C obj; + (obj.*m_testAsMethod)(); + } +}; + +auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker*; + +template<typename C> +auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* { + return new(std::nothrow) TestInvokerAsMethod<C>( testAsMethod ); +} + +struct NameAndTags { + NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept; + StringRef name; + StringRef tags; +}; + +struct AutoReg : NonCopyable { + AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept; + ~AutoReg(); +}; + +} // end namespace Catch + +#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) +#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ +#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ +#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF + +#if defined(CATCH_CONFIG_DISABLE) + #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \ + static void TestName() + #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \ + namespace{ \ + struct TestName : INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF ClassName) { \ + void test(); \ + }; \ + } \ + void TestName::test() + +#endif + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ + static void TestName(); \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + static void TestName() + #define INTERNAL_CATCH_TESTCASE( ... ) \ + INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ ) + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ \ + struct TestName : INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF ClassName) { \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ + } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + void TestName::test() + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ + INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ ) + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS + +// end catch_test_registry.h +// start catch_capture.hpp + +// start catch_assertionhandler.h + +// start catch_assertioninfo.h + +// start catch_result_type.h + +namespace Catch { + + // ResultWas::OfType enum + struct ResultWas { enum OfType { + Unknown = -1, + Ok = 0, + Info = 1, + Warning = 2, + + FailureBit = 0x10, + + ExpressionFailed = FailureBit | 1, + ExplicitFailure = FailureBit | 2, + + Exception = 0x100 | FailureBit, + + ThrewException = Exception | 1, + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit + + }; }; + + bool isOk( ResultWas::OfType resultType ); + bool isJustInfo( int flags ); + + // ResultDisposition::Flags enum + struct ResultDisposition { enum Flags { + Normal = 0x01, + + ContinueOnFailure = 0x02, // Failures fail test, but execution continues + FalseTest = 0x04, // Prefix expression with ! + SuppressFail = 0x08 // Failures are reported but do not fail the test + }; }; + + ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); + + bool shouldContinueOnFailure( int flags ); + inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } + bool shouldSuppressFailure( int flags ); + +} // end namespace Catch + +// end catch_result_type.h +namespace Catch { + + struct AssertionInfo + { + StringRef macroName; + SourceLineInfo lineInfo; + StringRef capturedExpression; + ResultDisposition::Flags resultDisposition; + + // We want to delete this constructor but a compiler bug in 4.8 means + // the struct is then treated as non-aggregate + //AssertionInfo() = delete; + }; + +} // end namespace Catch + +// end catch_assertioninfo.h +// start catch_decomposer.h + +// start catch_tostring.h + +#include <vector> +#include <cstddef> +#include <type_traits> +#include <string> +// start catch_stream.h + +#include <iosfwd> +#include <cstddef> +#include <ostream> + +namespace Catch { + + std::ostream& cout(); + std::ostream& cerr(); + std::ostream& clog(); + + class StringRef; + + struct IStream { + virtual ~IStream(); + virtual std::ostream& stream() const = 0; + }; + + auto makeStream( StringRef const &filename ) -> IStream const*; + + class ReusableStringStream { + std::size_t m_index; + std::ostream* m_oss; + public: + ReusableStringStream(); + ~ReusableStringStream(); + + auto str() const -> std::string; + + template<typename T> + auto operator << ( T const& value ) -> ReusableStringStream& { + *m_oss << value; + return *this; + } + auto get() -> std::ostream& { return *m_oss; } + + static void cleanup(); + }; +} + +// end catch_stream.h + +#ifdef __OBJC__ +// start catch_objc_arc.hpp + +#import <Foundation/Foundation.h> + +#ifdef __has_feature +#define CATCH_ARC_ENABLED __has_feature(objc_arc) +#else +#define CATCH_ARC_ENABLED 0 +#endif + +void arcSafeRelease( NSObject* obj ); +id performOptionalSelector( id obj, SEL sel ); + +#if !CATCH_ARC_ENABLED +inline void arcSafeRelease( NSObject* obj ) { + [obj release]; +} +inline id performOptionalSelector( id obj, SEL sel ) { + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; + return nil; +} +#define CATCH_UNSAFE_UNRETAINED +#define CATCH_ARC_STRONG +#else +inline void arcSafeRelease( NSObject* ){} +inline id performOptionalSelector( id obj, SEL sel ) { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +#endif + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + return nil; +} +#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained +#define CATCH_ARC_STRONG __strong +#endif + +// end catch_objc_arc.hpp +#endif + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless +#endif + +// We need a dummy global operator<< so we can bring it into Catch namespace later +struct Catch_global_namespace_dummy {}; +std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); + +namespace Catch { + // Bring in operator<< from global namespace into Catch namespace + using ::operator<<; + + namespace Detail { + + extern const std::string unprintableString; + + std::string rawMemoryToString( const void *object, std::size_t size ); + + template<typename T> + std::string rawMemoryToString( const T& object ) { + return rawMemoryToString( &object, sizeof(object) ); + } + + template<typename T> + class IsStreamInsertable { + template<typename SS, typename TT> + static auto test(int) + -> decltype(std::declval<SS&>() << std::declval<TT>(), std::true_type()); + + template<typename, typename> + static auto test(...)->std::false_type; + + public: + static const bool value = decltype(test<std::ostream, const T&>(0))::value; + }; + + template<typename E> + std::string convertUnknownEnumToString( E e ); + + template<typename T> + typename std::enable_if< + !std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value, + std::string>::type convertUnstreamable( T const& ) { + return Detail::unprintableString; + } + template<typename T> + typename std::enable_if< + !std::is_enum<T>::value && std::is_base_of<std::exception, T>::value, + std::string>::type convertUnstreamable(T const& ex) { + return ex.what(); + } + + template<typename T> + typename std::enable_if< + std::is_enum<T>::value + , std::string>::type convertUnstreamable( T const& value ) { + return convertUnknownEnumToString( value ); + } + +#if defined(_MANAGED) + //! Convert a CLR string to a utf8 std::string + template<typename T> + std::string clrReferenceToString( T^ ref ) { + if (ref == nullptr) + return std::string("null"); + auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString()); + cli::pin_ptr<System::Byte> p = &bytes[0]; + return std::string(reinterpret_cast<char const *>(p), bytes->Length); + } +#endif + + } // namespace Detail + + // If we decide for C++14, change these to enable_if_ts + template <typename T, typename = void> + struct StringMaker { + template <typename Fake = T> + static + typename std::enable_if<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type + convert(const Fake& value) { + ReusableStringStream rss; + // NB: call using the function-like syntax to avoid ambiguity with + // user-defined templated operator<< under clang. + rss.operator<<(value); + return rss.str(); + } + + template <typename Fake = T> + static + typename std::enable_if<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type + convert( const Fake& value ) { +#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER) + return Detail::convertUnstreamable(value); +#else + return CATCH_CONFIG_FALLBACK_STRINGIFIER(value); +#endif + } + }; + + namespace Detail { + + // This function dispatches all stringification requests inside of Catch. + // Should be preferably called fully qualified, like ::Catch::Detail::stringify + template <typename T> + std::string stringify(const T& e) { + return ::Catch::StringMaker<typename std::remove_cv<typename std::remove_reference<T>::type>::type>::convert(e); + } + + template<typename E> + std::string convertUnknownEnumToString( E e ) { + return ::Catch::Detail::stringify(static_cast<typename std::underlying_type<E>::type>(e)); + } + +#if defined(_MANAGED) + template <typename T> + std::string stringify( T^ e ) { + return ::Catch::StringMaker<T^>::convert(e); + } +#endif + + } // namespace Detail + + // Some predefined specializations + + template<> + struct StringMaker<std::string> { + static std::string convert(const std::string& str); + }; +#ifdef CATCH_CONFIG_WCHAR + template<> + struct StringMaker<std::wstring> { + static std::string convert(const std::wstring& wstr); + }; +#endif + + template<> + struct StringMaker<char const *> { + static std::string convert(char const * str); + }; + template<> + struct StringMaker<char *> { + static std::string convert(char * str); + }; + +#ifdef CATCH_CONFIG_WCHAR + template<> + struct StringMaker<wchar_t const *> { + static std::string convert(wchar_t const * str); + }; + template<> + struct StringMaker<wchar_t *> { + static std::string convert(wchar_t * str); + }; +#endif + + // TBD: Should we use `strnlen` to ensure that we don't go out of the buffer, + // while keeping string semantics? + template<int SZ> + struct StringMaker<char[SZ]> { + static std::string convert(char const* str) { + return ::Catch::Detail::stringify(std::string{ str }); + } + }; + template<int SZ> + struct StringMaker<signed char[SZ]> { + static std::string convert(signed char const* str) { + return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) }); + } + }; + template<int SZ> + struct StringMaker<unsigned char[SZ]> { + static std::string convert(unsigned char const* str) { + return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) }); + } + }; + + template<> + struct StringMaker<int> { + static std::string convert(int value); + }; + template<> + struct StringMaker<long> { + static std::string convert(long value); + }; + template<> + struct StringMaker<long long> { + static std::string convert(long long value); + }; + template<> + struct StringMaker<unsigned int> { + static std::string convert(unsigned int value); + }; + template<> + struct StringMaker<unsigned long> { + static std::string convert(unsigned long value); + }; + template<> + struct StringMaker<unsigned long long> { + static std::string convert(unsigned long long value); + }; + + template<> + struct StringMaker<bool> { + static std::string convert(bool b); + }; + + template<> + struct StringMaker<char> { + static std::string convert(char c); + }; + template<> + struct StringMaker<signed char> { + static std::string convert(signed char c); + }; + template<> + struct StringMaker<unsigned char> { + static std::string convert(unsigned char c); + }; + + template<> + struct StringMaker<std::nullptr_t> { + static std::string convert(std::nullptr_t); + }; + + template<> + struct StringMaker<float> { + static std::string convert(float value); + }; + template<> + struct StringMaker<double> { + static std::string convert(double value); + }; + + template <typename T> + struct StringMaker<T*> { + template <typename U> + static std::string convert(U* p) { + if (p) { + return ::Catch::Detail::rawMemoryToString(p); + } else { + return "nullptr"; + } + } + }; + + template <typename R, typename C> + struct StringMaker<R C::*> { + static std::string convert(R C::* p) { + if (p) { + return ::Catch::Detail::rawMemoryToString(p); + } else { + return "nullptr"; + } + } + }; + +#if defined(_MANAGED) + template <typename T> + struct StringMaker<T^> { + static std::string convert( T^ ref ) { + return ::Catch::Detail::clrReferenceToString(ref); + } + }; +#endif + + namespace Detail { + template<typename InputIterator> + std::string rangeToString(InputIterator first, InputIterator last) { + ReusableStringStream rss; + rss << "{ "; + if (first != last) { + rss << ::Catch::Detail::stringify(*first); + for (++first; first != last; ++first) + rss << ", " << ::Catch::Detail::stringify(*first); + } + rss << " }"; + return rss.str(); + } + } + +#ifdef __OBJC__ + template<> + struct StringMaker<NSString*> { + static std::string convert(NSString * nsstring) { + if (!nsstring) + return "nil"; + return std::string("@") + [nsstring UTF8String]; + } + }; + template<> + struct StringMaker<NSObject*> { + static std::string convert(NSObject* nsObject) { + return ::Catch::Detail::stringify([nsObject description]); + } + + }; + namespace Detail { + inline std::string stringify( NSString* nsstring ) { + return StringMaker<NSString*>::convert( nsstring ); + } + + } // namespace Detail +#endif // __OBJC__ + +} // namespace Catch + +////////////////////////////////////////////////////// +// Separate std-lib types stringification, so it can be selectively enabled +// This means that we do not bring in + +#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS) +# define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER +# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +#endif + +// Separate std::pair specialization +#if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER) +#include <utility> +namespace Catch { + template<typename T1, typename T2> + struct StringMaker<std::pair<T1, T2> > { + static std::string convert(const std::pair<T1, T2>& pair) { + ReusableStringStream rss; + rss << "{ " + << ::Catch::Detail::stringify(pair.first) + << ", " + << ::Catch::Detail::stringify(pair.second) + << " }"; + return rss.str(); + } + }; +} +#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER + +// Separate std::tuple specialization +#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER) +#include <tuple> +namespace Catch { + namespace Detail { + template< + typename Tuple, + std::size_t N = 0, + bool = (N < std::tuple_size<Tuple>::value) + > + struct TupleElementPrinter { + static void print(const Tuple& tuple, std::ostream& os) { + os << (N ? ", " : " ") + << ::Catch::Detail::stringify(std::get<N>(tuple)); + TupleElementPrinter<Tuple, N + 1>::print(tuple, os); + } + }; + + template< + typename Tuple, + std::size_t N + > + struct TupleElementPrinter<Tuple, N, false> { + static void print(const Tuple&, std::ostream&) {} + }; + + } + + template<typename ...Types> + struct StringMaker<std::tuple<Types...>> { + static std::string convert(const std::tuple<Types...>& tuple) { + ReusableStringStream rss; + rss << '{'; + Detail::TupleElementPrinter<std::tuple<Types...>>::print(tuple, rss.get()); + rss << " }"; + return rss.str(); + } + }; +} +#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER + +namespace Catch { + struct not_this_one {}; // Tag type for detecting which begin/ end are being selected + + // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace + using std::begin; + using std::end; + + not_this_one begin( ... ); + not_this_one end( ... ); + + template <typename T> + struct is_range { + static const bool value = + !std::is_same<decltype(begin(std::declval<T>())), not_this_one>::value && + !std::is_same<decltype(end(std::declval<T>())), not_this_one>::value; + }; + +#if defined(_MANAGED) // Managed types are never ranges + template <typename T> + struct is_range<T^> { + static const bool value = false; + }; +#endif + + template<typename Range> + std::string rangeToString( Range const& range ) { + return ::Catch::Detail::rangeToString( begin( range ), end( range ) ); + } + + // Handle vector<bool> specially + template<typename Allocator> + std::string rangeToString( std::vector<bool, Allocator> const& v ) { + ReusableStringStream rss; + rss << "{ "; + bool first = true; + for( bool b : v ) { + if( first ) + first = false; + else + rss << ", "; + rss << ::Catch::Detail::stringify( b ); + } + rss << " }"; + return rss.str(); + } + + template<typename R> + struct StringMaker<R, typename std::enable_if<is_range<R>::value && !::Catch::Detail::IsStreamInsertable<R>::value>::type> { + static std::string convert( R const& range ) { + return rangeToString( range ); + } + }; + + template <typename T, int SZ> + struct StringMaker<T[SZ]> { + static std::string convert(T const(&arr)[SZ]) { + return rangeToString(arr); + } + }; + +} // namespace Catch + +// Separate std::chrono::duration specialization +#if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +#include <ctime> +#include <ratio> +#include <chrono> + +namespace Catch { + +template <class Ratio> +struct ratio_string { + static std::string symbol(); +}; + +template <class Ratio> +std::string ratio_string<Ratio>::symbol() { + Catch::ReusableStringStream rss; + rss << '[' << Ratio::num << '/' + << Ratio::den << ']'; + return rss.str(); +} +template <> +struct ratio_string<std::atto> { + static std::string symbol(); +}; +template <> +struct ratio_string<std::femto> { + static std::string symbol(); +}; +template <> +struct ratio_string<std::pico> { + static std::string symbol(); +}; +template <> +struct ratio_string<std::nano> { + static std::string symbol(); +}; +template <> +struct ratio_string<std::micro> { + static std::string symbol(); +}; +template <> +struct ratio_string<std::milli> { + static std::string symbol(); +}; + + //////////// + // std::chrono::duration specializations + template<typename Value, typename Ratio> + struct StringMaker<std::chrono::duration<Value, Ratio>> { + static std::string convert(std::chrono::duration<Value, Ratio> const& duration) { + ReusableStringStream rss; + rss << duration.count() << ' ' << ratio_string<Ratio>::symbol() << 's'; + return rss.str(); + } + }; + template<typename Value> + struct StringMaker<std::chrono::duration<Value, std::ratio<1>>> { + static std::string convert(std::chrono::duration<Value, std::ratio<1>> const& duration) { + ReusableStringStream rss; + rss << duration.count() << " s"; + return rss.str(); + } + }; + template<typename Value> + struct StringMaker<std::chrono::duration<Value, std::ratio<60>>> { + static std::string convert(std::chrono::duration<Value, std::ratio<60>> const& duration) { + ReusableStringStream rss; + rss << duration.count() << " m"; + return rss.str(); + } + }; + template<typename Value> + struct StringMaker<std::chrono::duration<Value, std::ratio<3600>>> { + static std::string convert(std::chrono::duration<Value, std::ratio<3600>> const& duration) { + ReusableStringStream rss; + rss << duration.count() << " h"; + return rss.str(); + } + }; + + //////////// + // std::chrono::time_point specialization + // Generic time_point cannot be specialized, only std::chrono::time_point<system_clock> + template<typename Clock, typename Duration> + struct StringMaker<std::chrono::time_point<Clock, Duration>> { + static std::string convert(std::chrono::time_point<Clock, Duration> const& time_point) { + return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch"; + } + }; + // std::chrono::time_point<system_clock> specialization + template<typename Duration> + struct StringMaker<std::chrono::time_point<std::chrono::system_clock, Duration>> { + static std::string convert(std::chrono::time_point<std::chrono::system_clock, Duration> const& time_point) { + auto converted = std::chrono::system_clock::to_time_t(time_point); + +#ifdef _MSC_VER + std::tm timeInfo = {}; + gmtime_s(&timeInfo, &converted); +#else + std::tm* timeInfo = std::gmtime(&converted); +#endif + + auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); + char timeStamp[timeStampSize]; + const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; + +#ifdef _MSC_VER + std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); +#else + std::strftime(timeStamp, timeStampSize, fmt, timeInfo); +#endif + return std::string(timeStamp); + } + }; +} +#endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// end catch_tostring.h +#include <iosfwd> + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#pragma warning(disable:4018) // more "signed/unsigned mismatch" +#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) +#pragma warning(disable:4180) // qualifier applied to function type has no meaning +#endif + +namespace Catch { + + struct ITransientExpression { + auto isBinaryExpression() const -> bool { return m_isBinaryExpression; } + auto getResult() const -> bool { return m_result; } + virtual void streamReconstructedExpression( std::ostream &os ) const = 0; + + ITransientExpression( bool isBinaryExpression, bool result ) + : m_isBinaryExpression( isBinaryExpression ), + m_result( result ) + {} + + // We don't actually need a virtual destructor, but many static analysers + // complain if it's not here :-( + virtual ~ITransientExpression(); + + bool m_isBinaryExpression; + bool m_result; + + }; + + void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); + + template<typename LhsT, typename RhsT> + class BinaryExpr : public ITransientExpression { + LhsT m_lhs; + StringRef m_op; + RhsT m_rhs; + + void streamReconstructedExpression( std::ostream &os ) const override { + formatReconstructedExpression + ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); + } + + public: + BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs ) + : ITransientExpression{ true, comparisonResult }, + m_lhs( lhs ), + m_op( op ), + m_rhs( rhs ) + {} + }; + + template<typename LhsT> + class UnaryExpr : public ITransientExpression { + LhsT m_lhs; + + void streamReconstructedExpression( std::ostream &os ) const override { + os << Catch::Detail::stringify( m_lhs ); + } + + public: + explicit UnaryExpr( LhsT lhs ) + : ITransientExpression{ false, lhs ? true : false }, + m_lhs( lhs ) + {} + }; + + // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int) + template<typename LhsT, typename RhsT> + auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast<bool>(lhs == rhs); } + template<typename T> + auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); } + template<typename T> + auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); } + template<typename T> + auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; } + template<typename T> + auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; } + + template<typename LhsT, typename RhsT> + auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast<bool>(lhs != rhs); } + template<typename T> + auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); } + template<typename T> + auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); } + template<typename T> + auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; } + template<typename T> + auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; } + + template<typename LhsT> + class ExprLhs { + LhsT m_lhs; + public: + explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} + + template<typename RhsT> + auto operator == ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { + return { compareEqual( m_lhs, rhs ), m_lhs, "==", rhs }; + } + auto operator == ( bool rhs ) -> BinaryExpr<LhsT, bool> const { + return { m_lhs == rhs, m_lhs, "==", rhs }; + } + + template<typename RhsT> + auto operator != ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { + return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs }; + } + auto operator != ( bool rhs ) -> BinaryExpr<LhsT, bool> const { + return { m_lhs != rhs, m_lhs, "!=", rhs }; + } + + template<typename RhsT> + auto operator > ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { + return { static_cast<bool>(m_lhs > rhs), m_lhs, ">", rhs }; + } + template<typename RhsT> + auto operator < ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { + return { static_cast<bool>(m_lhs < rhs), m_lhs, "<", rhs }; + } + template<typename RhsT> + auto operator >= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { + return { static_cast<bool>(m_lhs >= rhs), m_lhs, ">=", rhs }; + } + template<typename RhsT> + auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { + return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs }; + } + + auto makeUnaryExpr() const -> UnaryExpr<LhsT> { + return UnaryExpr<LhsT>{ m_lhs }; + } + }; + + void handleExpression( ITransientExpression const& expr ); + + template<typename T> + void handleExpression( ExprLhs<T> const& expr ) { + handleExpression( expr.makeUnaryExpr() ); + } + + struct Decomposer { + template<typename T> + auto operator <= ( T const& lhs ) -> ExprLhs<T const&> { + return ExprLhs<T const&>{ lhs }; + } + + auto operator <=( bool value ) -> ExprLhs<bool> { + return ExprLhs<bool>{ value }; + } + }; + +} // end namespace Catch + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// end catch_decomposer.h +// start catch_interfaces_capture.h + +#include <string> + +namespace Catch { + + class AssertionResult; + struct AssertionInfo; + struct SectionInfo; + struct SectionEndInfo; + struct MessageInfo; + struct Counts; + struct BenchmarkInfo; + struct BenchmarkStats; + struct AssertionReaction; + + struct ITransientExpression; + + struct IResultCapture { + + virtual ~IResultCapture(); + + virtual bool sectionStarted( SectionInfo const& sectionInfo, + Counts& assertions ) = 0; + virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; + + virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; + virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0; + + virtual void pushScopedMessage( MessageInfo const& message ) = 0; + virtual void popScopedMessage( MessageInfo const& message ) = 0; + + virtual void handleFatalErrorCondition( StringRef message ) = 0; + + virtual void handleExpr + ( AssertionInfo const& info, + ITransientExpression const& expr, + AssertionReaction& reaction ) = 0; + virtual void handleMessage + ( AssertionInfo const& info, + ResultWas::OfType resultType, + StringRef const& message, + AssertionReaction& reaction ) = 0; + virtual void handleUnexpectedExceptionNotThrown + ( AssertionInfo const& info, + AssertionReaction& reaction ) = 0; + virtual void handleUnexpectedInflightException + ( AssertionInfo const& info, + std::string const& message, + AssertionReaction& reaction ) = 0; + virtual void handleIncomplete + ( AssertionInfo const& info ) = 0; + virtual void handleNonExpr + ( AssertionInfo const &info, + ResultWas::OfType resultType, + AssertionReaction &reaction ) = 0; + + virtual bool lastAssertionPassed() = 0; + virtual void assertionPassed() = 0; + + // Deprecated, do not use: + virtual std::string getCurrentTestName() const = 0; + virtual const AssertionResult* getLastResult() const = 0; + virtual void exceptionEarlyReported() = 0; + }; + + IResultCapture& getResultCapture(); +} + +// end catch_interfaces_capture.h +namespace Catch { + + struct TestFailureException{}; + struct AssertionResultData; + struct IResultCapture; + class RunContext; + + class LazyExpression { + friend class AssertionHandler; + friend struct AssertionStats; + friend class RunContext; + + ITransientExpression const* m_transientExpression = nullptr; + bool m_isNegated; + public: + LazyExpression( bool isNegated ); + LazyExpression( LazyExpression const& other ); + LazyExpression& operator = ( LazyExpression const& ) = delete; + + explicit operator bool() const; + + friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; + }; + + struct AssertionReaction { + bool shouldDebugBreak = false; + bool shouldThrow = false; + }; + + class AssertionHandler { + AssertionInfo m_assertionInfo; + AssertionReaction m_reaction; + bool m_completed = false; + IResultCapture& m_resultCapture; + + public: + AssertionHandler + ( StringRef macroName, + SourceLineInfo const& lineInfo, + StringRef capturedExpression, + ResultDisposition::Flags resultDisposition ); + ~AssertionHandler() { + if ( !m_completed ) { + m_resultCapture.handleIncomplete( m_assertionInfo ); + } + } + + template<typename T> + void handleExpr( ExprLhs<T> const& expr ) { + handleExpr( expr.makeUnaryExpr() ); + } + void handleExpr( ITransientExpression const& expr ); + + void handleMessage(ResultWas::OfType resultType, StringRef const& message); + + void handleExceptionThrownAsExpected(); + void handleUnexpectedExceptionNotThrown(); + void handleExceptionNotThrownAsExpected(); + void handleThrowingCallSkipped(); + void handleUnexpectedInflightException(); + + void complete(); + void setCompleted(); + + // query + auto allowThrows() const -> bool; + }; + + void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ); + +} // namespace Catch + +// end catch_assertionhandler.h +// start catch_message.h + +#include <string> + +namespace Catch { + + struct MessageInfo { + MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ); + + std::string macroName; + std::string message; + SourceLineInfo lineInfo; + ResultWas::OfType type; + unsigned int sequence; + + bool operator == ( MessageInfo const& other ) const; + bool operator < ( MessageInfo const& other ) const; + private: + static unsigned int globalCount; + }; + + struct MessageStream { + + template<typename T> + MessageStream& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + ReusableStringStream m_stream; + }; + + struct MessageBuilder : MessageStream { + MessageBuilder( std::string const& macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType type ); + + template<typename T> + MessageBuilder& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + MessageInfo m_info; + }; + + class ScopedMessage { + public: + explicit ScopedMessage( MessageBuilder const& builder ); + ~ScopedMessage(); + + MessageInfo m_info; + }; + +} // end namespace Catch + +// end catch_message.h +#if !defined(CATCH_CONFIG_DISABLE) + +#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) + #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__ +#else + #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION" +#endif + +#if defined(CATCH_CONFIG_FAST_COMPILE) + +/////////////////////////////////////////////////////////////////////////////// +// Another way to speed-up compilation is to omit local try-catch for REQUIRE* +// macros. +#define INTERNAL_CATCH_TRY +#define INTERNAL_CATCH_CATCH( capturer ) + +#else // CATCH_CONFIG_FAST_COMPILE + +#define INTERNAL_CATCH_TRY try +#define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); } + +#endif + +#define INTERNAL_CATCH_REACT( handler ) handler.complete(); + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ + INTERNAL_CATCH_TRY { \ + CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \ + CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ + } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( (void)0, false && static_cast<bool>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look + // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \ + INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ + if( Catch::getResultCapture().lastAssertionPassed() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \ + INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ + if( !Catch::getResultCapture().lastAssertionPassed() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ + try { \ + static_cast<void>(__VA_ARGS__); \ + catchAssertionHandler.handleExceptionNotThrownAsExpected(); \ + } \ + catch( ... ) { \ + catchAssertionHandler.handleUnexpectedInflightException(); \ + } \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \ + if( catchAssertionHandler.allowThrows() ) \ + try { \ + static_cast<void>(__VA_ARGS__); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ + } \ + catch( ... ) { \ + catchAssertionHandler.handleExceptionThrownAsExpected(); \ + } \ + else \ + catchAssertionHandler.handleThrowingCallSkipped(); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \ + if( catchAssertionHandler.allowThrows() ) \ + try { \ + static_cast<void>(expr); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ + } \ + catch( exceptionType const& ) { \ + catchAssertionHandler.handleExceptionThrownAsExpected(); \ + } \ + catch( ... ) { \ + catchAssertionHandler.handleUnexpectedInflightException(); \ + } \ + else \ + catchAssertionHandler.handleThrowingCallSkipped(); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \ + catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_INFO( macroName, log ) \ + Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ); + +/////////////////////////////////////////////////////////////////////////////// +// Although this is matcher-based, it can be used with just a string +#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ + if( catchAssertionHandler.allowThrows() ) \ + try { \ + static_cast<void>(__VA_ARGS__); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ + } \ + catch( ... ) { \ + Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \ + } \ + else \ + catchAssertionHandler.handleThrowingCallSkipped(); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) + +#endif // CATCH_CONFIG_DISABLE + +// end catch_capture.hpp +// start catch_section.h + +// start catch_section_info.h + +// start catch_totals.h + +#include <cstddef> + +namespace Catch { + + struct Counts { + Counts operator - ( Counts const& other ) const; + Counts& operator += ( Counts const& other ); + + std::size_t total() const; + bool allPassed() const; + bool allOk() const; + + std::size_t passed = 0; + std::size_t failed = 0; + std::size_t failedButOk = 0; + }; + + struct Totals { + + Totals operator - ( Totals const& other ) const; + Totals& operator += ( Totals const& other ); + + Totals delta( Totals const& prevTotals ) const; + + int error = 0; + Counts assertions; + Counts testCases; + }; +} + +// end catch_totals.h +#include <string> + +namespace Catch { + + struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name ); + + // Deprecated + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& ) : SectionInfo( _lineInfo, _name ) {} + + std::string name; + std::string description; // !Deprecated: this will always be empty + SourceLineInfo lineInfo; + }; + + struct SectionEndInfo { + SectionInfo sectionInfo; + Counts prevAssertions; + double durationInSeconds; + }; + +} // end namespace Catch + +// end catch_section_info.h +// start catch_timer.h + +#include <cstdint> + +namespace Catch { + + auto getCurrentNanosecondsSinceEpoch() -> uint64_t; + auto getEstimatedClockResolution() -> uint64_t; + + class Timer { + uint64_t m_nanoseconds = 0; + public: + void start(); + auto getElapsedNanoseconds() const -> uint64_t; + auto getElapsedMicroseconds() const -> uint64_t; + auto getElapsedMilliseconds() const -> unsigned int; + auto getElapsedSeconds() const -> double; + }; + +} // namespace Catch + +// end catch_timer.h +#include <string> + +namespace Catch { + + class Section : NonCopyable { + public: + Section( SectionInfo const& info ); + ~Section(); + + // This indicates whether the section should be executed or not + explicit operator bool() const; + + private: + SectionInfo m_info; + + std::string m_name; + Counts m_assertions; + bool m_sectionIncluded; + Timer m_timer; + }; + +} // end namespace Catch + +#define INTERNAL_CATCH_SECTION( ... ) \ + CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \ + CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS + +#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ + CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \ + CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS + +// end catch_section.h +// start catch_benchmark.h + +#include <cstdint> +#include <string> + +namespace Catch { + + class BenchmarkLooper { + + std::string m_name; + std::size_t m_count = 0; + std::size_t m_iterationsToRun = 1; + uint64_t m_resolution; + Timer m_timer; + + static auto getResolution() -> uint64_t; + public: + // Keep most of this inline as it's on the code path that is being timed + BenchmarkLooper( StringRef name ) + : m_name( name ), + m_resolution( getResolution() ) + { + reportStart(); + m_timer.start(); + } + + explicit operator bool() { + if( m_count < m_iterationsToRun ) + return true; + return needsMoreIterations(); + } + + void increment() { + ++m_count; + } + + void reportStart(); + auto needsMoreIterations() -> bool; + }; + +} // end namespace Catch + +#define BENCHMARK( name ) \ + for( Catch::BenchmarkLooper looper( name ); looper; looper.increment() ) + +// end catch_benchmark.h +// start catch_interfaces_exception.h + +// start catch_interfaces_registry_hub.h + +#include <string> +#include <memory> + +namespace Catch { + + class TestCase; + struct ITestCaseRegistry; + struct IExceptionTranslatorRegistry; + struct IExceptionTranslator; + struct IReporterRegistry; + struct IReporterFactory; + struct ITagAliasRegistry; + class StartupExceptionRegistry; + + using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>; + + struct IRegistryHub { + virtual ~IRegistryHub(); + + virtual IReporterRegistry const& getReporterRegistry() const = 0; + virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; + virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; + + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; + + virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0; + }; + + struct IMutableRegistryHub { + virtual ~IMutableRegistryHub(); + virtual void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) = 0; + virtual void registerListener( IReporterFactoryPtr const& factory ) = 0; + virtual void registerTest( TestCase const& testInfo ) = 0; + virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; + virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; + virtual void registerStartupException() noexcept = 0; + }; + + IRegistryHub& getRegistryHub(); + IMutableRegistryHub& getMutableRegistryHub(); + void cleanUp(); + std::string translateActiveException(); + +} + +// end catch_interfaces_registry_hub.h +#if defined(CATCH_CONFIG_DISABLE) + #define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \ + static std::string translatorName( signature ) +#endif + +#include <exception> +#include <string> +#include <vector> + +namespace Catch { + using exceptionTranslateFunction = std::string(*)(); + + struct IExceptionTranslator; + using ExceptionTranslators = std::vector<std::unique_ptr<IExceptionTranslator const>>; + + struct IExceptionTranslator { + virtual ~IExceptionTranslator(); + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; + }; + + struct IExceptionTranslatorRegistry { + virtual ~IExceptionTranslatorRegistry(); + + virtual std::string translateActiveException() const = 0; + }; + + class ExceptionTranslatorRegistrar { + template<typename T> + class ExceptionTranslator : public IExceptionTranslator { + public: + + ExceptionTranslator( std::string(*translateFunction)( T& ) ) + : m_translateFunction( translateFunction ) + {} + + std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override { + try { + if( it == itEnd ) + std::rethrow_exception(std::current_exception()); + else + return (*it)->translate( it+1, itEnd ); + } + catch( T& ex ) { + return m_translateFunction( ex ); + } + } + + protected: + std::string(*m_translateFunction)( T& ); + }; + + public: + template<typename T> + ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { + getMutableRegistryHub().registerTranslator + ( new ExceptionTranslator<T>( translateFunction ) ); + } + }; +} + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \ + static std::string translatorName( signature ); \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + static std::string translatorName( signature ) + +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) + +// end catch_interfaces_exception.h +// start catch_approx.h + +#include <type_traits> +#include <stdexcept> + +namespace Catch { +namespace Detail { + + class Approx { + private: + bool equalityComparisonImpl(double other) const; + + public: + explicit Approx ( double value ); + + static Approx custom(); + + Approx operator-() const; + + template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + Approx operator()( T const& value ) { + Approx approx( static_cast<double>(value) ); + approx.epsilon( m_epsilon ); + approx.margin( m_margin ); + approx.scale( m_scale ); + return approx; + } + + template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + explicit Approx( T const& value ): Approx(static_cast<double>(value)) + {} + + template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + friend bool operator == ( const T& lhs, Approx const& rhs ) { + auto lhs_v = static_cast<double>(lhs); + return rhs.equalityComparisonImpl(lhs_v); + } + + template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + friend bool operator == ( Approx const& lhs, const T& rhs ) { + return operator==( rhs, lhs ); + } + + template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + friend bool operator != ( T const& lhs, Approx const& rhs ) { + return !operator==( lhs, rhs ); + } + + template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + friend bool operator != ( Approx const& lhs, T const& rhs ) { + return !operator==( rhs, lhs ); + } + + template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + friend bool operator <= ( T const& lhs, Approx const& rhs ) { + return static_cast<double>(lhs) < rhs.m_value || lhs == rhs; + } + + template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + friend bool operator <= ( Approx const& lhs, T const& rhs ) { + return lhs.m_value < static_cast<double>(rhs) || lhs == rhs; + } + + template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + friend bool operator >= ( T const& lhs, Approx const& rhs ) { + return static_cast<double>(lhs) > rhs.m_value || lhs == rhs; + } + + template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + friend bool operator >= ( Approx const& lhs, T const& rhs ) { + return lhs.m_value > static_cast<double>(rhs) || lhs == rhs; + } + + template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + Approx& epsilon( T const& newEpsilon ) { + double epsilonAsDouble = static_cast<double>(newEpsilon); + if( epsilonAsDouble < 0 || epsilonAsDouble > 1.0 ) { + throw std::domain_error + ( "Invalid Approx::epsilon: " + + Catch::Detail::stringify( epsilonAsDouble ) + + ", Approx::epsilon has to be between 0 and 1" ); + } + m_epsilon = epsilonAsDouble; + return *this; + } + + template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + Approx& margin( T const& newMargin ) { + double marginAsDouble = static_cast<double>(newMargin); + if( marginAsDouble < 0 ) { + throw std::domain_error + ( "Invalid Approx::margin: " + + Catch::Detail::stringify( marginAsDouble ) + + ", Approx::Margin has to be non-negative." ); + + } + m_margin = marginAsDouble; + return *this; + } + + template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> + Approx& scale( T const& newScale ) { + m_scale = static_cast<double>(newScale); + return *this; + } + + std::string toString() const; + + private: + double m_epsilon; + double m_margin; + double m_scale; + double m_value; + }; +} // end namespace Detail + +namespace literals { + Detail::Approx operator "" _a(long double val); + Detail::Approx operator "" _a(unsigned long long val); +} // end namespace literals + +template<> +struct StringMaker<Catch::Detail::Approx> { + static std::string convert(Catch::Detail::Approx const& value); +}; + +} // end namespace Catch + +// end catch_approx.h +// start catch_string_manip.h + +#include <string> +#include <iosfwd> + +namespace Catch { + + bool startsWith( std::string const& s, std::string const& prefix ); + bool startsWith( std::string const& s, char prefix ); + bool endsWith( std::string const& s, std::string const& suffix ); + bool endsWith( std::string const& s, char suffix ); + bool contains( std::string const& s, std::string const& infix ); + void toLowerInPlace( std::string& s ); + std::string toLower( std::string const& s ); + std::string trim( std::string const& str ); + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); + + struct pluralise { + pluralise( std::size_t count, std::string const& label ); + + friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); + + std::size_t m_count; + std::string m_label; + }; +} + +// end catch_string_manip.h +#ifndef CATCH_CONFIG_DISABLE_MATCHERS +// start catch_capture_matchers.h + +// start catch_matchers.h + +#include <string> +#include <vector> + +namespace Catch { +namespace Matchers { + namespace Impl { + + template<typename ArgT> struct MatchAllOf; + template<typename ArgT> struct MatchAnyOf; + template<typename ArgT> struct MatchNotOf; + + class MatcherUntypedBase { + public: + MatcherUntypedBase() = default; + MatcherUntypedBase ( MatcherUntypedBase const& ) = default; + MatcherUntypedBase& operator = ( MatcherUntypedBase const& ) = delete; + std::string toString() const; + + protected: + virtual ~MatcherUntypedBase(); + virtual std::string describe() const = 0; + mutable std::string m_cachedToString; + }; + + template<typename ObjectT> + struct MatcherMethod { + virtual bool match( ObjectT const& arg ) const = 0; + }; + template<typename PtrT> + struct MatcherMethod<PtrT*> { + virtual bool match( PtrT* arg ) const = 0; + }; + + template<typename T> + struct MatcherBase : MatcherUntypedBase, MatcherMethod<T> { + + MatchAllOf<T> operator && ( MatcherBase const& other ) const; + MatchAnyOf<T> operator || ( MatcherBase const& other ) const; + MatchNotOf<T> operator ! () const; + }; + + template<typename ArgT> + struct MatchAllOf : MatcherBase<ArgT> { + bool match( ArgT const& arg ) const override { + for( auto matcher : m_matchers ) { + if (!matcher->match(arg)) + return false; + } + return true; + } + std::string describe() const override { + std::string description; + description.reserve( 4 + m_matchers.size()*32 ); + description += "( "; + bool first = true; + for( auto matcher : m_matchers ) { + if( first ) + first = false; + else + description += " and "; + description += matcher->toString(); + } + description += " )"; + return description; + } + + MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) { + m_matchers.push_back( &other ); + return *this; + } + + std::vector<MatcherBase<ArgT> const*> m_matchers; + }; + template<typename ArgT> + struct MatchAnyOf : MatcherBase<ArgT> { + + bool match( ArgT const& arg ) const override { + for( auto matcher : m_matchers ) { + if (matcher->match(arg)) + return true; + } + return false; + } + std::string describe() const override { + std::string description; + description.reserve( 4 + m_matchers.size()*32 ); + description += "( "; + bool first = true; + for( auto matcher : m_matchers ) { + if( first ) + first = false; + else + description += " or "; + description += matcher->toString(); + } + description += " )"; + return description; + } + + MatchAnyOf<ArgT>& operator || ( MatcherBase<ArgT> const& other ) { + m_matchers.push_back( &other ); + return *this; + } + + std::vector<MatcherBase<ArgT> const*> m_matchers; + }; + + template<typename ArgT> + struct MatchNotOf : MatcherBase<ArgT> { + + MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} + + bool match( ArgT const& arg ) const override { + return !m_underlyingMatcher.match( arg ); + } + + std::string describe() const override { + return "not " + m_underlyingMatcher.toString(); + } + MatcherBase<ArgT> const& m_underlyingMatcher; + }; + + template<typename T> + MatchAllOf<T> MatcherBase<T>::operator && ( MatcherBase const& other ) const { + return MatchAllOf<T>() && *this && other; + } + template<typename T> + MatchAnyOf<T> MatcherBase<T>::operator || ( MatcherBase const& other ) const { + return MatchAnyOf<T>() || *this || other; + } + template<typename T> + MatchNotOf<T> MatcherBase<T>::operator ! () const { + return MatchNotOf<T>( *this ); + } + + } // namespace Impl + +} // namespace Matchers + +using namespace Matchers; +using Matchers::Impl::MatcherBase; + +} // namespace Catch + +// end catch_matchers.h +// start catch_matchers_floating.h + +#include <type_traits> +#include <cmath> + +namespace Catch { +namespace Matchers { + + namespace Floating { + + enum class FloatingPointKind : uint8_t; + + struct WithinAbsMatcher : MatcherBase<double> { + WithinAbsMatcher(double target, double margin); + bool match(double const& matchee) const override; + std::string describe() const override; + private: + double m_target; + double m_margin; + }; + + struct WithinUlpsMatcher : MatcherBase<double> { + WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType); + bool match(double const& matchee) const override; + std::string describe() const override; + private: + double m_target; + int m_ulps; + FloatingPointKind m_type; + }; + + } // namespace Floating + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff); + Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff); + Floating::WithinAbsMatcher WithinAbs(double target, double margin); + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_floating.h +// start catch_matchers_generic.hpp + +#include <functional> +#include <string> + +namespace Catch { +namespace Matchers { +namespace Generic { + +namespace Detail { + std::string finalizeDescription(const std::string& desc); +} + +template <typename T> +class PredicateMatcher : public MatcherBase<T> { + std::function<bool(T const&)> m_predicate; + std::string m_description; +public: + + PredicateMatcher(std::function<bool(T const&)> const& elem, std::string const& descr) + :m_predicate(std::move(elem)), + m_description(Detail::finalizeDescription(descr)) + {} + + bool match( T const& item ) const override { + return m_predicate(item); + } + + std::string describe() const override { + return m_description; + } +}; + +} // namespace Generic + + // The following functions create the actual matcher objects. + // The user has to explicitly specify type to the function, because + // infering std::function<bool(T const&)> is hard (but possible) and + // requires a lot of TMP. + template<typename T> + Generic::PredicateMatcher<T> Predicate(std::function<bool(T const&)> const& predicate, std::string const& description = "") { + return Generic::PredicateMatcher<T>(predicate, description); + } + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_generic.hpp +// start catch_matchers_string.h + +#include <string> + +namespace Catch { +namespace Matchers { + + namespace StdString { + + struct CasedString + { + CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ); + std::string adjustString( std::string const& str ) const; + std::string caseSensitivitySuffix() const; + + CaseSensitive::Choice m_caseSensitivity; + std::string m_str; + }; + + struct StringMatcherBase : MatcherBase<std::string> { + StringMatcherBase( std::string const& operation, CasedString const& comparator ); + std::string describe() const override; + + CasedString m_comparator; + std::string m_operation; + }; + + struct EqualsMatcher : StringMatcherBase { + EqualsMatcher( CasedString const& comparator ); + bool match( std::string const& source ) const override; + }; + struct ContainsMatcher : StringMatcherBase { + ContainsMatcher( CasedString const& comparator ); + bool match( std::string const& source ) const override; + }; + struct StartsWithMatcher : StringMatcherBase { + StartsWithMatcher( CasedString const& comparator ); + bool match( std::string const& source ) const override; + }; + struct EndsWithMatcher : StringMatcherBase { + EndsWithMatcher( CasedString const& comparator ); + bool match( std::string const& source ) const override; + }; + + struct RegexMatcher : MatcherBase<std::string> { + RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity ); + bool match( std::string const& matchee ) const override; + std::string describe() const override; + + private: + std::string m_regex; + CaseSensitive::Choice m_caseSensitivity; + }; + + } // namespace StdString + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + + StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + StdString::RegexMatcher Matches( std::string const& regex, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_string.h +// start catch_matchers_vector.h + +#include <algorithm> + +namespace Catch { +namespace Matchers { + + namespace Vector { + namespace Detail { + template <typename InputIterator, typename T> + size_t count(InputIterator first, InputIterator last, T const& item) { + size_t cnt = 0; + for (; first != last; ++first) { + if (*first == item) { + ++cnt; + } + } + return cnt; + } + template <typename InputIterator, typename T> + bool contains(InputIterator first, InputIterator last, T const& item) { + for (; first != last; ++first) { + if (*first == item) { + return true; + } + } + return false; + } + } + + template<typename T> + struct ContainsElementMatcher : MatcherBase<std::vector<T>> { + + ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} + + bool match(std::vector<T> const &v) const override { + for (auto const& el : v) { + if (el == m_comparator) { + return true; + } + } + return false; + } + + std::string describe() const override { + return "Contains: " + ::Catch::Detail::stringify( m_comparator ); + } + + T const& m_comparator; + }; + + template<typename T> + struct ContainsMatcher : MatcherBase<std::vector<T>> { + + ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {} + + bool match(std::vector<T> const &v) const override { + // !TBD: see note in EqualsMatcher + if (m_comparator.size() > v.size()) + return false; + for (auto const& comparator : m_comparator) { + auto present = false; + for (const auto& el : v) { + if (el == comparator) { + present = true; + break; + } + } + if (!present) { + return false; + } + } + return true; + } + std::string describe() const override { + return "Contains: " + ::Catch::Detail::stringify( m_comparator ); + } + + std::vector<T> const& m_comparator; + }; + + template<typename T> + struct EqualsMatcher : MatcherBase<std::vector<T>> { + + EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {} + + bool match(std::vector<T> const &v) const override { + // !TBD: This currently works if all elements can be compared using != + // - a more general approach would be via a compare template that defaults + // to using !=. but could be specialised for, e.g. std::vector<T> etc + // - then just call that directly + if (m_comparator.size() != v.size()) + return false; + for (std::size_t i = 0; i < v.size(); ++i) + if (m_comparator[i] != v[i]) + return false; + return true; + } + std::string describe() const override { + return "Equals: " + ::Catch::Detail::stringify( m_comparator ); + } + std::vector<T> const& m_comparator; + }; + + template<typename T> + struct UnorderedEqualsMatcher : MatcherBase<std::vector<T>> { + UnorderedEqualsMatcher(std::vector<T> const& target) : m_target(target) {} + bool match(std::vector<T> const& vec) const override { + // Note: This is a reimplementation of std::is_permutation, + // because I don't want to include <algorithm> inside the common path + if (m_target.size() != vec.size()) { + return false; + } + auto lfirst = m_target.begin(), llast = m_target.end(); + auto rfirst = vec.begin(), rlast = vec.end(); + // Cut common prefix to optimize checking of permuted parts + while (lfirst != llast && *lfirst != *rfirst) { + ++lfirst; ++rfirst; + } + if (lfirst == llast) { + return true; + } + + for (auto mid = lfirst; mid != llast; ++mid) { + // Skip already counted items + if (Detail::contains(lfirst, mid, *mid)) { + continue; + } + size_t num_vec = Detail::count(rfirst, rlast, *mid); + if (num_vec == 0 || Detail::count(lfirst, llast, *mid) != num_vec) { + return false; + } + } + + return true; + } + + std::string describe() const override { + return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); + } + private: + std::vector<T> const& m_target; + }; + + } // namespace Vector + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + + template<typename T> + Vector::ContainsMatcher<T> Contains( std::vector<T> const& comparator ) { + return Vector::ContainsMatcher<T>( comparator ); + } + + template<typename T> + Vector::ContainsElementMatcher<T> VectorContains( T const& comparator ) { + return Vector::ContainsElementMatcher<T>( comparator ); + } + + template<typename T> + Vector::EqualsMatcher<T> Equals( std::vector<T> const& comparator ) { + return Vector::EqualsMatcher<T>( comparator ); + } + + template<typename T> + Vector::UnorderedEqualsMatcher<T> UnorderedEquals(std::vector<T> const& target) { + return Vector::UnorderedEqualsMatcher<T>(target); + } + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_vector.h +namespace Catch { + + template<typename ArgT, typename MatcherT> + class MatchExpr : public ITransientExpression { + ArgT const& m_arg; + MatcherT m_matcher; + StringRef m_matcherString; + public: + MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) + : ITransientExpression{ true, matcher.match( arg ) }, + m_arg( arg ), + m_matcher( matcher ), + m_matcherString( matcherString ) + {} + + void streamReconstructedExpression( std::ostream &os ) const override { + auto matcherAsString = m_matcher.toString(); + os << Catch::Detail::stringify( m_arg ) << ' '; + if( matcherAsString == Detail::unprintableString ) + os << m_matcherString; + else + os << matcherAsString; + } + }; + + using StringMatcher = Matchers::Impl::MatcherBase<std::string>; + + void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ); + + template<typename ArgT, typename MatcherT> + auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) -> MatchExpr<ArgT, MatcherT> { + return MatchExpr<ArgT, MatcherT>( arg, matcher, matcherString ); + } + +} // namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ + INTERNAL_CATCH_TRY { \ + catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \ + } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ + if( catchAssertionHandler.allowThrows() ) \ + try { \ + static_cast<void>(__VA_ARGS__ ); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ + } \ + catch( exceptionType const& ex ) { \ + catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \ + } \ + catch( ... ) { \ + catchAssertionHandler.handleUnexpectedInflightException(); \ + } \ + else \ + catchAssertionHandler.handleThrowingCallSkipped(); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) + +// end catch_capture_matchers.h +#endif + +// These files are included here so the single_include script doesn't put them +// in the conditionally compiled sections +// start catch_test_case_info.h + +#include <string> +#include <vector> +#include <memory> + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + struct ITestInvoker; + + struct TestCaseInfo { + enum SpecialProperties{ + None = 0, + IsHidden = 1 << 1, + ShouldFail = 1 << 2, + MayFail = 1 << 3, + Throws = 1 << 4, + NonPortable = 1 << 5, + Benchmark = 1 << 6 + }; + + TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::vector<std::string> const& _tags, + SourceLineInfo const& _lineInfo ); + + friend void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags ); + + bool isHidden() const; + bool throws() const; + bool okToFail() const; + bool expectedToFail() const; + + std::string tagsAsString() const; + + std::string name; + std::string className; + std::string description; + std::vector<std::string> tags; + std::vector<std::string> lcaseTags; + SourceLineInfo lineInfo; + SpecialProperties properties; + }; + + class TestCase : public TestCaseInfo { + public: + + TestCase( ITestInvoker* testCase, TestCaseInfo&& info ); + + TestCase withName( std::string const& _newName ) const; + + void invoke() const; + + TestCaseInfo const& getTestCaseInfo() const; + + bool operator == ( TestCase const& other ) const; + bool operator < ( TestCase const& other ) const; + + private: + std::shared_ptr<ITestInvoker> test; + }; + + TestCase makeTestCase( ITestInvoker* testCase, + std::string const& className, + NameAndTags const& nameAndTags, + SourceLineInfo const& lineInfo ); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// end catch_test_case_info.h +// start catch_interfaces_runner.h + +namespace Catch { + + struct IRunner { + virtual ~IRunner(); + virtual bool aborting() const = 0; + }; +} + +// end catch_interfaces_runner.h + +#ifdef __OBJC__ +// start catch_objc.hpp + +#import <objc/runtime.h> + +#include <string> + +// NB. Any general catch headers included here must be included +// in catch.hpp first to make sure they are included by the single +// header for non obj-usage + +/////////////////////////////////////////////////////////////////////////////// +// This protocol is really only here for (self) documenting purposes, since +// all its methods are optional. +@protocol OcFixture + +@optional + +-(void) setUp; +-(void) tearDown; + +@end + +namespace Catch { + + class OcMethod : public ITestInvoker { + + public: + OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} + + virtual void invoke() const { + id obj = [[m_cls alloc] init]; + + performOptionalSelector( obj, @selector(setUp) ); + performOptionalSelector( obj, m_sel ); + performOptionalSelector( obj, @selector(tearDown) ); + + arcSafeRelease( obj ); + } + private: + virtual ~OcMethod() {} + + Class m_cls; + SEL m_sel; + }; + + namespace Detail{ + + inline std::string getAnnotation( Class cls, + std::string const& annotationName, + std::string const& testCaseName ) { + NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; + SEL sel = NSSelectorFromString( selStr ); + arcSafeRelease( selStr ); + id value = performOptionalSelector( cls, sel ); + if( value ) + return [(NSString*)value UTF8String]; + return ""; + } + } + + inline std::size_t registerTestMethods() { + std::size_t noTestMethods = 0; + int noClasses = objc_getClassList( nullptr, 0 ); + + Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); + objc_getClassList( classes, noClasses ); + + for( int c = 0; c < noClasses; c++ ) { + Class cls = classes[c]; + { + u_int count; + Method* methods = class_copyMethodList( cls, &count ); + for( u_int m = 0; m < count ; m++ ) { + SEL selector = method_getName(methods[m]); + std::string methodName = sel_getName(selector); + if( startsWith( methodName, "Catch_TestCase_" ) ) { + std::string testCaseName = methodName.substr( 15 ); + std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); + std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); + const char* className = class_getName( cls ); + + getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, NameAndTags( name.c_str(), desc.c_str() ), SourceLineInfo("",0) ) ); + noTestMethods++; + } + } + free(methods); + } + } + return noTestMethods; + } + +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) + + namespace Matchers { + namespace Impl { + namespace NSStringMatchers { + + struct StringHolder : MatcherBase<NSString*>{ + StringHolder( NSString* substr ) : m_substr( [substr copy] ){} + StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} + StringHolder() { + arcSafeRelease( m_substr ); + } + + bool match( NSString* arg ) const override { + return false; + } + + NSString* CATCH_ARC_STRONG m_substr; + }; + + struct Equals : StringHolder { + Equals( NSString* substr ) : StringHolder( substr ){} + + bool match( NSString* str ) const override { + return (str != nil || m_substr == nil ) && + [str isEqualToString:m_substr]; + } + + std::string describe() const override { + return "equals string: " + Catch::Detail::stringify( m_substr ); + } + }; + + struct Contains : StringHolder { + Contains( NSString* substr ) : StringHolder( substr ){} + + bool match( NSString* str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location != NSNotFound; + } + + std::string describe() const override { + return "contains string: " + Catch::Detail::stringify( m_substr ); + } + }; + + struct StartsWith : StringHolder { + StartsWith( NSString* substr ) : StringHolder( substr ){} + + bool match( NSString* str ) const override { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == 0; + } + + std::string describe() const override { + return "starts with: " + Catch::Detail::stringify( m_substr ); + } + }; + struct EndsWith : StringHolder { + EndsWith( NSString* substr ) : StringHolder( substr ){} + + bool match( NSString* str ) const override { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == [str length] - [m_substr length]; + } + + std::string describe() const override { + return "ends with: " + Catch::Detail::stringify( m_substr ); + } + }; + + } // namespace NSStringMatchers + } // namespace Impl + + inline Impl::NSStringMatchers::Equals + Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } + + inline Impl::NSStringMatchers::Contains + Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } + + inline Impl::NSStringMatchers::StartsWith + StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } + + inline Impl::NSStringMatchers::EndsWith + EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } + + } // namespace Matchers + + using namespace Matchers; + +#endif // CATCH_CONFIG_DISABLE_MATCHERS + +} // namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define OC_MAKE_UNIQUE_NAME( root, uniqueSuffix ) root##uniqueSuffix +#define OC_TEST_CASE2( name, desc, uniqueSuffix ) \ ++(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Name_test_, uniqueSuffix ) \ +{ \ +return @ name; \ +} \ ++(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Description_test_, uniqueSuffix ) \ +{ \ +return @ desc; \ +} \ +-(void) OC_MAKE_UNIQUE_NAME( Catch_TestCase_test_, uniqueSuffix ) + +#define OC_TEST_CASE( name, desc ) OC_TEST_CASE2( name, desc, __LINE__ ) + +// end catch_objc.hpp +#endif + +#ifdef CATCH_CONFIG_EXTERNAL_INTERFACES +// start catch_external_interfaces.h + +// start catch_reporter_bases.hpp + +// start catch_interfaces_reporter.h + +// start catch_config.hpp + +// start catch_test_spec_parser.h + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// start catch_test_spec.h + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// start catch_wildcard_pattern.h + +namespace Catch +{ + class WildcardPattern { + enum WildcardPosition { + NoWildcard = 0, + WildcardAtStart = 1, + WildcardAtEnd = 2, + WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd + }; + + public: + + WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ); + virtual ~WildcardPattern() = default; + virtual bool matches( std::string const& str ) const; + + private: + std::string adjustCase( std::string const& str ) const; + CaseSensitive::Choice m_caseSensitivity; + WildcardPosition m_wildcard = NoWildcard; + std::string m_pattern; + }; +} + +// end catch_wildcard_pattern.h +#include <string> +#include <vector> +#include <memory> + +namespace Catch { + + class TestSpec { + struct Pattern { + virtual ~Pattern(); + virtual bool matches( TestCaseInfo const& testCase ) const = 0; + }; + using PatternPtr = std::shared_ptr<Pattern>; + + class NamePattern : public Pattern { + public: + NamePattern( std::string const& name ); + virtual ~NamePattern(); + virtual bool matches( TestCaseInfo const& testCase ) const override; + private: + WildcardPattern m_wildcardPattern; + }; + + class TagPattern : public Pattern { + public: + TagPattern( std::string const& tag ); + virtual ~TagPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const override; + private: + std::string m_tag; + }; + + class ExcludedPattern : public Pattern { + public: + ExcludedPattern( PatternPtr const& underlyingPattern ); + virtual ~ExcludedPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const override; + private: + PatternPtr m_underlyingPattern; + }; + + struct Filter { + std::vector<PatternPtr> m_patterns; + + bool matches( TestCaseInfo const& testCase ) const; + }; + + public: + bool hasFilters() const; + bool matches( TestCaseInfo const& testCase ) const; + + private: + std::vector<Filter> m_filters; + + friend class TestSpecParser; + }; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// end catch_test_spec.h +// start catch_interfaces_tag_alias_registry.h + +#include <string> + +namespace Catch { + + struct TagAlias; + + struct ITagAliasRegistry { + virtual ~ITagAliasRegistry(); + // Nullptr if not present + virtual TagAlias const* find( std::string const& alias ) const = 0; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; + + static ITagAliasRegistry const& get(); + }; + +} // end namespace Catch + +// end catch_interfaces_tag_alias_registry.h +namespace Catch { + + class TestSpecParser { + enum Mode{ None, Name, QuotedName, Tag, EscapedName }; + Mode m_mode = None; + bool m_exclusion = false; + std::size_t m_start = std::string::npos, m_pos = 0; + std::string m_arg; + std::vector<std::size_t> m_escapeChars; + TestSpec::Filter m_currentFilter; + TestSpec m_testSpec; + ITagAliasRegistry const* m_tagAliases = nullptr; + + public: + TestSpecParser( ITagAliasRegistry const& tagAliases ); + + TestSpecParser& parse( std::string const& arg ); + TestSpec testSpec(); + + private: + void visitChar( char c ); + void startNewMode( Mode mode, std::size_t start ); + void escape(); + std::string subString() const; + + template<typename T> + void addPattern() { + std::string token = subString(); + for( std::size_t i = 0; i < m_escapeChars.size(); ++i ) + token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 ); + m_escapeChars.clear(); + if( startsWith( token, "exclude:" ) ) { + m_exclusion = true; + token = token.substr( 8 ); + } + if( !token.empty() ) { + TestSpec::PatternPtr pattern = std::make_shared<T>( token ); + if( m_exclusion ) + pattern = std::make_shared<TestSpec::ExcludedPattern>( pattern ); + m_currentFilter.m_patterns.push_back( pattern ); + } + m_exclusion = false; + m_mode = None; + } + + void addFilter(); + }; + TestSpec parseTestSpec( std::string const& arg ); + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// end catch_test_spec_parser.h +// start catch_interfaces_config.h + +#include <iosfwd> +#include <string> +#include <vector> +#include <memory> + +namespace Catch { + + enum class Verbosity { + Quiet = 0, + Normal, + High + }; + + struct WarnAbout { enum What { + Nothing = 0x00, + NoAssertions = 0x01, + NoTests = 0x02 + }; }; + + struct ShowDurations { enum OrNot { + DefaultForReporter, + Always, + Never + }; }; + struct RunTests { enum InWhatOrder { + InDeclarationOrder, + InLexicographicalOrder, + InRandomOrder + }; }; + struct UseColour { enum YesOrNo { + Auto, + Yes, + No + }; }; + struct WaitForKeypress { enum When { + Never, + BeforeStart = 1, + BeforeExit = 2, + BeforeStartAndExit = BeforeStart | BeforeExit + }; }; + + class TestSpec; + + struct IConfig : NonCopyable { + + virtual ~IConfig(); + + virtual bool allowThrows() const = 0; + virtual std::ostream& stream() const = 0; + virtual std::string name() const = 0; + virtual bool includeSuccessfulResults() const = 0; + virtual bool shouldDebugBreak() const = 0; + virtual bool warnAboutMissingAssertions() const = 0; + virtual bool warnAboutNoTests() const = 0; + virtual int abortAfter() const = 0; + virtual bool showInvisibles() const = 0; + virtual ShowDurations::OrNot showDurations() const = 0; + virtual TestSpec const& testSpec() const = 0; + virtual bool hasTestFilters() const = 0; + virtual RunTests::InWhatOrder runOrder() const = 0; + virtual unsigned int rngSeed() const = 0; + virtual int benchmarkResolutionMultiple() const = 0; + virtual UseColour::YesOrNo useColour() const = 0; + virtual std::vector<std::string> const& getSectionsToRun() const = 0; + virtual Verbosity verbosity() const = 0; + }; + + using IConfigPtr = std::shared_ptr<IConfig const>; +} + +// end catch_interfaces_config.h +// Libstdc++ doesn't like incomplete classes for unique_ptr + +#include <memory> +#include <vector> +#include <string> + +#ifndef CATCH_CONFIG_CONSOLE_WIDTH +#define CATCH_CONFIG_CONSOLE_WIDTH 80 +#endif + +namespace Catch { + + struct IStream; + + struct ConfigData { + bool listTests = false; + bool listTags = false; + bool listReporters = false; + bool listTestNamesOnly = false; + + bool showSuccessfulTests = false; + bool shouldDebugBreak = false; + bool noThrow = false; + bool showHelp = false; + bool showInvisibles = false; + bool filenamesAsTags = false; + bool libIdentify = false; + + int abortAfter = -1; + unsigned int rngSeed = 0; + int benchmarkResolutionMultiple = 100; + + Verbosity verbosity = Verbosity::Normal; + WarnAbout::What warnings = WarnAbout::Nothing; + ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter; + RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder; + UseColour::YesOrNo useColour = UseColour::Auto; + WaitForKeypress::When waitForKeypress = WaitForKeypress::Never; + + std::string outputFilename; + std::string name; + std::string processName; +#ifndef CATCH_CONFIG_DEFAULT_REPORTER +#define CATCH_CONFIG_DEFAULT_REPORTER "console" +#endif + std::string reporterName = CATCH_CONFIG_DEFAULT_REPORTER; +#undef CATCH_CONFIG_DEFAULT_REPORTER + + std::vector<std::string> testsOrTags; + std::vector<std::string> sectionsToRun; + }; + + class Config : public IConfig { + public: + + Config() = default; + Config( ConfigData const& data ); + virtual ~Config() = default; + + std::string const& getFilename() const; + + bool listTests() const; + bool listTestNamesOnly() const; + bool listTags() const; + bool listReporters() const; + + std::string getProcessName() const; + std::string const& getReporterName() const; + + std::vector<std::string> const& getTestsOrTags() const; + std::vector<std::string> const& getSectionsToRun() const override; + + virtual TestSpec const& testSpec() const override; + bool hasTestFilters() const override; + + bool showHelp() const; + + // IConfig interface + bool allowThrows() const override; + std::ostream& stream() const override; + std::string name() const override; + bool includeSuccessfulResults() const override; + bool warnAboutMissingAssertions() const override; + bool warnAboutNoTests() const override; + ShowDurations::OrNot showDurations() const override; + RunTests::InWhatOrder runOrder() const override; + unsigned int rngSeed() const override; + int benchmarkResolutionMultiple() const override; + UseColour::YesOrNo useColour() const override; + bool shouldDebugBreak() const override; + int abortAfter() const override; + bool showInvisibles() const override; + Verbosity verbosity() const override; + + private: + + IStream const* openStream(); + ConfigData m_data; + + std::unique_ptr<IStream const> m_stream; + TestSpec m_testSpec; + bool m_hasTestFilters = false; + }; + +} // end namespace Catch + +// end catch_config.hpp +// start catch_assertionresult.h + +#include <string> + +namespace Catch { + + struct AssertionResultData + { + AssertionResultData() = delete; + + AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ); + + std::string message; + mutable std::string reconstructedExpression; + LazyExpression lazyExpression; + ResultWas::OfType resultType; + + std::string reconstructExpression() const; + }; + + class AssertionResult { + public: + AssertionResult() = delete; + AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); + + bool isOk() const; + bool succeeded() const; + ResultWas::OfType getResultType() const; + bool hasExpression() const; + bool hasMessage() const; + std::string getExpression() const; + std::string getExpressionInMacro() const; + bool hasExpandedExpression() const; + std::string getExpandedExpression() const; + std::string getMessage() const; + SourceLineInfo getSourceInfo() const; + StringRef getTestMacroName() const; + + //protected: + AssertionInfo m_info; + AssertionResultData m_resultData; + }; + +} // end namespace Catch + +// end catch_assertionresult.h +// start catch_option.hpp + +namespace Catch { + + // An optional type + template<typename T> + class Option { + public: + Option() : nullableValue( nullptr ) {} + Option( T const& _value ) + : nullableValue( new( storage ) T( _value ) ) + {} + Option( Option const& _other ) + : nullableValue( _other ? new( storage ) T( *_other ) : nullptr ) + {} + + ~Option() { + reset(); + } + + Option& operator= ( Option const& _other ) { + if( &_other != this ) { + reset(); + if( _other ) + nullableValue = new( storage ) T( *_other ); + } + return *this; + } + Option& operator = ( T const& _value ) { + reset(); + nullableValue = new( storage ) T( _value ); + return *this; + } + + void reset() { + if( nullableValue ) + nullableValue->~T(); + nullableValue = nullptr; + } + + T& operator*() { return *nullableValue; } + T const& operator*() const { return *nullableValue; } + T* operator->() { return nullableValue; } + const T* operator->() const { return nullableValue; } + + T valueOr( T const& defaultValue ) const { + return nullableValue ? *nullableValue : defaultValue; + } + + bool some() const { return nullableValue != nullptr; } + bool none() const { return nullableValue == nullptr; } + + bool operator !() const { return nullableValue == nullptr; } + explicit operator bool() const { + return some(); + } + + private: + T *nullableValue; + alignas(alignof(T)) char storage[sizeof(T)]; + }; + +} // end namespace Catch + +// end catch_option.hpp +#include <string> +#include <iosfwd> +#include <map> +#include <set> +#include <memory> + +namespace Catch { + + struct ReporterConfig { + explicit ReporterConfig( IConfigPtr const& _fullConfig ); + + ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ); + + std::ostream& stream() const; + IConfigPtr fullConfig() const; + + private: + std::ostream* m_stream; + IConfigPtr m_fullConfig; + }; + + struct ReporterPreferences { + bool shouldRedirectStdOut = false; + bool shouldReportAllAssertions = false; + }; + + template<typename T> + struct LazyStat : Option<T> { + LazyStat& operator=( T const& _value ) { + Option<T>::operator=( _value ); + used = false; + return *this; + } + void reset() { + Option<T>::reset(); + used = false; + } + bool used = false; + }; + + struct TestRunInfo { + TestRunInfo( std::string const& _name ); + std::string name; + }; + struct GroupInfo { + GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ); + + std::string name; + std::size_t groupIndex; + std::size_t groupsCounts; + }; + + struct AssertionStats { + AssertionStats( AssertionResult const& _assertionResult, + std::vector<MessageInfo> const& _infoMessages, + Totals const& _totals ); + + AssertionStats( AssertionStats const& ) = default; + AssertionStats( AssertionStats && ) = default; + AssertionStats& operator = ( AssertionStats const& ) = default; + AssertionStats& operator = ( AssertionStats && ) = default; + virtual ~AssertionStats(); + + AssertionResult assertionResult; + std::vector<MessageInfo> infoMessages; + Totals totals; + }; + + struct SectionStats { + SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ); + SectionStats( SectionStats const& ) = default; + SectionStats( SectionStats && ) = default; + SectionStats& operator = ( SectionStats const& ) = default; + SectionStats& operator = ( SectionStats && ) = default; + virtual ~SectionStats(); + + SectionInfo sectionInfo; + Counts assertions; + double durationInSeconds; + bool missingAssertions; + }; + + struct TestCaseStats { + TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ); + + TestCaseStats( TestCaseStats const& ) = default; + TestCaseStats( TestCaseStats && ) = default; + TestCaseStats& operator = ( TestCaseStats const& ) = default; + TestCaseStats& operator = ( TestCaseStats && ) = default; + virtual ~TestCaseStats(); + + TestCaseInfo testInfo; + Totals totals; + std::string stdOut; + std::string stdErr; + bool aborting; + }; + + struct TestGroupStats { + TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ); + TestGroupStats( GroupInfo const& _groupInfo ); + + TestGroupStats( TestGroupStats const& ) = default; + TestGroupStats( TestGroupStats && ) = default; + TestGroupStats& operator = ( TestGroupStats const& ) = default; + TestGroupStats& operator = ( TestGroupStats && ) = default; + virtual ~TestGroupStats(); + + GroupInfo groupInfo; + Totals totals; + bool aborting; + }; + + struct TestRunStats { + TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ); + + TestRunStats( TestRunStats const& ) = default; + TestRunStats( TestRunStats && ) = default; + TestRunStats& operator = ( TestRunStats const& ) = default; + TestRunStats& operator = ( TestRunStats && ) = default; + virtual ~TestRunStats(); + + TestRunInfo runInfo; + Totals totals; + bool aborting; + }; + + struct BenchmarkInfo { + std::string name; + }; + struct BenchmarkStats { + BenchmarkInfo info; + std::size_t iterations; + uint64_t elapsedTimeInNanoseconds; + }; + + struct IStreamingReporter { + virtual ~IStreamingReporter() = default; + + // Implementing class must also provide the following static methods: + // static std::string getDescription(); + // static std::set<Verbosity> getSupportedVerbosities() + + virtual ReporterPreferences getPreferences() const = 0; + + virtual void noMatchingTestCases( std::string const& spec ) = 0; + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; + virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; + virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; + + // *** experimental *** + virtual void benchmarkStarting( BenchmarkInfo const& ) {} + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + + // *** experimental *** + virtual void benchmarkEnded( BenchmarkStats const& ) {} + + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; + virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; + + virtual void skipTest( TestCaseInfo const& testInfo ) = 0; + + // Default empty implementation provided + virtual void fatalErrorEncountered( StringRef name ); + + virtual bool isMulti() const; + }; + using IStreamingReporterPtr = std::unique_ptr<IStreamingReporter>; + + struct IReporterFactory { + virtual ~IReporterFactory(); + virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0; + virtual std::string getDescription() const = 0; + }; + using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>; + + struct IReporterRegistry { + using FactoryMap = std::map<std::string, IReporterFactoryPtr>; + using Listeners = std::vector<IReporterFactoryPtr>; + + virtual ~IReporterRegistry(); + virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0; + virtual FactoryMap const& getFactories() const = 0; + virtual Listeners const& getListeners() const = 0; + }; + +} // end namespace Catch + +// end catch_interfaces_reporter.h +#include <algorithm> +#include <cstring> +#include <cfloat> +#include <cstdio> +#include <cassert> +#include <memory> +#include <ostream> + +namespace Catch { + void prepareExpandedExpression(AssertionResult& result); + + // Returns double formatted as %.3f (format expected on output) + std::string getFormattedDuration( double duration ); + + template<typename DerivedT> + struct StreamingReporterBase : IStreamingReporter { + + StreamingReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) + throw std::domain_error( "Verbosity level not supported by this reporter" ); + } + + ReporterPreferences getPreferences() const override { + return m_reporterPrefs; + } + + static std::set<Verbosity> getSupportedVerbosities() { + return { Verbosity::Normal }; + } + + ~StreamingReporterBase() override = default; + + void noMatchingTestCases(std::string const&) override {} + + void testRunStarting(TestRunInfo const& _testRunInfo) override { + currentTestRunInfo = _testRunInfo; + } + void testGroupStarting(GroupInfo const& _groupInfo) override { + currentGroupInfo = _groupInfo; + } + + void testCaseStarting(TestCaseInfo const& _testInfo) override { + currentTestCaseInfo = _testInfo; + } + void sectionStarting(SectionInfo const& _sectionInfo) override { + m_sectionStack.push_back(_sectionInfo); + } + + void sectionEnded(SectionStats const& /* _sectionStats */) override { + m_sectionStack.pop_back(); + } + void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override { + currentTestCaseInfo.reset(); + } + void testGroupEnded(TestGroupStats const& /* _testGroupStats */) override { + currentGroupInfo.reset(); + } + void testRunEnded(TestRunStats const& /* _testRunStats */) override { + currentTestCaseInfo.reset(); + currentGroupInfo.reset(); + currentTestRunInfo.reset(); + } + + void skipTest(TestCaseInfo const&) override { + // Don't do anything with this by default. + // It can optionally be overridden in the derived class. + } + + IConfigPtr m_config; + std::ostream& stream; + + LazyStat<TestRunInfo> currentTestRunInfo; + LazyStat<GroupInfo> currentGroupInfo; + LazyStat<TestCaseInfo> currentTestCaseInfo; + + std::vector<SectionInfo> m_sectionStack; + ReporterPreferences m_reporterPrefs; + }; + + template<typename DerivedT> + struct CumulativeReporterBase : IStreamingReporter { + template<typename T, typename ChildNodeT> + struct Node { + explicit Node( T const& _value ) : value( _value ) {} + virtual ~Node() {} + + using ChildNodes = std::vector<std::shared_ptr<ChildNodeT>>; + T value; + ChildNodes children; + }; + struct SectionNode { + explicit SectionNode(SectionStats const& _stats) : stats(_stats) {} + virtual ~SectionNode() = default; + + bool operator == (SectionNode const& other) const { + return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; + } + bool operator == (std::shared_ptr<SectionNode> const& other) const { + return operator==(*other); + } + + SectionStats stats; + using ChildSections = std::vector<std::shared_ptr<SectionNode>>; + using Assertions = std::vector<AssertionStats>; + ChildSections childSections; + Assertions assertions; + std::string stdOut; + std::string stdErr; + }; + + struct BySectionInfo { + BySectionInfo( SectionInfo const& other ) : m_other( other ) {} + BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} + bool operator() (std::shared_ptr<SectionNode> const& node) const { + return ((node->stats.sectionInfo.name == m_other.name) && + (node->stats.sectionInfo.lineInfo == m_other.lineInfo)); + } + void operator=(BySectionInfo const&) = delete; + + private: + SectionInfo const& m_other; + }; + + using TestCaseNode = Node<TestCaseStats, SectionNode>; + using TestGroupNode = Node<TestGroupStats, TestCaseNode>; + using TestRunNode = Node<TestRunStats, TestGroupNode>; + + CumulativeReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) + throw std::domain_error( "Verbosity level not supported by this reporter" ); + } + ~CumulativeReporterBase() override = default; + + ReporterPreferences getPreferences() const override { + return m_reporterPrefs; + } + + static std::set<Verbosity> getSupportedVerbosities() { + return { Verbosity::Normal }; + } + + void testRunStarting( TestRunInfo const& ) override {} + void testGroupStarting( GroupInfo const& ) override {} + + void testCaseStarting( TestCaseInfo const& ) override {} + + void sectionStarting( SectionInfo const& sectionInfo ) override { + SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); + std::shared_ptr<SectionNode> node; + if( m_sectionStack.empty() ) { + if( !m_rootSection ) + m_rootSection = std::make_shared<SectionNode>( incompleteStats ); + node = m_rootSection; + } + else { + SectionNode& parentNode = *m_sectionStack.back(); + auto it = + std::find_if( parentNode.childSections.begin(), + parentNode.childSections.end(), + BySectionInfo( sectionInfo ) ); + if( it == parentNode.childSections.end() ) { + node = std::make_shared<SectionNode>( incompleteStats ); + parentNode.childSections.push_back( node ); + } + else + node = *it; + } + m_sectionStack.push_back( node ); + m_deepestSection = std::move(node); + } + + void assertionStarting(AssertionInfo const&) override {} + + bool assertionEnded(AssertionStats const& assertionStats) override { + assert(!m_sectionStack.empty()); + // AssertionResult holds a pointer to a temporary DecomposedExpression, + // which getExpandedExpression() calls to build the expression string. + // Our section stack copy of the assertionResult will likely outlive the + // temporary, so it must be expanded or discarded now to avoid calling + // a destroyed object later. + prepareExpandedExpression(const_cast<AssertionResult&>( assertionStats.assertionResult ) ); + SectionNode& sectionNode = *m_sectionStack.back(); + sectionNode.assertions.push_back(assertionStats); + return true; + } + void sectionEnded(SectionStats const& sectionStats) override { + assert(!m_sectionStack.empty()); + SectionNode& node = *m_sectionStack.back(); + node.stats = sectionStats; + m_sectionStack.pop_back(); + } + void testCaseEnded(TestCaseStats const& testCaseStats) override { + auto node = std::make_shared<TestCaseNode>(testCaseStats); + assert(m_sectionStack.size() == 0); + node->children.push_back(m_rootSection); + m_testCases.push_back(node); + m_rootSection.reset(); + + assert(m_deepestSection); + m_deepestSection->stdOut = testCaseStats.stdOut; + m_deepestSection->stdErr = testCaseStats.stdErr; + } + void testGroupEnded(TestGroupStats const& testGroupStats) override { + auto node = std::make_shared<TestGroupNode>(testGroupStats); + node->children.swap(m_testCases); + m_testGroups.push_back(node); + } + void testRunEnded(TestRunStats const& testRunStats) override { + auto node = std::make_shared<TestRunNode>(testRunStats); + node->children.swap(m_testGroups); + m_testRuns.push_back(node); + testRunEndedCumulative(); + } + virtual void testRunEndedCumulative() = 0; + + void skipTest(TestCaseInfo const&) override {} + + IConfigPtr m_config; + std::ostream& stream; + std::vector<AssertionStats> m_assertions; + std::vector<std::vector<std::shared_ptr<SectionNode>>> m_sections; + std::vector<std::shared_ptr<TestCaseNode>> m_testCases; + std::vector<std::shared_ptr<TestGroupNode>> m_testGroups; + + std::vector<std::shared_ptr<TestRunNode>> m_testRuns; + + std::shared_ptr<SectionNode> m_rootSection; + std::shared_ptr<SectionNode> m_deepestSection; + std::vector<std::shared_ptr<SectionNode>> m_sectionStack; + ReporterPreferences m_reporterPrefs; + }; + + template<char C> + char const* getLineOfChars() { + static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; + if( !*line ) { + std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); + line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; + } + return line; + } + + struct TestEventListenerBase : StreamingReporterBase<TestEventListenerBase> { + TestEventListenerBase( ReporterConfig const& _config ); + + void assertionStarting(AssertionInfo const&) override; + bool assertionEnded(AssertionStats const&) override; + }; + +} // end namespace Catch + +// end catch_reporter_bases.hpp +// start catch_console_colour.h + +namespace Catch { + + struct Colour { + enum Code { + None = 0, + + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White, + BrightYellow = Bright | Yellow, + + // By intention + FileName = LightGrey, + Warning = BrightYellow, + ResultError = BrightRed, + ResultSuccess = BrightGreen, + ResultExpectedFailure = Warning, + + Error = BrightRed, + Success = Green, + + OriginalExpression = Cyan, + ReconstructedExpression = BrightYellow, + + SecondaryText = LightGrey, + Headers = White + }; + + // Use constructed object for RAII guard + Colour( Code _colourCode ); + Colour( Colour&& other ) noexcept; + Colour& operator=( Colour&& other ) noexcept; + ~Colour(); + + // Use static method for one-shot changes + static void use( Code _colourCode ); + + private: + bool m_moved = false; + }; + + std::ostream& operator << ( std::ostream& os, Colour const& ); + +} // end namespace Catch + +// end catch_console_colour.h +// start catch_reporter_registrars.hpp + + +namespace Catch { + + template<typename T> + class ReporterRegistrar { + + class ReporterFactory : public IReporterFactory { + + virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { + return std::unique_ptr<T>( new T( config ) ); + } + + virtual std::string getDescription() const override { + return T::getDescription(); + } + }; + + public: + + explicit ReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, std::make_shared<ReporterFactory>() ); + } + }; + + template<typename T> + class ListenerRegistrar { + + class ListenerFactory : public IReporterFactory { + + virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { + return std::unique_ptr<T>( new T( config ) ); + } + virtual std::string getDescription() const override { + return std::string(); + } + }; + + public: + + ListenerRegistrar() { + getMutableRegistryHub().registerListener( std::make_shared<ListenerFactory>() ); + } + }; +} + +#if !defined(CATCH_CONFIG_DISABLE) + +#define CATCH_REGISTER_REPORTER( name, reporterType ) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS + +#define CATCH_REGISTER_LISTENER( listenerType ) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS +#else // CATCH_CONFIG_DISABLE + +#define CATCH_REGISTER_REPORTER(name, reporterType) +#define CATCH_REGISTER_LISTENER(listenerType) + +#endif // CATCH_CONFIG_DISABLE + +// end catch_reporter_registrars.hpp +// Allow users to base their work off existing reporters +// start catch_reporter_compact.h + +namespace Catch { + + struct CompactReporter : StreamingReporterBase<CompactReporter> { + + using StreamingReporterBase::StreamingReporterBase; + + ~CompactReporter() override; + + static std::string getDescription(); + + ReporterPreferences getPreferences() const override; + + void noMatchingTestCases(std::string const& spec) override; + + void assertionStarting(AssertionInfo const&) override; + + bool assertionEnded(AssertionStats const& _assertionStats) override; + + void sectionEnded(SectionStats const& _sectionStats) override; + + void testRunEnded(TestRunStats const& _testRunStats) override; + + }; + +} // end namespace Catch + +// end catch_reporter_compact.h +// start catch_reporter_console.h + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch + // Note that 4062 (not all labels are handled + // and default is missing) is enabled +#endif + +namespace Catch { + // Fwd decls + struct SummaryColumn; + class TablePrinter; + + struct ConsoleReporter : StreamingReporterBase<ConsoleReporter> { + std::unique_ptr<TablePrinter> m_tablePrinter; + + ConsoleReporter(ReporterConfig const& config); + ~ConsoleReporter() override; + static std::string getDescription(); + + void noMatchingTestCases(std::string const& spec) override; + + void assertionStarting(AssertionInfo const&) override; + + bool assertionEnded(AssertionStats const& _assertionStats) override; + + void sectionStarting(SectionInfo const& _sectionInfo) override; + void sectionEnded(SectionStats const& _sectionStats) override; + + void benchmarkStarting(BenchmarkInfo const& info) override; + void benchmarkEnded(BenchmarkStats const& stats) override; + + void testCaseEnded(TestCaseStats const& _testCaseStats) override; + void testGroupEnded(TestGroupStats const& _testGroupStats) override; + void testRunEnded(TestRunStats const& _testRunStats) override; + + private: + + void lazyPrint(); + + void lazyPrintWithoutClosingBenchmarkTable(); + void lazyPrintRunInfo(); + void lazyPrintGroupInfo(); + void printTestCaseAndSectionHeader(); + + void printClosedHeader(std::string const& _name); + void printOpenHeader(std::string const& _name); + + // if string has a : in first line will set indent to follow it on + // subsequent lines + void printHeaderString(std::string const& _string, std::size_t indent = 0); + + void printTotals(Totals const& totals); + void printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row); + + void printTotalsDivider(Totals const& totals); + void printSummaryDivider(); + + private: + bool m_headerPrinted = false; + }; + +} // end namespace Catch + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +// end catch_reporter_console.h +// start catch_reporter_junit.h + +// start catch_xmlwriter.h + +#include <vector> + +namespace Catch { + + class XmlEncode { + public: + enum ForWhat { ForTextNodes, ForAttributes }; + + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); + + void encodeTo( std::ostream& os ) const; + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); + + private: + std::string m_str; + ForWhat m_forWhat; + }; + + class XmlWriter { + public: + + class ScopedElement { + public: + ScopedElement( XmlWriter* writer ); + + ScopedElement( ScopedElement&& other ) noexcept; + ScopedElement& operator=( ScopedElement&& other ) noexcept; + + ~ScopedElement(); + + ScopedElement& writeText( std::string const& text, bool indent = true ); + + template<typename T> + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } + + private: + mutable XmlWriter* m_writer = nullptr; + }; + + XmlWriter( std::ostream& os = Catch::cout() ); + ~XmlWriter(); + + XmlWriter( XmlWriter const& ) = delete; + XmlWriter& operator=( XmlWriter const& ) = delete; + + XmlWriter& startElement( std::string const& name ); + + ScopedElement scopedElement( std::string const& name ); + + XmlWriter& endElement(); + + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); + + XmlWriter& writeAttribute( std::string const& name, bool attribute ); + + template<typename T> + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + ReusableStringStream rss; + rss << attribute; + return writeAttribute( name, rss.str() ); + } + + XmlWriter& writeText( std::string const& text, bool indent = true ); + + XmlWriter& writeComment( std::string const& text ); + + void writeStylesheetRef( std::string const& url ); + + XmlWriter& writeBlankLine(); + + void ensureTagClosed(); + + private: + + void writeDeclaration(); + + void newlineIfNecessary(); + + bool m_tagIsOpen = false; + bool m_needsNewline = false; + std::vector<std::string> m_tags; + std::string m_indent; + std::ostream& m_os; + }; + +} + +// end catch_xmlwriter.h +namespace Catch { + + class JunitReporter : public CumulativeReporterBase<JunitReporter> { + public: + JunitReporter(ReporterConfig const& _config); + + ~JunitReporter() override; + + static std::string getDescription(); + + void noMatchingTestCases(std::string const& /*spec*/) override; + + void testRunStarting(TestRunInfo const& runInfo) override; + + void testGroupStarting(GroupInfo const& groupInfo) override; + + void testCaseStarting(TestCaseInfo const& testCaseInfo) override; + bool assertionEnded(AssertionStats const& assertionStats) override; + + void testCaseEnded(TestCaseStats const& testCaseStats) override; + + void testGroupEnded(TestGroupStats const& testGroupStats) override; + + void testRunEndedCumulative() override; + + void writeGroup(TestGroupNode const& groupNode, double suiteTime); + + void writeTestCase(TestCaseNode const& testCaseNode); + + void writeSection(std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode); + + void writeAssertions(SectionNode const& sectionNode); + void writeAssertion(AssertionStats const& stats); + + XmlWriter xml; + Timer suiteTimer; + std::string stdOutForSuite; + std::string stdErrForSuite; + unsigned int unexpectedExceptions = 0; + bool m_okToFail = false; + }; + +} // end namespace Catch + +// end catch_reporter_junit.h +// start catch_reporter_xml.h + +namespace Catch { + class XmlReporter : public StreamingReporterBase<XmlReporter> { + public: + XmlReporter(ReporterConfig const& _config); + + ~XmlReporter() override; + + static std::string getDescription(); + + virtual std::string getStylesheetRef() const; + + void writeSourceInfo(SourceLineInfo const& sourceInfo); + + public: // StreamingReporterBase + + void noMatchingTestCases(std::string const& s) override; + + void testRunStarting(TestRunInfo const& testInfo) override; + + void testGroupStarting(GroupInfo const& groupInfo) override; + + void testCaseStarting(TestCaseInfo const& testInfo) override; + + void sectionStarting(SectionInfo const& sectionInfo) override; + + void assertionStarting(AssertionInfo const&) override; + + bool assertionEnded(AssertionStats const& assertionStats) override; + + void sectionEnded(SectionStats const& sectionStats) override; + + void testCaseEnded(TestCaseStats const& testCaseStats) override; + + void testGroupEnded(TestGroupStats const& testGroupStats) override; + + void testRunEnded(TestRunStats const& testRunStats) override; + + private: + Timer m_testCaseTimer; + XmlWriter m_xml; + int m_sectionDepth = 0; + }; + +} // end namespace Catch + +// end catch_reporter_xml.h + +// end catch_external_interfaces.h +#endif + +#endif // ! CATCH_CONFIG_IMPL_ONLY + +#ifdef CATCH_IMPL +// start catch_impl.hpp + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +// Keep these here for external reporters +// start catch_test_case_tracker.h + +#include <string> +#include <vector> +#include <memory> + +namespace Catch { +namespace TestCaseTracking { + + struct NameAndLocation { + std::string name; + SourceLineInfo location; + + NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); + }; + + struct ITracker; + + using ITrackerPtr = std::shared_ptr<ITracker>; + + struct ITracker { + virtual ~ITracker(); + + // static queries + virtual NameAndLocation const& nameAndLocation() const = 0; + + // dynamic queries + virtual bool isComplete() const = 0; // Successfully completed or failed + virtual bool isSuccessfullyCompleted() const = 0; + virtual bool isOpen() const = 0; // Started but not complete + virtual bool hasChildren() const = 0; + + virtual ITracker& parent() = 0; + + // actions + virtual void close() = 0; // Successfully complete + virtual void fail() = 0; + virtual void markAsNeedingAnotherRun() = 0; + + virtual void addChild( ITrackerPtr const& child ) = 0; + virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0; + virtual void openChild() = 0; + + // Debug/ checking + virtual bool isSectionTracker() const = 0; + virtual bool isIndexTracker() const = 0; + }; + + class TrackerContext { + + enum RunState { + NotStarted, + Executing, + CompletedCycle + }; + + ITrackerPtr m_rootTracker; + ITracker* m_currentTracker = nullptr; + RunState m_runState = NotStarted; + + public: + + static TrackerContext& instance(); + + ITracker& startRun(); + void endRun(); + + void startCycle(); + void completeCycle(); + + bool completedCycle() const; + ITracker& currentTracker(); + void setCurrentTracker( ITracker* tracker ); + }; + + class TrackerBase : public ITracker { + protected: + enum CycleState { + NotStarted, + Executing, + ExecutingChildren, + NeedsAnotherRun, + CompletedSuccessfully, + Failed + }; + + class TrackerHasName { + NameAndLocation m_nameAndLocation; + public: + TrackerHasName( NameAndLocation const& nameAndLocation ); + bool operator ()( ITrackerPtr const& tracker ) const; + }; + + using Children = std::vector<ITrackerPtr>; + NameAndLocation m_nameAndLocation; + TrackerContext& m_ctx; + ITracker* m_parent; + Children m_children; + CycleState m_runState = NotStarted; + + public: + TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); + + NameAndLocation const& nameAndLocation() const override; + bool isComplete() const override; + bool isSuccessfullyCompleted() const override; + bool isOpen() const override; + bool hasChildren() const override; + + void addChild( ITrackerPtr const& child ) override; + + ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override; + ITracker& parent() override; + + void openChild() override; + + bool isSectionTracker() const override; + bool isIndexTracker() const override; + + void open(); + + void close() override; + void fail() override; + void markAsNeedingAnotherRun() override; + + private: + void moveToParent(); + void moveToThis(); + }; + + class SectionTracker : public TrackerBase { + std::vector<std::string> m_filters; + public: + SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); + + bool isSectionTracker() const override; + + static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ); + + void tryOpen(); + + void addInitialFilters( std::vector<std::string> const& filters ); + void addNextFilters( std::vector<std::string> const& filters ); + }; + + class IndexTracker : public TrackerBase { + int m_size; + int m_index = -1; + public: + IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ); + + bool isIndexTracker() const override; + void close() override; + + static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ); + + int index() const; + + void moveNext(); + }; + +} // namespace TestCaseTracking + +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; +using TestCaseTracking::IndexTracker; + +} // namespace Catch + +// end catch_test_case_tracker.h + +// start catch_leak_detector.h + +namespace Catch { + + struct LeakDetector { + LeakDetector(); + }; + +} +// end catch_leak_detector.h +// Cpp files will be included in the single-header file here +// start catch_approx.cpp + +#include <cmath> +#include <limits> + +namespace { + +// Performs equivalent check of std::fabs(lhs - rhs) <= margin +// But without the subtraction to allow for INFINITY in comparison +bool marginComparison(double lhs, double rhs, double margin) { + return (lhs + margin >= rhs) && (rhs + margin >= lhs); +} + +} + +namespace Catch { +namespace Detail { + + Approx::Approx ( double value ) + : m_epsilon( std::numeric_limits<float>::epsilon()*100 ), + m_margin( 0.0 ), + m_scale( 0.0 ), + m_value( value ) + {} + + Approx Approx::custom() { + return Approx( 0 ); + } + + Approx Approx::operator-() const { + auto temp(*this); + temp.m_value = -temp.m_value; + return temp; + } + + std::string Approx::toString() const { + ReusableStringStream rss; + rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )"; + return rss.str(); + } + + bool Approx::equalityComparisonImpl(const double other) const { + // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value + // Thanks to Richard Harris for his help refining the scaled margin value + return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value))); + } + +} // end namespace Detail + +namespace literals { + Detail::Approx operator "" _a(long double val) { + return Detail::Approx(val); + } + Detail::Approx operator "" _a(unsigned long long val) { + return Detail::Approx(val); + } +} // end namespace literals + +std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx const& value) { + return value.toString(); +} + +} // end namespace Catch +// end catch_approx.cpp +// start catch_assertionhandler.cpp + +// start catch_context.h + +#include <memory> + +namespace Catch { + + struct IResultCapture; + struct IRunner; + struct IConfig; + struct IMutableContext; + + using IConfigPtr = std::shared_ptr<IConfig const>; + + struct IContext + { + virtual ~IContext(); + + virtual IResultCapture* getResultCapture() = 0; + virtual IRunner* getRunner() = 0; + virtual IConfigPtr const& getConfig() const = 0; + }; + + struct IMutableContext : IContext + { + virtual ~IMutableContext(); + virtual void setResultCapture( IResultCapture* resultCapture ) = 0; + virtual void setRunner( IRunner* runner ) = 0; + virtual void setConfig( IConfigPtr const& config ) = 0; + + private: + static IMutableContext *currentContext; + friend IMutableContext& getCurrentMutableContext(); + friend void cleanUpContext(); + static void createContext(); + }; + + inline IMutableContext& getCurrentMutableContext() + { + if( !IMutableContext::currentContext ) + IMutableContext::createContext(); + return *IMutableContext::currentContext; + } + + inline IContext& getCurrentContext() + { + return getCurrentMutableContext(); + } + + void cleanUpContext(); +} + +// end catch_context.h +// start catch_debugger.h + +namespace Catch { + bool isDebuggerActive(); +} + +#ifdef CATCH_PLATFORM_MAC + + #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ + +#elif defined(CATCH_PLATFORM_LINUX) + // If we can use inline assembler, do it because this allows us to break + // directly at the location of the failing check instead of breaking inside + // raise() called from it, i.e. one stack frame below. + #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) + #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */ + #else // Fall back to the generic way. + #include <signal.h> + + #define CATCH_TRAP() raise(SIGTRAP) + #endif +#elif defined(_MSC_VER) + #define CATCH_TRAP() __debugbreak() +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) void __stdcall DebugBreak(); + #define CATCH_TRAP() DebugBreak() +#endif + +#ifdef CATCH_TRAP + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } +#else + namespace Catch { + inline void doNothing() {} + } + #define CATCH_BREAK_INTO_DEBUGGER() Catch::doNothing() +#endif + +// end catch_debugger.h +// start catch_run_context.h + +// start catch_fatal_condition.h + +// start catch_windows_h_proxy.h + + +#if defined(CATCH_PLATFORM_WINDOWS) + +#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) +# define CATCH_DEFINED_NOMINMAX +# define NOMINMAX +#endif +#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) +# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif + +#ifdef __AFXDLL +#include <AfxWin.h> +#else +#include <windows.h> +#endif + +#ifdef CATCH_DEFINED_NOMINMAX +# undef NOMINMAX +#endif +#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN +# undef WIN32_LEAN_AND_MEAN +#endif + +#endif // defined(CATCH_PLATFORM_WINDOWS) + +// end catch_windows_h_proxy.h +#if defined( CATCH_CONFIG_WINDOWS_SEH ) + +namespace Catch { + + struct FatalConditionHandler { + + static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); + FatalConditionHandler(); + static void reset(); + ~FatalConditionHandler(); + + private: + static bool isSet; + static ULONG guaranteeSize; + static PVOID exceptionHandlerHandle; + }; + +} // namespace Catch + +#elif defined ( CATCH_CONFIG_POSIX_SIGNALS ) + +#include <signal.h> + +namespace Catch { + + struct FatalConditionHandler { + + static bool isSet; + static struct sigaction oldSigActions[]; + static stack_t oldSigStack; + static char altStackMem[]; + + static void handleSignal( int sig ); + + FatalConditionHandler(); + ~FatalConditionHandler(); + static void reset(); + }; + +} // namespace Catch + +#else + +namespace Catch { + struct FatalConditionHandler { + void reset(); + }; +} + +#endif + +// end catch_fatal_condition.h +#include <string> + +namespace Catch { + + struct IMutableContext; + + /////////////////////////////////////////////////////////////////////////// + + class RunContext : public IResultCapture, public IRunner { + + public: + RunContext( RunContext const& ) = delete; + RunContext& operator =( RunContext const& ) = delete; + + explicit RunContext( IConfigPtr const& _config, IStreamingReporterPtr&& reporter ); + + ~RunContext() override; + + void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ); + void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ); + + Totals runTest(TestCase const& testCase); + + IConfigPtr config() const; + IStreamingReporter& reporter() const; + + public: // IResultCapture + + // Assertion handlers + void handleExpr + ( AssertionInfo const& info, + ITransientExpression const& expr, + AssertionReaction& reaction ) override; + void handleMessage + ( AssertionInfo const& info, + ResultWas::OfType resultType, + StringRef const& message, + AssertionReaction& reaction ) override; + void handleUnexpectedExceptionNotThrown + ( AssertionInfo const& info, + AssertionReaction& reaction ) override; + void handleUnexpectedInflightException + ( AssertionInfo const& info, + std::string const& message, + AssertionReaction& reaction ) override; + void handleIncomplete + ( AssertionInfo const& info ) override; + void handleNonExpr + ( AssertionInfo const &info, + ResultWas::OfType resultType, + AssertionReaction &reaction ) override; + + bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; + + void sectionEnded( SectionEndInfo const& endInfo ) override; + void sectionEndedEarly( SectionEndInfo const& endInfo ) override; + + void benchmarkStarting( BenchmarkInfo const& info ) override; + void benchmarkEnded( BenchmarkStats const& stats ) override; + + void pushScopedMessage( MessageInfo const& message ) override; + void popScopedMessage( MessageInfo const& message ) override; + + std::string getCurrentTestName() const override; + + const AssertionResult* getLastResult() const override; + + void exceptionEarlyReported() override; + + void handleFatalErrorCondition( StringRef message ) override; + + bool lastAssertionPassed() override; + + void assertionPassed() override; + + public: + // !TBD We need to do this another way! + bool aborting() const final; + + private: + + void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ); + void invokeActiveTestCase(); + + void resetAssertionInfo(); + bool testForMissingAssertions( Counts& assertions ); + + void assertionEnded( AssertionResult const& result ); + void reportExpr + ( AssertionInfo const &info, + ResultWas::OfType resultType, + ITransientExpression const *expr, + bool negated ); + + void populateReaction( AssertionReaction& reaction ); + + private: + + void handleUnfinishedSections(); + + TestRunInfo m_runInfo; + IMutableContext& m_context; + TestCase const* m_activeTestCase = nullptr; + ITracker* m_testCaseTracker; + Option<AssertionResult> m_lastResult; + + IConfigPtr m_config; + Totals m_totals; + IStreamingReporterPtr m_reporter; + std::vector<MessageInfo> m_messages; + AssertionInfo m_lastAssertionInfo; + std::vector<SectionEndInfo> m_unfinishedSections; + std::vector<ITracker*> m_activeSections; + TrackerContext m_trackerContext; + bool m_lastAssertionPassed = false; + bool m_shouldReportUnexpected = true; + bool m_includeSuccessfulResults; + }; + +} // end namespace Catch + +// end catch_run_context.h +namespace Catch { + + namespace { + auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { + expr.streamReconstructedExpression( os ); + return os; + } + } + + LazyExpression::LazyExpression( bool isNegated ) + : m_isNegated( isNegated ) + {} + + LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {} + + LazyExpression::operator bool() const { + return m_transientExpression != nullptr; + } + + auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& { + if( lazyExpr.m_isNegated ) + os << "!"; + + if( lazyExpr ) { + if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() ) + os << "(" << *lazyExpr.m_transientExpression << ")"; + else + os << *lazyExpr.m_transientExpression; + } + else { + os << "{** error - unchecked empty expression requested **}"; + } + return os; + } + + AssertionHandler::AssertionHandler + ( StringRef macroName, + SourceLineInfo const& lineInfo, + StringRef capturedExpression, + ResultDisposition::Flags resultDisposition ) + : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, + m_resultCapture( getResultCapture() ) + {} + + void AssertionHandler::handleExpr( ITransientExpression const& expr ) { + m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction ); + } + void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const& message) { + m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction ); + } + + auto AssertionHandler::allowThrows() const -> bool { + return getCurrentContext().getConfig()->allowThrows(); + } + + void AssertionHandler::complete() { + setCompleted(); + if( m_reaction.shouldDebugBreak ) { + + // If you find your debugger stopping you here then go one level up on the + // call-stack for the code that caused it (typically a failed assertion) + + // (To go back to the test and change execution, jump over the throw, next) + CATCH_BREAK_INTO_DEBUGGER(); + } + if( m_reaction.shouldThrow ) + throw Catch::TestFailureException(); + } + void AssertionHandler::setCompleted() { + m_completed = true; + } + + void AssertionHandler::handleUnexpectedInflightException() { + m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction ); + } + + void AssertionHandler::handleExceptionThrownAsExpected() { + m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); + } + void AssertionHandler::handleExceptionNotThrownAsExpected() { + m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); + } + + void AssertionHandler::handleUnexpectedExceptionNotThrown() { + m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction ); + } + + void AssertionHandler::handleThrowingCallSkipped() { + m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); + } + + // This is the overload that takes a string and infers the Equals matcher from it + // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp + void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ) { + handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString ); + } + +} // namespace Catch +// end catch_assertionhandler.cpp +// start catch_assertionresult.cpp + +namespace Catch { + AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression): + lazyExpression(_lazyExpression), + resultType(_resultType) {} + + std::string AssertionResultData::reconstructExpression() const { + + if( reconstructedExpression.empty() ) { + if( lazyExpression ) { + ReusableStringStream rss; + rss << lazyExpression; + reconstructedExpression = rss.str(); + } + } + return reconstructedExpression; + } + + AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) + : m_info( info ), + m_resultData( data ) + {} + + // Result was a success + bool AssertionResult::succeeded() const { + return Catch::isOk( m_resultData.resultType ); + } + + // Result was a success, or failure is suppressed + bool AssertionResult::isOk() const { + return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); + } + + ResultWas::OfType AssertionResult::getResultType() const { + return m_resultData.resultType; + } + + bool AssertionResult::hasExpression() const { + return m_info.capturedExpression[0] != 0; + } + + bool AssertionResult::hasMessage() const { + return !m_resultData.message.empty(); + } + + std::string AssertionResult::getExpression() const { + if( isFalseTest( m_info.resultDisposition ) ) + return "!(" + m_info.capturedExpression + ")"; + else + return m_info.capturedExpression; + } + + std::string AssertionResult::getExpressionInMacro() const { + std::string expr; + if( m_info.macroName[0] == 0 ) + expr = m_info.capturedExpression; + else { + expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); + expr += m_info.macroName; + expr += "( "; + expr += m_info.capturedExpression; + expr += " )"; + } + return expr; + } + + bool AssertionResult::hasExpandedExpression() const { + return hasExpression() && getExpandedExpression() != getExpression(); + } + + std::string AssertionResult::getExpandedExpression() const { + std::string expr = m_resultData.reconstructExpression(); + return expr.empty() + ? getExpression() + : expr; + } + + std::string AssertionResult::getMessage() const { + return m_resultData.message; + } + SourceLineInfo AssertionResult::getSourceInfo() const { + return m_info.lineInfo; + } + + StringRef AssertionResult::getTestMacroName() const { + return m_info.macroName; + } + +} // end namespace Catch +// end catch_assertionresult.cpp +// start catch_benchmark.cpp + +namespace Catch { + + auto BenchmarkLooper::getResolution() -> uint64_t { + return getEstimatedClockResolution() * getCurrentContext().getConfig()->benchmarkResolutionMultiple(); + } + + void BenchmarkLooper::reportStart() { + getResultCapture().benchmarkStarting( { m_name } ); + } + auto BenchmarkLooper::needsMoreIterations() -> bool { + auto elapsed = m_timer.getElapsedNanoseconds(); + + // Exponentially increasing iterations until we're confident in our timer resolution + if( elapsed < m_resolution ) { + m_iterationsToRun *= 10; + return true; + } + + getResultCapture().benchmarkEnded( { { m_name }, m_count, elapsed } ); + return false; + } + +} // end namespace Catch +// end catch_benchmark.cpp +// start catch_capture_matchers.cpp + +namespace Catch { + + using StringMatcher = Matchers::Impl::MatcherBase<std::string>; + + // This is the general overload that takes a any string matcher + // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers + // the Equals matcher (so the header does not mention matchers) + void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ) { + std::string exceptionMessage = Catch::translateActiveException(); + MatchExpr<std::string, StringMatcher const&> expr( exceptionMessage, matcher, matcherString ); + handler.handleExpr( expr ); + } + +} // namespace Catch +// end catch_capture_matchers.cpp +// start catch_commandline.cpp + +// start catch_commandline.h + +// start catch_clara.h + +// Use Catch's value for console width (store Clara's off to the side, if present) +#ifdef CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH +#undef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH +#endif +#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH-1 + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#pragma clang diagnostic ignored "-Wexit-time-destructors" +#pragma clang diagnostic ignored "-Wshadow" +#endif + +// start clara.hpp +// Copyright 2017 Two Blue Cubes Ltd. All rights reserved. +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See https://github.com/philsquared/Clara for more details + +// Clara v1.1.4 + + +#ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80 +#endif + +#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH +#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +#ifndef CLARA_CONFIG_OPTIONAL_TYPE +#ifdef __has_include +#if __has_include(<optional>) && __cplusplus >= 201703L +#include <optional> +#define CLARA_CONFIG_OPTIONAL_TYPE std::optional +#endif +#endif +#endif + +// ----------- #included from clara_textflow.hpp ----------- + +// TextFlowCpp +// +// A single-header library for wrapping and laying out basic text, by Phil Nash +// +// This work is licensed under the BSD 2-Clause license. +// See the accompanying LICENSE file, or the one at https://opensource.org/licenses/BSD-2-Clause +// +// This project is hosted at https://github.com/philsquared/textflowcpp + + +#include <cassert> +#include <ostream> +#include <sstream> +#include <vector> + +#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH +#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80 +#endif + +namespace Catch { namespace clara { namespace TextFlow { + + inline auto isWhitespace( char c ) -> bool { + static std::string chars = " \t\n\r"; + return chars.find( c ) != std::string::npos; + } + inline auto isBreakableBefore( char c ) -> bool { + static std::string chars = "[({<|"; + return chars.find( c ) != std::string::npos; + } + inline auto isBreakableAfter( char c ) -> bool { + static std::string chars = "])}>.,:;*+-=&/\\"; + return chars.find( c ) != std::string::npos; + } + + class Columns; + + class Column { + std::vector<std::string> m_strings; + size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH; + size_t m_indent = 0; + size_t m_initialIndent = std::string::npos; + + public: + class iterator { + friend Column; + + Column const& m_column; + size_t m_stringIndex = 0; + size_t m_pos = 0; + + size_t m_len = 0; + size_t m_end = 0; + bool m_suffix = false; + + iterator( Column const& column, size_t stringIndex ) + : m_column( column ), + m_stringIndex( stringIndex ) + {} + + auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; } + + auto isBoundary( size_t at ) const -> bool { + assert( at > 0 ); + assert( at <= line().size() ); + + return at == line().size() || + ( isWhitespace( line()[at] ) && !isWhitespace( line()[at-1] ) ) || + isBreakableBefore( line()[at] ) || + isBreakableAfter( line()[at-1] ); + } + + void calcLength() { + assert( m_stringIndex < m_column.m_strings.size() ); + + m_suffix = false; + auto width = m_column.m_width-indent(); + m_end = m_pos; + while( m_end < line().size() && line()[m_end] != '\n' ) + ++m_end; + + if( m_end < m_pos + width ) { + m_len = m_end - m_pos; + } + else { + size_t len = width; + while (len > 0 && !isBoundary(m_pos + len)) + --len; + while (len > 0 && isWhitespace( line()[m_pos + len - 1] )) + --len; + + if (len > 0) { + m_len = len; + } else { + m_suffix = true; + m_len = width - 1; + } + } + } + + auto indent() const -> size_t { + auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos; + return initial == std::string::npos ? m_column.m_indent : initial; + } + + auto addIndentAndSuffix(std::string const &plain) const -> std::string { + return std::string( indent(), ' ' ) + (m_suffix ? plain + "-" : plain); + } + + public: + explicit iterator( Column const& column ) : m_column( column ) { + assert( m_column.m_width > m_column.m_indent ); + assert( m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent ); + calcLength(); + if( m_len == 0 ) + m_stringIndex++; // Empty string + } + + auto operator *() const -> std::string { + assert( m_stringIndex < m_column.m_strings.size() ); + assert( m_pos <= m_end ); + if( m_pos + m_column.m_width < m_end ) + return addIndentAndSuffix(line().substr(m_pos, m_len)); + else + return addIndentAndSuffix(line().substr(m_pos, m_end - m_pos)); + } + + auto operator ++() -> iterator& { + m_pos += m_len; + if( m_pos < line().size() && line()[m_pos] == '\n' ) + m_pos += 1; + else + while( m_pos < line().size() && isWhitespace( line()[m_pos] ) ) + ++m_pos; + + if( m_pos == line().size() ) { + m_pos = 0; + ++m_stringIndex; + } + if( m_stringIndex < m_column.m_strings.size() ) + calcLength(); + return *this; + } + auto operator ++(int) -> iterator { + iterator prev( *this ); + operator++(); + return prev; + } + + auto operator ==( iterator const& other ) const -> bool { + return + m_pos == other.m_pos && + m_stringIndex == other.m_stringIndex && + &m_column == &other.m_column; + } + auto operator !=( iterator const& other ) const -> bool { + return !operator==( other ); + } + }; + using const_iterator = iterator; + + explicit Column( std::string const& text ) { m_strings.push_back( text ); } + + auto width( size_t newWidth ) -> Column& { + assert( newWidth > 0 ); + m_width = newWidth; + return *this; + } + auto indent( size_t newIndent ) -> Column& { + m_indent = newIndent; + return *this; + } + auto initialIndent( size_t newIndent ) -> Column& { + m_initialIndent = newIndent; + return *this; + } + + auto width() const -> size_t { return m_width; } + auto begin() const -> iterator { return iterator( *this ); } + auto end() const -> iterator { return { *this, m_strings.size() }; } + + inline friend std::ostream& operator << ( std::ostream& os, Column const& col ) { + bool first = true; + for( auto line : col ) { + if( first ) + first = false; + else + os << "\n"; + os << line; + } + return os; + } + + auto operator + ( Column const& other ) -> Columns; + + auto toString() const -> std::string { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + }; + + class Spacer : public Column { + + public: + explicit Spacer( size_t spaceWidth ) : Column( "" ) { + width( spaceWidth ); + } + }; + + class Columns { + std::vector<Column> m_columns; + + public: + + class iterator { + friend Columns; + struct EndTag {}; + + std::vector<Column> const& m_columns; + std::vector<Column::iterator> m_iterators; + size_t m_activeIterators; + + iterator( Columns const& columns, EndTag ) + : m_columns( columns.m_columns ), + m_activeIterators( 0 ) + { + m_iterators.reserve( m_columns.size() ); + + for( auto const& col : m_columns ) + m_iterators.push_back( col.end() ); + } + + public: + explicit iterator( Columns const& columns ) + : m_columns( columns.m_columns ), + m_activeIterators( m_columns.size() ) + { + m_iterators.reserve( m_columns.size() ); + + for( auto const& col : m_columns ) + m_iterators.push_back( col.begin() ); + } + + auto operator ==( iterator const& other ) const -> bool { + return m_iterators == other.m_iterators; + } + auto operator !=( iterator const& other ) const -> bool { + return m_iterators != other.m_iterators; + } + auto operator *() const -> std::string { + std::string row, padding; + + for( size_t i = 0; i < m_columns.size(); ++i ) { + auto width = m_columns[i].width(); + if( m_iterators[i] != m_columns[i].end() ) { + std::string col = *m_iterators[i]; + row += padding + col; + if( col.size() < width ) + padding = std::string( width - col.size(), ' ' ); + else + padding = ""; + } + else { + padding += std::string( width, ' ' ); + } + } + return row; + } + auto operator ++() -> iterator& { + for( size_t i = 0; i < m_columns.size(); ++i ) { + if (m_iterators[i] != m_columns[i].end()) + ++m_iterators[i]; + } + return *this; + } + auto operator ++(int) -> iterator { + iterator prev( *this ); + operator++(); + return prev; + } + }; + using const_iterator = iterator; + + auto begin() const -> iterator { return iterator( *this ); } + auto end() const -> iterator { return { *this, iterator::EndTag() }; } + + auto operator += ( Column const& col ) -> Columns& { + m_columns.push_back( col ); + return *this; + } + auto operator + ( Column const& col ) -> Columns { + Columns combined = *this; + combined += col; + return combined; + } + + inline friend std::ostream& operator << ( std::ostream& os, Columns const& cols ) { + + bool first = true; + for( auto line : cols ) { + if( first ) + first = false; + else + os << "\n"; + os << line; + } + return os; + } + + auto toString() const -> std::string { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + }; + + inline auto Column::operator + ( Column const& other ) -> Columns { + Columns cols; + cols += *this; + cols += other; + return cols; + } +}}} // namespace Catch::clara::TextFlow + +// ----------- end of #include from clara_textflow.hpp ----------- +// ........... back in clara.hpp + +#include <memory> +#include <set> +#include <algorithm> + +#if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) ) +#define CATCH_PLATFORM_WINDOWS +#endif + +namespace Catch { namespace clara { +namespace detail { + + // Traits for extracting arg and return type of lambdas (for single argument lambdas) + template<typename L> + struct UnaryLambdaTraits : UnaryLambdaTraits<decltype( &L::operator() )> {}; + + template<typename ClassT, typename ReturnT, typename... Args> + struct UnaryLambdaTraits<ReturnT( ClassT::* )( Args... ) const> { + static const bool isValid = false; + }; + + template<typename ClassT, typename ReturnT, typename ArgT> + struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> { + static const bool isValid = true; + using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type; + using ReturnType = ReturnT; + }; + + class TokenStream; + + // Transport for raw args (copied from main args, or supplied via init list for testing) + class Args { + friend TokenStream; + std::string m_exeName; + std::vector<std::string> m_args; + + public: + Args( int argc, char const* const* argv ) + : m_exeName(argv[0]), + m_args(argv + 1, argv + argc) {} + + Args( std::initializer_list<std::string> args ) + : m_exeName( *args.begin() ), + m_args( args.begin()+1, args.end() ) + {} + + auto exeName() const -> std::string { + return m_exeName; + } + }; + + // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string + // may encode an option + its argument if the : or = form is used + enum class TokenType { + Option, Argument + }; + struct Token { + TokenType type; + std::string token; + }; + + inline auto isOptPrefix( char c ) -> bool { + return c == '-' +#ifdef CATCH_PLATFORM_WINDOWS + || c == '/' +#endif + ; + } + + // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled + class TokenStream { + using Iterator = std::vector<std::string>::const_iterator; + Iterator it; + Iterator itEnd; + std::vector<Token> m_tokenBuffer; + + void loadBuffer() { + m_tokenBuffer.resize( 0 ); + + // Skip any empty strings + while( it != itEnd && it->empty() ) + ++it; + + if( it != itEnd ) { + auto const &next = *it; + if( isOptPrefix( next[0] ) ) { + auto delimiterPos = next.find_first_of( " :=" ); + if( delimiterPos != std::string::npos ) { + m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } ); + m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } ); + } else { + if( next[1] != '-' && next.size() > 2 ) { + std::string opt = "- "; + for( size_t i = 1; i < next.size(); ++i ) { + opt[1] = next[i]; + m_tokenBuffer.push_back( { TokenType::Option, opt } ); + } + } else { + m_tokenBuffer.push_back( { TokenType::Option, next } ); + } + } + } else { + m_tokenBuffer.push_back( { TokenType::Argument, next } ); + } + } + } + + public: + explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {} + + TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) { + loadBuffer(); + } + + explicit operator bool() const { + return !m_tokenBuffer.empty() || it != itEnd; + } + + auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); } + + auto operator*() const -> Token { + assert( !m_tokenBuffer.empty() ); + return m_tokenBuffer.front(); + } + + auto operator->() const -> Token const * { + assert( !m_tokenBuffer.empty() ); + return &m_tokenBuffer.front(); + } + + auto operator++() -> TokenStream & { + if( m_tokenBuffer.size() >= 2 ) { + m_tokenBuffer.erase( m_tokenBuffer.begin() ); + } else { + if( it != itEnd ) + ++it; + loadBuffer(); + } + return *this; + } + }; + + class ResultBase { + public: + enum Type { + Ok, LogicError, RuntimeError + }; + + protected: + ResultBase( Type type ) : m_type( type ) {} + virtual ~ResultBase() = default; + + virtual void enforceOk() const = 0; + + Type m_type; + }; + + template<typename T> + class ResultValueBase : public ResultBase { + public: + auto value() const -> T const & { + enforceOk(); + return m_value; + } + + protected: + ResultValueBase( Type type ) : ResultBase( type ) {} + + ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) { + if( m_type == ResultBase::Ok ) + new( &m_value ) T( other.m_value ); + } + + ResultValueBase( Type, T const &value ) : ResultBase( Ok ) { + new( &m_value ) T( value ); + } + + auto operator=( ResultValueBase const &other ) -> ResultValueBase & { + if( m_type == ResultBase::Ok ) + m_value.~T(); + ResultBase::operator=(other); + if( m_type == ResultBase::Ok ) + new( &m_value ) T( other.m_value ); + return *this; + } + + ~ResultValueBase() override { + if( m_type == Ok ) + m_value.~T(); + } + + union { + T m_value; + }; + }; + + template<> + class ResultValueBase<void> : public ResultBase { + protected: + using ResultBase::ResultBase; + }; + + template<typename T = void> + class BasicResult : public ResultValueBase<T> { + public: + template<typename U> + explicit BasicResult( BasicResult<U> const &other ) + : ResultValueBase<T>( other.type() ), + m_errorMessage( other.errorMessage() ) + { + assert( type() != ResultBase::Ok ); + } + + template<typename U> + static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; } + static auto ok() -> BasicResult { return { ResultBase::Ok }; } + static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; } + static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; } + + explicit operator bool() const { return m_type == ResultBase::Ok; } + auto type() const -> ResultBase::Type { return m_type; } + auto errorMessage() const -> std::string { return m_errorMessage; } + + protected: + void enforceOk() const override { + + // Errors shouldn't reach this point, but if they do + // the actual error message will be in m_errorMessage + assert( m_type != ResultBase::LogicError ); + assert( m_type != ResultBase::RuntimeError ); + if( m_type != ResultBase::Ok ) + std::abort(); + } + + std::string m_errorMessage; // Only populated if resultType is an error + + BasicResult( ResultBase::Type type, std::string const &message ) + : ResultValueBase<T>(type), + m_errorMessage(message) + { + assert( m_type != ResultBase::Ok ); + } + + using ResultValueBase<T>::ResultValueBase; + using ResultBase::m_type; + }; + + enum class ParseResultType { + Matched, NoMatch, ShortCircuitAll, ShortCircuitSame + }; + + class ParseState { + public: + + ParseState( ParseResultType type, TokenStream const &remainingTokens ) + : m_type(type), + m_remainingTokens( remainingTokens ) + {} + + auto type() const -> ParseResultType { return m_type; } + auto remainingTokens() const -> TokenStream { return m_remainingTokens; } + + private: + ParseResultType m_type; + TokenStream m_remainingTokens; + }; + + using Result = BasicResult<void>; + using ParserResult = BasicResult<ParseResultType>; + using InternalParseResult = BasicResult<ParseState>; + + struct HelpColumns { + std::string left; + std::string right; + }; + + template<typename T> + inline auto convertInto( std::string const &source, T& target ) -> ParserResult { + std::stringstream ss; + ss << source; + ss >> target; + if( ss.fail() ) + return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" ); + else + return ParserResult::ok( ParseResultType::Matched ); + } + inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult { + target = source; + return ParserResult::ok( ParseResultType::Matched ); + } + inline auto convertInto( std::string const &source, bool &target ) -> ParserResult { + std::string srcLC = source; + std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( ::tolower(c) ); } ); + if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on") + target = true; + else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off") + target = false; + else + return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" ); + return ParserResult::ok( ParseResultType::Matched ); + } +#ifdef CLARA_CONFIG_OPTIONAL_TYPE + template<typename T> + inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T>& target ) -> ParserResult { + T temp; + auto result = convertInto( source, temp ); + if( result ) + target = std::move(temp); + return result; + } +#endif // CLARA_CONFIG_OPTIONAL_TYPE + + struct NonCopyable { + NonCopyable() = default; + NonCopyable( NonCopyable const & ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable &operator=( NonCopyable const & ) = delete; + NonCopyable &operator=( NonCopyable && ) = delete; + }; + + struct BoundRef : NonCopyable { + virtual ~BoundRef() = default; + virtual auto isContainer() const -> bool { return false; } + virtual auto isFlag() const -> bool { return false; } + }; + struct BoundValueRefBase : BoundRef { + virtual auto setValue( std::string const &arg ) -> ParserResult = 0; + }; + struct BoundFlagRefBase : BoundRef { + virtual auto setFlag( bool flag ) -> ParserResult = 0; + virtual auto isFlag() const -> bool { return true; } + }; + + template<typename T> + struct BoundValueRef : BoundValueRefBase { + T &m_ref; + + explicit BoundValueRef( T &ref ) : m_ref( ref ) {} + + auto setValue( std::string const &arg ) -> ParserResult override { + return convertInto( arg, m_ref ); + } + }; + + template<typename T> + struct BoundValueRef<std::vector<T>> : BoundValueRefBase { + std::vector<T> &m_ref; + + explicit BoundValueRef( std::vector<T> &ref ) : m_ref( ref ) {} + + auto isContainer() const -> bool override { return true; } + + auto setValue( std::string const &arg ) -> ParserResult override { + T temp; + auto result = convertInto( arg, temp ); + if( result ) + m_ref.push_back( temp ); + return result; + } + }; + + struct BoundFlagRef : BoundFlagRefBase { + bool &m_ref; + + explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {} + + auto setFlag( bool flag ) -> ParserResult override { + m_ref = flag; + return ParserResult::ok( ParseResultType::Matched ); + } + }; + + template<typename ReturnType> + struct LambdaInvoker { + static_assert( std::is_same<ReturnType, ParserResult>::value, "Lambda must return void or clara::ParserResult" ); + + template<typename L, typename ArgType> + static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { + return lambda( arg ); + } + }; + + template<> + struct LambdaInvoker<void> { + template<typename L, typename ArgType> + static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { + lambda( arg ); + return ParserResult::ok( ParseResultType::Matched ); + } + }; + + template<typename ArgType, typename L> + inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult { + ArgType temp{}; + auto result = convertInto( arg, temp ); + return !result + ? result + : LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp ); + } + + template<typename L> + struct BoundLambda : BoundValueRefBase { + L m_lambda; + + static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" ); + explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {} + + auto setValue( std::string const &arg ) -> ParserResult override { + return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>( m_lambda, arg ); + } + }; + + template<typename L> + struct BoundFlagLambda : BoundFlagRefBase { + L m_lambda; + + static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" ); + static_assert( std::is_same<typename UnaryLambdaTraits<L>::ArgType, bool>::value, "flags must be boolean" ); + + explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {} + + auto setFlag( bool flag ) -> ParserResult override { + return LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( m_lambda, flag ); + } + }; + + enum class Optionality { Optional, Required }; + + struct Parser; + + class ParserBase { + public: + virtual ~ParserBase() = default; + virtual auto validate() const -> Result { return Result::ok(); } + virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0; + virtual auto cardinality() const -> size_t { return 1; } + + auto parse( Args const &args ) const -> InternalParseResult { + return parse( args.exeName(), TokenStream( args ) ); + } + }; + + template<typename DerivedT> + class ComposableParserImpl : public ParserBase { + public: + template<typename T> + auto operator|( T const &other ) const -> Parser; + + template<typename T> + auto operator+( T const &other ) const -> Parser; + }; + + // Common code and state for Args and Opts + template<typename DerivedT> + class ParserRefImpl : public ComposableParserImpl<DerivedT> { + protected: + Optionality m_optionality = Optionality::Optional; + std::shared_ptr<BoundRef> m_ref; + std::string m_hint; + std::string m_description; + + explicit ParserRefImpl( std::shared_ptr<BoundRef> const &ref ) : m_ref( ref ) {} + + public: + template<typename T> + ParserRefImpl( T &ref, std::string const &hint ) + : m_ref( std::make_shared<BoundValueRef<T>>( ref ) ), + m_hint( hint ) + {} + + template<typename LambdaT> + ParserRefImpl( LambdaT const &ref, std::string const &hint ) + : m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ), + m_hint(hint) + {} + + auto operator()( std::string const &description ) -> DerivedT & { + m_description = description; + return static_cast<DerivedT &>( *this ); + } + + auto optional() -> DerivedT & { + m_optionality = Optionality::Optional; + return static_cast<DerivedT &>( *this ); + }; + + auto required() -> DerivedT & { + m_optionality = Optionality::Required; + return static_cast<DerivedT &>( *this ); + }; + + auto isOptional() const -> bool { + return m_optionality == Optionality::Optional; + } + + auto cardinality() const -> size_t override { + if( m_ref->isContainer() ) + return 0; + else + return 1; + } + + auto hint() const -> std::string { return m_hint; } + }; + + class ExeName : public ComposableParserImpl<ExeName> { + std::shared_ptr<std::string> m_name; + std::shared_ptr<BoundValueRefBase> m_ref; + + template<typename LambdaT> + static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> { + return std::make_shared<BoundLambda<LambdaT>>( lambda) ; + } + + public: + ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {} + + explicit ExeName( std::string &ref ) : ExeName() { + m_ref = std::make_shared<BoundValueRef<std::string>>( ref ); + } + + template<typename LambdaT> + explicit ExeName( LambdaT const& lambda ) : ExeName() { + m_ref = std::make_shared<BoundLambda<LambdaT>>( lambda ); + } + + // The exe name is not parsed out of the normal tokens, but is handled specially + auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { + return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); + } + + auto name() const -> std::string { return *m_name; } + auto set( std::string const& newName ) -> ParserResult { + + auto lastSlash = newName.find_last_of( "\\/" ); + auto filename = ( lastSlash == std::string::npos ) + ? newName + : newName.substr( lastSlash+1 ); + + *m_name = filename; + if( m_ref ) + return m_ref->setValue( filename ); + else + return ParserResult::ok( ParseResultType::Matched ); + } + }; + + class Arg : public ParserRefImpl<Arg> { + public: + using ParserRefImpl::ParserRefImpl; + + auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override { + auto validationResult = validate(); + if( !validationResult ) + return InternalParseResult( validationResult ); + + auto remainingTokens = tokens; + auto const &token = *remainingTokens; + if( token.type != TokenType::Argument ) + return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); + + assert( !m_ref->isFlag() ); + auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() ); + + auto result = valueRef->setValue( remainingTokens->token ); + if( !result ) + return InternalParseResult( result ); + else + return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); + } + }; + + inline auto normaliseOpt( std::string const &optName ) -> std::string { +#ifdef CATCH_PLATFORM_WINDOWS + if( optName[0] == '/' ) + return "-" + optName.substr( 1 ); + else +#endif + return optName; + } + + class Opt : public ParserRefImpl<Opt> { + protected: + std::vector<std::string> m_optNames; + + public: + template<typename LambdaT> + explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared<BoundFlagLambda<LambdaT>>( ref ) ) {} + + explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared<BoundFlagRef>( ref ) ) {} + + template<typename LambdaT> + Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} + + template<typename T> + Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} + + auto operator[]( std::string const &optName ) -> Opt & { + m_optNames.push_back( optName ); + return *this; + } + + auto getHelpColumns() const -> std::vector<HelpColumns> { + std::ostringstream oss; + bool first = true; + for( auto const &opt : m_optNames ) { + if (first) + first = false; + else + oss << ", "; + oss << opt; + } + if( !m_hint.empty() ) + oss << " <" << m_hint << ">"; + return { { oss.str(), m_description } }; + } + + auto isMatch( std::string const &optToken ) const -> bool { + auto normalisedToken = normaliseOpt( optToken ); + for( auto const &name : m_optNames ) { + if( normaliseOpt( name ) == normalisedToken ) + return true; + } + return false; + } + + using ParserBase::parse; + + auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { + auto validationResult = validate(); + if( !validationResult ) + return InternalParseResult( validationResult ); + + auto remainingTokens = tokens; + if( remainingTokens && remainingTokens->type == TokenType::Option ) { + auto const &token = *remainingTokens; + if( isMatch(token.token ) ) { + if( m_ref->isFlag() ) { + auto flagRef = static_cast<detail::BoundFlagRefBase*>( m_ref.get() ); + auto result = flagRef->setFlag( true ); + if( !result ) + return InternalParseResult( result ); + if( result.value() == ParseResultType::ShortCircuitAll ) + return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); + } else { + auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() ); + ++remainingTokens; + if( !remainingTokens ) + return InternalParseResult::runtimeError( "Expected argument following " + token.token ); + auto const &argToken = *remainingTokens; + if( argToken.type != TokenType::Argument ) + return InternalParseResult::runtimeError( "Expected argument following " + token.token ); + auto result = valueRef->setValue( argToken.token ); + if( !result ) + return InternalParseResult( result ); + if( result.value() == ParseResultType::ShortCircuitAll ) + return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); + } + return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); + } + } + return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); + } + + auto validate() const -> Result override { + if( m_optNames.empty() ) + return Result::logicError( "No options supplied to Opt" ); + for( auto const &name : m_optNames ) { + if( name.empty() ) + return Result::logicError( "Option name cannot be empty" ); +#ifdef CATCH_PLATFORM_WINDOWS + if( name[0] != '-' && name[0] != '/' ) + return Result::logicError( "Option name must begin with '-' or '/'" ); +#else + if( name[0] != '-' ) + return Result::logicError( "Option name must begin with '-'" ); +#endif + } + return ParserRefImpl::validate(); + } + }; + + struct Help : Opt { + Help( bool &showHelpFlag ) + : Opt([&]( bool flag ) { + showHelpFlag = flag; + return ParserResult::ok( ParseResultType::ShortCircuitAll ); + }) + { + static_cast<Opt &>( *this ) + ("display usage information") + ["-?"]["-h"]["--help"] + .optional(); + } + }; + + struct Parser : ParserBase { + + mutable ExeName m_exeName; + std::vector<Opt> m_options; + std::vector<Arg> m_args; + + auto operator|=( ExeName const &exeName ) -> Parser & { + m_exeName = exeName; + return *this; + } + + auto operator|=( Arg const &arg ) -> Parser & { + m_args.push_back(arg); + return *this; + } + + auto operator|=( Opt const &opt ) -> Parser & { + m_options.push_back(opt); + return *this; + } + + auto operator|=( Parser const &other ) -> Parser & { + m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end()); + m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end()); + return *this; + } + + template<typename T> + auto operator|( T const &other ) const -> Parser { + return Parser( *this ) |= other; + } + + // Forward deprecated interface with '+' instead of '|' + template<typename T> + auto operator+=( T const &other ) -> Parser & { return operator|=( other ); } + template<typename T> + auto operator+( T const &other ) const -> Parser { return operator|( other ); } + + auto getHelpColumns() const -> std::vector<HelpColumns> { + std::vector<HelpColumns> cols; + for (auto const &o : m_options) { + auto childCols = o.getHelpColumns(); + cols.insert( cols.end(), childCols.begin(), childCols.end() ); + } + return cols; + } + + void writeToStream( std::ostream &os ) const { + if (!m_exeName.name().empty()) { + os << "usage:\n" << " " << m_exeName.name() << " "; + bool required = true, first = true; + for( auto const &arg : m_args ) { + if (first) + first = false; + else + os << " "; + if( arg.isOptional() && required ) { + os << "["; + required = false; + } + os << "<" << arg.hint() << ">"; + if( arg.cardinality() == 0 ) + os << " ... "; + } + if( !required ) + os << "]"; + if( !m_options.empty() ) + os << " options"; + os << "\n\nwhere options are:" << std::endl; + } + + auto rows = getHelpColumns(); + size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH; + size_t optWidth = 0; + for( auto const &cols : rows ) + optWidth = (std::max)(optWidth, cols.left.size() + 2); + + optWidth = (std::min)(optWidth, consoleWidth/2); + + for( auto const &cols : rows ) { + auto row = + TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) + + TextFlow::Spacer(4) + + TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth ); + os << row << std::endl; + } + } + + friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& { + parser.writeToStream( os ); + return os; + } + + auto validate() const -> Result override { + for( auto const &opt : m_options ) { + auto result = opt.validate(); + if( !result ) + return result; + } + for( auto const &arg : m_args ) { + auto result = arg.validate(); + if( !result ) + return result; + } + return Result::ok(); + } + + using ParserBase::parse; + + auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override { + + struct ParserInfo { + ParserBase const* parser = nullptr; + size_t count = 0; + }; + const size_t totalParsers = m_options.size() + m_args.size(); + assert( totalParsers < 512 ); + // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do + ParserInfo parseInfos[512]; + + { + size_t i = 0; + for (auto const &opt : m_options) parseInfos[i++].parser = &opt; + for (auto const &arg : m_args) parseInfos[i++].parser = &arg; + } + + m_exeName.set( exeName ); + + auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); + while( result.value().remainingTokens() ) { + bool tokenParsed = false; + + for( size_t i = 0; i < totalParsers; ++i ) { + auto& parseInfo = parseInfos[i]; + if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) { + result = parseInfo.parser->parse(exeName, result.value().remainingTokens()); + if (!result) + return result; + if (result.value().type() != ParseResultType::NoMatch) { + tokenParsed = true; + ++parseInfo.count; + break; + } + } + } + + if( result.value().type() == ParseResultType::ShortCircuitAll ) + return result; + if( !tokenParsed ) + return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token ); + } + // !TBD Check missing required options + return result; + } + }; + + template<typename DerivedT> + template<typename T> + auto ComposableParserImpl<DerivedT>::operator|( T const &other ) const -> Parser { + return Parser() | static_cast<DerivedT const &>( *this ) | other; + } +} // namespace detail + +// A Combined parser +using detail::Parser; + +// A parser for options +using detail::Opt; + +// A parser for arguments +using detail::Arg; + +// Wrapper for argc, argv from main() +using detail::Args; + +// Specifies the name of the executable +using detail::ExeName; + +// Convenience wrapper for option parser that specifies the help option +using detail::Help; + +// enum of result types from a parse +using detail::ParseResultType; + +// Result type for parser operation +using detail::ParserResult; + +}} // namespace Catch::clara + +// end clara.hpp +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// Restore Clara's value for console width, if present +#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +// end catch_clara.h +namespace Catch { + + clara::Parser makeCommandLineParser( ConfigData& config ); + +} // end namespace Catch + +// end catch_commandline.h +#include <fstream> +#include <ctime> + +namespace Catch { + + clara::Parser makeCommandLineParser( ConfigData& config ) { + + using namespace clara; + + auto const setWarning = [&]( std::string const& warning ) { + auto warningSet = [&]() { + if( warning == "NoAssertions" ) + return WarnAbout::NoAssertions; + + if ( warning == "NoTests" ) + return WarnAbout::NoTests; + + return WarnAbout::Nothing; + }(); + + if (warningSet == WarnAbout::Nothing) + return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" ); + config.warnings = static_cast<WarnAbout::What>( config.warnings | warningSet ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const loadTestNamesFromFile = [&]( std::string const& filename ) { + std::ifstream f( filename.c_str() ); + if( !f.is_open() ) + return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" ); + + std::string line; + while( std::getline( f, line ) ) { + line = trim(line); + if( !line.empty() && !startsWith( line, '#' ) ) { + if( !startsWith( line, '"' ) ) + line = '"' + line + '"'; + config.testsOrTags.push_back( line + ',' ); + } + } + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setTestOrder = [&]( std::string const& order ) { + if( startsWith( "declared", order ) ) + config.runOrder = RunTests::InDeclarationOrder; + else if( startsWith( "lexical", order ) ) + config.runOrder = RunTests::InLexicographicalOrder; + else if( startsWith( "random", order ) ) + config.runOrder = RunTests::InRandomOrder; + else + return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setRngSeed = [&]( std::string const& seed ) { + if( seed != "time" ) + return clara::detail::convertInto( seed, config.rngSeed ); + config.rngSeed = static_cast<unsigned int>( std::time(nullptr) ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setColourUsage = [&]( std::string const& useColour ) { + auto mode = toLower( useColour ); + + if( mode == "yes" ) + config.useColour = UseColour::Yes; + else if( mode == "no" ) + config.useColour = UseColour::No; + else if( mode == "auto" ) + config.useColour = UseColour::Auto; + else + return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setWaitForKeypress = [&]( std::string const& keypress ) { + auto keypressLc = toLower( keypress ); + if( keypressLc == "start" ) + config.waitForKeypress = WaitForKeypress::BeforeStart; + else if( keypressLc == "exit" ) + config.waitForKeypress = WaitForKeypress::BeforeExit; + else if( keypressLc == "both" ) + config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; + else + return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setVerbosity = [&]( std::string const& verbosity ) { + auto lcVerbosity = toLower( verbosity ); + if( lcVerbosity == "quiet" ) + config.verbosity = Verbosity::Quiet; + else if( lcVerbosity == "normal" ) + config.verbosity = Verbosity::Normal; + else if( lcVerbosity == "high" ) + config.verbosity = Verbosity::High; + else + return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" ); + return ParserResult::ok( ParseResultType::Matched ); + }; + + auto cli + = ExeName( config.processName ) + | Help( config.showHelp ) + | Opt( config.listTests ) + ["-l"]["--list-tests"] + ( "list all/matching test cases" ) + | Opt( config.listTags ) + ["-t"]["--list-tags"] + ( "list all/matching tags" ) + | Opt( config.showSuccessfulTests ) + ["-s"]["--success"] + ( "include successful tests in output" ) + | Opt( config.shouldDebugBreak ) + ["-b"]["--break"] + ( "break into debugger on failure" ) + | Opt( config.noThrow ) + ["-e"]["--nothrow"] + ( "skip exception tests" ) + | Opt( config.showInvisibles ) + ["-i"]["--invisibles"] + ( "show invisibles (tabs, newlines)" ) + | Opt( config.outputFilename, "filename" ) + ["-o"]["--out"] + ( "output filename" ) + | Opt( config.reporterName, "name" ) + ["-r"]["--reporter"] + ( "reporter to use (defaults to console)" ) + | Opt( config.name, "name" ) + ["-n"]["--name"] + ( "suite name" ) + | Opt( [&]( bool ){ config.abortAfter = 1; } ) + ["-a"]["--abort"] + ( "abort at first failure" ) + | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" ) + ["-x"]["--abortx"] + ( "abort after x failures" ) + | Opt( setWarning, "warning name" ) + ["-w"]["--warn"] + ( "enable warnings" ) + | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) + ["-d"]["--durations"] + ( "show test durations" ) + | Opt( loadTestNamesFromFile, "filename" ) + ["-f"]["--input-file"] + ( "load test names to run from a file" ) + | Opt( config.filenamesAsTags ) + ["-#"]["--filenames-as-tags"] + ( "adds a tag for the filename" ) + | Opt( config.sectionsToRun, "section name" ) + ["-c"]["--section"] + ( "specify section to run" ) + | Opt( setVerbosity, "quiet|normal|high" ) + ["-v"]["--verbosity"] + ( "set output verbosity" ) + | Opt( config.listTestNamesOnly ) + ["--list-test-names-only"] + ( "list all/matching test cases names only" ) + | Opt( config.listReporters ) + ["--list-reporters"] + ( "list all reporters" ) + | Opt( setTestOrder, "decl|lex|rand" ) + ["--order"] + ( "test case order (defaults to decl)" ) + | Opt( setRngSeed, "'time'|number" ) + ["--rng-seed"] + ( "set a specific seed for random numbers" ) + | Opt( setColourUsage, "yes|no" ) + ["--use-colour"] + ( "should output be colourised" ) + | Opt( config.libIdentify ) + ["--libidentify"] + ( "report name and version according to libidentify standard" ) + | Opt( setWaitForKeypress, "start|exit|both" ) + ["--wait-for-keypress"] + ( "waits for a keypress before exiting" ) + | Opt( config.benchmarkResolutionMultiple, "multiplier" ) + ["--benchmark-resolution-multiple"] + ( "multiple of clock resolution to run benchmarks" ) + + | Arg( config.testsOrTags, "test name|pattern|tags" ) + ( "which test or tests to use" ); + + return cli; + } + +} // end namespace Catch +// end catch_commandline.cpp +// start catch_common.cpp + +#include <cstring> +#include <ostream> + +namespace Catch { + + bool SourceLineInfo::empty() const noexcept { + return file[0] == '\0'; + } + bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept { + return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); + } + bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept { + return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0)); + } + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { +#ifndef __GNUG__ + os << info.file << '(' << info.line << ')'; +#else + os << info.file << ':' << info.line; +#endif + return os; + } + + std::string StreamEndStop::operator+() const { + return std::string(); + } + + NonCopyable::NonCopyable() = default; + NonCopyable::~NonCopyable() = default; + +} +// end catch_common.cpp +// start catch_config.cpp + +// start catch_enforce.h + +#include <stdexcept> + +#define CATCH_PREPARE_EXCEPTION( type, msg ) \ + type( ( Catch::ReusableStringStream() << msg ).str() ) +#define CATCH_INTERNAL_ERROR( msg ) \ + throw CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg); +#define CATCH_ERROR( msg ) \ + throw CATCH_PREPARE_EXCEPTION( std::domain_error, msg ) +#define CATCH_ENFORCE( condition, msg ) \ + do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false) + +// end catch_enforce.h +namespace Catch { + + Config::Config( ConfigData const& data ) + : m_data( data ), + m_stream( openStream() ) + { + TestSpecParser parser(ITagAliasRegistry::get()); + if (data.testsOrTags.empty()) { + parser.parse("~[.]"); // All not hidden tests + } + else { + m_hasTestFilters = true; + for( auto const& testOrTags : data.testsOrTags ) + parser.parse( testOrTags ); + } + m_testSpec = parser.testSpec(); + } + + std::string const& Config::getFilename() const { + return m_data.outputFilename ; + } + + bool Config::listTests() const { return m_data.listTests; } + bool Config::listTestNamesOnly() const { return m_data.listTestNamesOnly; } + bool Config::listTags() const { return m_data.listTags; } + bool Config::listReporters() const { return m_data.listReporters; } + + std::string Config::getProcessName() const { return m_data.processName; } + std::string const& Config::getReporterName() const { return m_data.reporterName; } + + std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; } + std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; } + + TestSpec const& Config::testSpec() const { return m_testSpec; } + bool Config::hasTestFilters() const { return m_hasTestFilters; } + + bool Config::showHelp() const { return m_data.showHelp; } + + // IConfig interface + bool Config::allowThrows() const { return !m_data.noThrow; } + std::ostream& Config::stream() const { return m_stream->stream(); } + std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } + bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; } + bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); } + bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); } + ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } + RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } + unsigned int Config::rngSeed() const { return m_data.rngSeed; } + int Config::benchmarkResolutionMultiple() const { return m_data.benchmarkResolutionMultiple; } + UseColour::YesOrNo Config::useColour() const { return m_data.useColour; } + bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; } + int Config::abortAfter() const { return m_data.abortAfter; } + bool Config::showInvisibles() const { return m_data.showInvisibles; } + Verbosity Config::verbosity() const { return m_data.verbosity; } + + IStream const* Config::openStream() { + return Catch::makeStream(m_data.outputFilename); + } + +} // end namespace Catch +// end catch_config.cpp +// start catch_console_colour.cpp + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +#endif + +// start catch_errno_guard.h + +namespace Catch { + + class ErrnoGuard { + public: + ErrnoGuard(); + ~ErrnoGuard(); + private: + int m_oldErrno; + }; + +} + +// end catch_errno_guard.h +#include <sstream> + +namespace Catch { + namespace { + + struct IColourImpl { + virtual ~IColourImpl() = default; + virtual void use( Colour::Code _colourCode ) = 0; + }; + + struct NoColourImpl : IColourImpl { + void use( Colour::Code ) {} + + static IColourImpl* instance() { + static NoColourImpl s_instance; + return &s_instance; + } + }; + + } // anon namespace +} // namespace Catch + +#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) +# ifdef CATCH_PLATFORM_WINDOWS +# define CATCH_CONFIG_COLOUR_WINDOWS +# else +# define CATCH_CONFIG_COLOUR_ANSI +# endif +#endif + +#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// + +namespace Catch { +namespace { + + class Win32ColourImpl : public IColourImpl { + public: + Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) + { + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); + originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); + originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); + } + + virtual void use( Colour::Code _colourCode ) override { + switch( _colourCode ) { + case Colour::None: return setTextAttribute( originalForegroundAttributes ); + case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + case Colour::Red: return setTextAttribute( FOREGROUND_RED ); + case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); + case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); + case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); + case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); + case Colour::Grey: return setTextAttribute( 0 ); + + case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); + case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); + case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); + case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN ); + + case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); + + default: + CATCH_ERROR( "Unknown colour requested" ); + } + } + + private: + void setTextAttribute( WORD _textAttribute ) { + SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); + } + HANDLE stdoutHandle; + WORD originalForegroundAttributes; + WORD originalBackgroundAttributes; + }; + + IColourImpl* platformColourInstance() { + static Win32ColourImpl s_instance; + + IConfigPtr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = UseColour::Yes; + return colourMode == UseColour::Yes + ? &s_instance + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// + +#include <unistd.h> + +namespace Catch { +namespace { + + // use POSIX/ ANSI console terminal codes + // Thanks to Adam Strzelecki for original contribution + // (http://github.com/nanoant) + // https://github.com/philsquared/Catch/pull/131 + class PosixColourImpl : public IColourImpl { + public: + virtual void use( Colour::Code _colourCode ) override { + switch( _colourCode ) { + case Colour::None: + case Colour::White: return setColour( "[0m" ); + case Colour::Red: return setColour( "[0;31m" ); + case Colour::Green: return setColour( "[0;32m" ); + case Colour::Blue: return setColour( "[0;34m" ); + case Colour::Cyan: return setColour( "[0;36m" ); + case Colour::Yellow: return setColour( "[0;33m" ); + case Colour::Grey: return setColour( "[1;30m" ); + + case Colour::LightGrey: return setColour( "[0;37m" ); + case Colour::BrightRed: return setColour( "[1;31m" ); + case Colour::BrightGreen: return setColour( "[1;32m" ); + case Colour::BrightWhite: return setColour( "[1;37m" ); + case Colour::BrightYellow: return setColour( "[1;33m" ); + + case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); + default: CATCH_INTERNAL_ERROR( "Unknown colour requested" ); + } + } + static IColourImpl* instance() { + static PosixColourImpl s_instance; + return &s_instance; + } + + private: + void setColour( const char* _escapeCode ) { + Catch::cout() << '\033' << _escapeCode; + } + }; + + bool useColourOnPlatform() { + return +#ifdef CATCH_PLATFORM_MAC + !isDebuggerActive() && +#endif +#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__)) + isatty(STDOUT_FILENO) +#else + false +#endif + ; + } + IColourImpl* platformColourInstance() { + ErrnoGuard guard; + IConfigPtr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = useColourOnPlatform() + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes + ? PosixColourImpl::instance() + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#else // not Windows or ANSI /////////////////////////////////////////////// + +namespace Catch { + + static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } + +} // end namespace Catch + +#endif // Windows/ ANSI/ None + +namespace Catch { + + Colour::Colour( Code _colourCode ) { use( _colourCode ); } + Colour::Colour( Colour&& rhs ) noexcept { + m_moved = rhs.m_moved; + rhs.m_moved = true; + } + Colour& Colour::operator=( Colour&& rhs ) noexcept { + m_moved = rhs.m_moved; + rhs.m_moved = true; + return *this; + } + + Colour::~Colour(){ if( !m_moved ) use( None ); } + + void Colour::use( Code _colourCode ) { + static IColourImpl* impl = platformColourInstance(); + impl->use( _colourCode ); + } + + std::ostream& operator << ( std::ostream& os, Colour const& ) { + return os; + } + +} // end namespace Catch + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif + +// end catch_console_colour.cpp +// start catch_context.cpp + +namespace Catch { + + class Context : public IMutableContext, NonCopyable { + + public: // IContext + virtual IResultCapture* getResultCapture() override { + return m_resultCapture; + } + virtual IRunner* getRunner() override { + return m_runner; + } + + virtual IConfigPtr const& getConfig() const override { + return m_config; + } + + virtual ~Context() override; + + public: // IMutableContext + virtual void setResultCapture( IResultCapture* resultCapture ) override { + m_resultCapture = resultCapture; + } + virtual void setRunner( IRunner* runner ) override { + m_runner = runner; + } + virtual void setConfig( IConfigPtr const& config ) override { + m_config = config; + } + + friend IMutableContext& getCurrentMutableContext(); + + private: + IConfigPtr m_config; + IRunner* m_runner = nullptr; + IResultCapture* m_resultCapture = nullptr; + }; + + IMutableContext *IMutableContext::currentContext = nullptr; + + void IMutableContext::createContext() + { + currentContext = new Context(); + } + + void cleanUpContext() { + delete IMutableContext::currentContext; + IMutableContext::currentContext = nullptr; + } + IContext::~IContext() = default; + IMutableContext::~IMutableContext() = default; + Context::~Context() = default; +} +// end catch_context.cpp +// start catch_debug_console.cpp + +// start catch_debug_console.h + +#include <string> + +namespace Catch { + void writeToDebugConsole( std::string const& text ); +} + +// end catch_debug_console.h +#ifdef CATCH_PLATFORM_WINDOWS + + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + ::OutputDebugStringA( text.c_str() ); + } + } + +#else + + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + // !TBD: Need a version for Mac/ XCode and other IDEs + Catch::cout() << text; + } + } + +#endif // Platform +// end catch_debug_console.cpp +// start catch_debugger.cpp + +#ifdef CATCH_PLATFORM_MAC + +# include <assert.h> +# include <stdbool.h> +# include <sys/types.h> +# include <unistd.h> +# include <sys/sysctl.h> +# include <cstddef> +# include <ostream> + +namespace Catch { + + // The following function is taken directly from the following technical note: + // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html + + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive(){ + + int mib[4]; + struct kinfo_proc info; + std::size_t size; + + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + + info.kp_proc.p_flag = 0; + + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + // Call sysctl. + + size = sizeof(info); + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) { + Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; + return false; + } + + // We're being debugged if the P_TRACED flag is set. + + return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); + } + } // namespace Catch + +#elif defined(CATCH_PLATFORM_LINUX) + #include <fstream> + #include <string> + + namespace Catch{ + // The standard POSIX way of detecting a debugger is to attempt to + // ptrace() the process, but this needs to be done from a child and not + // this process itself to still allow attaching to this process later + // if wanted, so is rather heavy. Under Linux we have the PID of the + // "debugger" (which doesn't need to be gdb, of course, it could also + // be strace, for example) in /proc/$PID/status, so just get it from + // there instead. + bool isDebuggerActive(){ + // Libstdc++ has a bug, where std::ifstream sets errno to 0 + // This way our users can properly assert over errno values + ErrnoGuard guard; + std::ifstream in("/proc/self/status"); + for( std::string line; std::getline(in, line); ) { + static const int PREFIX_LEN = 11; + if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) { + // We're traced if the PID is not 0 and no other PID starts + // with 0 digit, so it's enough to check for just a single + // character. + return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; + } + } + + return false; + } + } // namespace Catch +#elif defined(_MSC_VER) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#else + namespace Catch { + bool isDebuggerActive() { return false; } + } +#endif // Platform +// end catch_debugger.cpp +// start catch_decomposer.cpp + +namespace Catch { + + ITransientExpression::~ITransientExpression() = default; + + void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) { + if( lhs.size() + rhs.size() < 40 && + lhs.find('\n') == std::string::npos && + rhs.find('\n') == std::string::npos ) + os << lhs << " " << op << " " << rhs; + else + os << lhs << "\n" << op << "\n" << rhs; + } +} +// end catch_decomposer.cpp +// start catch_errno_guard.cpp + +#include <cerrno> + +namespace Catch { + ErrnoGuard::ErrnoGuard():m_oldErrno(errno){} + ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; } +} +// end catch_errno_guard.cpp +// start catch_exception_translator_registry.cpp + +// start catch_exception_translator_registry.h + +#include <vector> +#include <string> +#include <memory> + +namespace Catch { + + class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { + public: + ~ExceptionTranslatorRegistry(); + virtual void registerTranslator( const IExceptionTranslator* translator ); + virtual std::string translateActiveException() const override; + std::string tryTranslators() const; + + private: + std::vector<std::unique_ptr<IExceptionTranslator const>> m_translators; + }; +} + +// end catch_exception_translator_registry.h +#ifdef __OBJC__ +#import "Foundation/Foundation.h" +#endif + +namespace Catch { + + ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() { + } + + void ExceptionTranslatorRegistry::registerTranslator( const IExceptionTranslator* translator ) { + m_translators.push_back( std::unique_ptr<const IExceptionTranslator>( translator ) ); + } + + std::string ExceptionTranslatorRegistry::translateActiveException() const { + try { +#ifdef __OBJC__ + // In Objective-C try objective-c exceptions first + @try { + return tryTranslators(); + } + @catch (NSException *exception) { + return Catch::Detail::stringify( [exception description] ); + } +#else + // Compiling a mixed mode project with MSVC means that CLR + // exceptions will be caught in (...) as well. However, these + // do not fill-in std::current_exception and thus lead to crash + // when attempting rethrow. + // /EHa switch also causes structured exceptions to be caught + // here, but they fill-in current_exception properly, so + // at worst the output should be a little weird, instead of + // causing a crash. + if (std::current_exception() == nullptr) { + return "Non C++ exception. Possibly a CLR exception."; + } + return tryTranslators(); +#endif + } + catch( TestFailureException& ) { + std::rethrow_exception(std::current_exception()); + } + catch( std::exception& ex ) { + return ex.what(); + } + catch( std::string& msg ) { + return msg; + } + catch( const char* msg ) { + return msg; + } + catch(...) { + return "Unknown exception"; + } + } + + std::string ExceptionTranslatorRegistry::tryTranslators() const { + if( m_translators.empty() ) + std::rethrow_exception(std::current_exception()); + else + return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); + } +} +// end catch_exception_translator_registry.cpp +// start catch_fatal_condition.cpp + +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif + +#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) + +namespace { + // Report the error condition + void reportFatal( char const * const message ) { + Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message ); + } +} + +#endif // signals/SEH handling + +#if defined( CATCH_CONFIG_WINDOWS_SEH ) + +namespace Catch { + struct SignalDefs { DWORD id; const char* name; }; + + // There is no 1-1 mapping between signals and windows exceptions. + // Windows can easily distinguish between SO and SigSegV, + // but SigInt, SigTerm, etc are handled differently. + static SignalDefs signalDefs[] = { + { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" }, + { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" }, + { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" }, + { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" }, + }; + + LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { + for (auto const& def : signalDefs) { + if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { + reportFatal(def.name); + } + } + // If its not an exception we care about, pass it along. + // This stops us from eating debugger breaks etc. + return EXCEPTION_CONTINUE_SEARCH; + } + + FatalConditionHandler::FatalConditionHandler() { + isSet = true; + // 32k seems enough for Catch to handle stack overflow, + // but the value was found experimentally, so there is no strong guarantee + guaranteeSize = 32 * 1024; + exceptionHandlerHandle = nullptr; + // Register as first handler in current chain + exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); + // Pass in guarantee size to be filled + SetThreadStackGuarantee(&guaranteeSize); + } + + void FatalConditionHandler::reset() { + if (isSet) { + RemoveVectoredExceptionHandler(exceptionHandlerHandle); + SetThreadStackGuarantee(&guaranteeSize); + exceptionHandlerHandle = nullptr; + isSet = false; + } + } + + FatalConditionHandler::~FatalConditionHandler() { + reset(); + } + +bool FatalConditionHandler::isSet = false; +ULONG FatalConditionHandler::guaranteeSize = 0; +PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr; + +} // namespace Catch + +#elif defined( CATCH_CONFIG_POSIX_SIGNALS ) + +namespace Catch { + + struct SignalDefs { + int id; + const char* name; + }; + + // 32kb for the alternate stack seems to be sufficient. However, this value + // is experimentally determined, so that's not guaranteed. + constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ; + + static SignalDefs signalDefs[] = { + { SIGINT, "SIGINT - Terminal interrupt signal" }, + { SIGILL, "SIGILL - Illegal instruction signal" }, + { SIGFPE, "SIGFPE - Floating point error signal" }, + { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, + { SIGTERM, "SIGTERM - Termination request signal" }, + { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } + }; + + void FatalConditionHandler::handleSignal( int sig ) { + char const * name = "<unknown signal>"; + for (auto const& def : signalDefs) { + if (sig == def.id) { + name = def.name; + break; + } + } + reset(); + reportFatal(name); + raise( sig ); + } + + FatalConditionHandler::FatalConditionHandler() { + isSet = true; + stack_t sigStack; + sigStack.ss_sp = altStackMem; + sigStack.ss_size = sigStackSize; + sigStack.ss_flags = 0; + sigaltstack(&sigStack, &oldSigStack); + struct sigaction sa = { }; + + sa.sa_handler = handleSignal; + sa.sa_flags = SA_ONSTACK; + for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { + sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); + } + } + + FatalConditionHandler::~FatalConditionHandler() { + reset(); + } + + void FatalConditionHandler::reset() { + if( isSet ) { + // Set signals back to previous values -- hopefully nobody overwrote them in the meantime + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { + sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); + } + // Return the old stack + sigaltstack(&oldSigStack, nullptr); + isSet = false; + } + } + + bool FatalConditionHandler::isSet = false; + struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; + stack_t FatalConditionHandler::oldSigStack = {}; + char FatalConditionHandler::altStackMem[sigStackSize] = {}; + +} // namespace Catch + +#else + +namespace Catch { + void FatalConditionHandler::reset() {} +} + +#endif // signals/SEH handling + +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#endif +// end catch_fatal_condition.cpp +// start catch_interfaces_capture.cpp + +namespace Catch { + IResultCapture::~IResultCapture() = default; +} +// end catch_interfaces_capture.cpp +// start catch_interfaces_config.cpp + +namespace Catch { + IConfig::~IConfig() = default; +} +// end catch_interfaces_config.cpp +// start catch_interfaces_exception.cpp + +namespace Catch { + IExceptionTranslator::~IExceptionTranslator() = default; + IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default; +} +// end catch_interfaces_exception.cpp +// start catch_interfaces_registry_hub.cpp + +namespace Catch { + IRegistryHub::~IRegistryHub() = default; + IMutableRegistryHub::~IMutableRegistryHub() = default; +} +// end catch_interfaces_registry_hub.cpp +// start catch_interfaces_reporter.cpp + +// start catch_reporter_listening.h + +namespace Catch { + + class ListeningReporter : public IStreamingReporter { + using Reporters = std::vector<IStreamingReporterPtr>; + Reporters m_listeners; + IStreamingReporterPtr m_reporter = nullptr; + ReporterPreferences m_preferences; + + public: + ListeningReporter(); + + void addListener( IStreamingReporterPtr&& listener ); + void addReporter( IStreamingReporterPtr&& reporter ); + + public: // IStreamingReporter + + ReporterPreferences getPreferences() const override; + + void noMatchingTestCases( std::string const& spec ) override; + + static std::set<Verbosity> getSupportedVerbosities(); + + void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override; + void benchmarkEnded( BenchmarkStats const& benchmarkStats ) override; + + void testRunStarting( TestRunInfo const& testRunInfo ) override; + void testGroupStarting( GroupInfo const& groupInfo ) override; + void testCaseStarting( TestCaseInfo const& testInfo ) override; + void sectionStarting( SectionInfo const& sectionInfo ) override; + void assertionStarting( AssertionInfo const& assertionInfo ) override; + + // The return value indicates if the messages buffer should be cleared: + bool assertionEnded( AssertionStats const& assertionStats ) override; + void sectionEnded( SectionStats const& sectionStats ) override; + void testCaseEnded( TestCaseStats const& testCaseStats ) override; + void testGroupEnded( TestGroupStats const& testGroupStats ) override; + void testRunEnded( TestRunStats const& testRunStats ) override; + + void skipTest( TestCaseInfo const& testInfo ) override; + bool isMulti() const override; + + }; + +} // end namespace Catch + +// end catch_reporter_listening.h +namespace Catch { + + ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig ) + : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} + + ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ) + : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} + + std::ostream& ReporterConfig::stream() const { return *m_stream; } + IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; } + + TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {} + + GroupInfo::GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ) + : name( _name ), + groupIndex( _groupIndex ), + groupsCounts( _groupsCount ) + {} + + AssertionStats::AssertionStats( AssertionResult const& _assertionResult, + std::vector<MessageInfo> const& _infoMessages, + Totals const& _totals ) + : assertionResult( _assertionResult ), + infoMessages( _infoMessages ), + totals( _totals ) + { + assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression; + + if( assertionResult.hasMessage() ) { + // Copy message into messages list. + // !TBD This should have been done earlier, somewhere + MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); + builder << assertionResult.getMessage(); + builder.m_info.message = builder.m_stream.str(); + + infoMessages.push_back( builder.m_info ); + } + } + + AssertionStats::~AssertionStats() = default; + + SectionStats::SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ) + : sectionInfo( _sectionInfo ), + assertions( _assertions ), + durationInSeconds( _durationInSeconds ), + missingAssertions( _missingAssertions ) + {} + + SectionStats::~SectionStats() = default; + + TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ) + : testInfo( _testInfo ), + totals( _totals ), + stdOut( _stdOut ), + stdErr( _stdErr ), + aborting( _aborting ) + {} + + TestCaseStats::~TestCaseStats() = default; + + TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ) + : groupInfo( _groupInfo ), + totals( _totals ), + aborting( _aborting ) + {} + + TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo ) + : groupInfo( _groupInfo ), + aborting( false ) + {} + + TestGroupStats::~TestGroupStats() = default; + + TestRunStats::TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ) + : runInfo( _runInfo ), + totals( _totals ), + aborting( _aborting ) + {} + + TestRunStats::~TestRunStats() = default; + + void IStreamingReporter::fatalErrorEncountered( StringRef ) {} + bool IStreamingReporter::isMulti() const { return false; } + + IReporterFactory::~IReporterFactory() = default; + IReporterRegistry::~IReporterRegistry() = default; + +} // end namespace Catch +// end catch_interfaces_reporter.cpp +// start catch_interfaces_runner.cpp + +namespace Catch { + IRunner::~IRunner() = default; +} +// end catch_interfaces_runner.cpp +// start catch_interfaces_testcase.cpp + +namespace Catch { + ITestInvoker::~ITestInvoker() = default; + ITestCaseRegistry::~ITestCaseRegistry() = default; +} +// end catch_interfaces_testcase.cpp +// start catch_leak_detector.cpp + +#ifdef CATCH_CONFIG_WINDOWS_CRTDBG +#include <crtdbg.h> + +namespace Catch { + + LeakDetector::LeakDetector() { + int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + flag |= _CRTDBG_LEAK_CHECK_DF; + flag |= _CRTDBG_ALLOC_MEM_DF; + _CrtSetDbgFlag(flag); + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); + // Change this to leaking allocation's number to break there + _CrtSetBreakAlloc(-1); + } +} + +#else + + Catch::LeakDetector::LeakDetector() {} + +#endif +// end catch_leak_detector.cpp +// start catch_list.cpp + +// start catch_list.h + +#include <set> + +namespace Catch { + + std::size_t listTests( Config const& config ); + + std::size_t listTestsNamesOnly( Config const& config ); + + struct TagInfo { + void add( std::string const& spelling ); + std::string all() const; + + std::set<std::string> spellings; + std::size_t count = 0; + }; + + std::size_t listTags( Config const& config ); + + std::size_t listReporters( Config const& /*config*/ ); + + Option<std::size_t> list( Config const& config ); + +} // end namespace Catch + +// end catch_list.h +// start catch_text.h + +namespace Catch { + using namespace clara::TextFlow; +} + +// end catch_text.h +#include <limits> +#include <algorithm> +#include <iomanip> + +namespace Catch { + + std::size_t listTests( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( config.hasTestFilters() ) + Catch::cout() << "Matching test cases:\n"; + else { + Catch::cout() << "All available test cases:\n"; + } + + auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( auto const& testCaseInfo : matchedTestCases ) { + Colour::Code colour = testCaseInfo.isHidden() + ? Colour::SecondaryText + : Colour::None; + Colour colourGuard( colour ); + + Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << "\n"; + if( config.verbosity() >= Verbosity::High ) { + Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl; + std::string description = testCaseInfo.description; + if( description.empty() ) + description = "(NO DESCRIPTION)"; + Catch::cout() << Column( description ).indent(4) << std::endl; + } + if( !testCaseInfo.tags.empty() ) + Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n"; + } + + if( !config.hasTestFilters() ) + Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl; + else + Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl; + return matchedTestCases.size(); + } + + std::size_t listTestsNamesOnly( Config const& config ) { + TestSpec testSpec = config.testSpec(); + std::size_t matchedTests = 0; + std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( auto const& testCaseInfo : matchedTestCases ) { + matchedTests++; + if( startsWith( testCaseInfo.name, '#' ) ) + Catch::cout() << '"' << testCaseInfo.name << '"'; + else + Catch::cout() << testCaseInfo.name; + if ( config.verbosity() >= Verbosity::High ) + Catch::cout() << "\t@" << testCaseInfo.lineInfo; + Catch::cout() << std::endl; + } + return matchedTests; + } + + void TagInfo::add( std::string const& spelling ) { + ++count; + spellings.insert( spelling ); + } + + std::string TagInfo::all() const { + std::string out; + for( auto const& spelling : spellings ) + out += "[" + spelling + "]"; + return out; + } + + std::size_t listTags( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( config.hasTestFilters() ) + Catch::cout() << "Tags for matching test cases:\n"; + else { + Catch::cout() << "All available tags:\n"; + } + + std::map<std::string, TagInfo> tagCounts; + + std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( auto const& testCase : matchedTestCases ) { + for( auto const& tagName : testCase.getTestCaseInfo().tags ) { + std::string lcaseTagName = toLower( tagName ); + auto countIt = tagCounts.find( lcaseTagName ); + if( countIt == tagCounts.end() ) + countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; + countIt->second.add( tagName ); + } + } + + for( auto const& tagCount : tagCounts ) { + ReusableStringStream rss; + rss << " " << std::setw(2) << tagCount.second.count << " "; + auto str = rss.str(); + auto wrapper = Column( tagCount.second.all() ) + .initialIndent( 0 ) + .indent( str.size() ) + .width( CATCH_CONFIG_CONSOLE_WIDTH-10 ); + Catch::cout() << str << wrapper << '\n'; + } + Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; + return tagCounts.size(); + } + + std::size_t listReporters( Config const& /*config*/ ) { + Catch::cout() << "Available reporters:\n"; + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + std::size_t maxNameLen = 0; + for( auto const& factoryKvp : factories ) + maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() ); + + for( auto const& factoryKvp : factories ) { + Catch::cout() + << Column( factoryKvp.first + ":" ) + .indent(2) + .width( 5+maxNameLen ) + + Column( factoryKvp.second->getDescription() ) + .initialIndent(0) + .indent(2) + .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) + << "\n"; + } + Catch::cout() << std::endl; + return factories.size(); + } + + Option<std::size_t> list( Config const& config ) { + Option<std::size_t> listedCount; + if( config.listTests() ) + listedCount = listedCount.valueOr(0) + listTests( config ); + if( config.listTestNamesOnly() ) + listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); + if( config.listTags() ) + listedCount = listedCount.valueOr(0) + listTags( config ); + if( config.listReporters() ) + listedCount = listedCount.valueOr(0) + listReporters( config ); + return listedCount; + } + +} // end namespace Catch +// end catch_list.cpp +// start catch_matchers.cpp + +namespace Catch { +namespace Matchers { + namespace Impl { + + std::string MatcherUntypedBase::toString() const { + if( m_cachedToString.empty() ) + m_cachedToString = describe(); + return m_cachedToString; + } + + MatcherUntypedBase::~MatcherUntypedBase() = default; + + } // namespace Impl +} // namespace Matchers + +using namespace Matchers; +using Matchers::Impl::MatcherBase; + +} // namespace Catch +// end catch_matchers.cpp +// start catch_matchers_floating.cpp + +// start catch_to_string.hpp + +#include <string> + +namespace Catch { + template <typename T> + std::string to_string(T const& t) { +#if defined(CATCH_CONFIG_CPP11_TO_STRING) + return std::to_string(t); +#else + ReusableStringStream rss; + rss << t; + return rss.str(); +#endif + } +} // end namespace Catch + +// end catch_to_string.hpp +#include <cstdlib> +#include <cstdint> +#include <cstring> +#include <stdexcept> + +namespace Catch { +namespace Matchers { +namespace Floating { +enum class FloatingPointKind : uint8_t { + Float, + Double +}; +} +} +} + +namespace { + +template <typename T> +struct Converter; + +template <> +struct Converter<float> { + static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated"); + Converter(float f) { + std::memcpy(&i, &f, sizeof(f)); + } + int32_t i; +}; + +template <> +struct Converter<double> { + static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated"); + Converter(double d) { + std::memcpy(&i, &d, sizeof(d)); + } + int64_t i; +}; + +template <typename T> +auto convert(T t) -> Converter<T> { + return Converter<T>(t); +} + +template <typename FP> +bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) { + // Comparison with NaN should always be false. + // This way we can rule it out before getting into the ugly details + if (std::isnan(lhs) || std::isnan(rhs)) { + return false; + } + + auto lc = convert(lhs); + auto rc = convert(rhs); + + if ((lc.i < 0) != (rc.i < 0)) { + // Potentially we can have +0 and -0 + return lhs == rhs; + } + + auto ulpDiff = std::abs(lc.i - rc.i); + return ulpDiff <= maxUlpDiff; +} + +} + +namespace Catch { +namespace Matchers { +namespace Floating { + WithinAbsMatcher::WithinAbsMatcher(double target, double margin) + :m_target{ target }, m_margin{ margin } { + if (m_margin < 0) { + throw std::domain_error("Allowed margin difference has to be >= 0"); + } + } + + // Performs equivalent check of std::fabs(lhs - rhs) <= margin + // But without the subtraction to allow for INFINITY in comparison + bool WithinAbsMatcher::match(double const& matchee) const { + return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee); + } + + std::string WithinAbsMatcher::describe() const { + return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target); + } + + WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType) + :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } { + if (m_ulps < 0) { + throw std::domain_error("Allowed ulp difference has to be >= 0"); + } + } + + bool WithinUlpsMatcher::match(double const& matchee) const { + switch (m_type) { + case FloatingPointKind::Float: + return almostEqualUlps<float>(static_cast<float>(matchee), static_cast<float>(m_target), m_ulps); + case FloatingPointKind::Double: + return almostEqualUlps<double>(matchee, m_target, m_ulps); + default: + throw std::domain_error("Unknown FloatingPointKind value"); + } + } + + std::string WithinUlpsMatcher::describe() const { + return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : ""); + } + +}// namespace Floating + +Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff) { + return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double); +} + +Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff) { + return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float); +} + +Floating::WithinAbsMatcher WithinAbs(double target, double margin) { + return Floating::WithinAbsMatcher(target, margin); +} + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_floating.cpp +// start catch_matchers_generic.cpp + +std::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) { + if (desc.empty()) { + return "matches undescribed predicate"; + } else { + return "matches predicate: \"" + desc + '"'; + } +} +// end catch_matchers_generic.cpp +// start catch_matchers_string.cpp + +#include <regex> + +namespace Catch { +namespace Matchers { + + namespace StdString { + + CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_str( adjustString( str ) ) + {} + std::string CasedString::adjustString( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No + ? toLower( str ) + : str; + } + std::string CasedString::caseSensitivitySuffix() const { + return m_caseSensitivity == CaseSensitive::No + ? " (case insensitive)" + : std::string(); + } + + StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator ) + : m_comparator( comparator ), + m_operation( operation ) { + } + + std::string StringMatcherBase::describe() const { + std::string description; + description.reserve(5 + m_operation.size() + m_comparator.m_str.size() + + m_comparator.caseSensitivitySuffix().size()); + description += m_operation; + description += ": \""; + description += m_comparator.m_str; + description += "\""; + description += m_comparator.caseSensitivitySuffix(); + return description; + } + + EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {} + + bool EqualsMatcher::match( std::string const& source ) const { + return m_comparator.adjustString( source ) == m_comparator.m_str; + } + + ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {} + + bool ContainsMatcher::match( std::string const& source ) const { + return contains( m_comparator.adjustString( source ), m_comparator.m_str ); + } + + StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {} + + bool StartsWithMatcher::match( std::string const& source ) const { + return startsWith( m_comparator.adjustString( source ), m_comparator.m_str ); + } + + EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {} + + bool EndsWithMatcher::match( std::string const& source ) const { + return endsWith( m_comparator.adjustString( source ), m_comparator.m_str ); + } + + RegexMatcher::RegexMatcher(std::string regex, CaseSensitive::Choice caseSensitivity): m_regex(std::move(regex)), m_caseSensitivity(caseSensitivity) {} + + bool RegexMatcher::match(std::string const& matchee) const { + auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway + if (m_caseSensitivity == CaseSensitive::Choice::No) { + flags |= std::regex::icase; + } + auto reg = std::regex(m_regex, flags); + return std::regex_match(matchee, reg); + } + + std::string RegexMatcher::describe() const { + return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Choice::Yes)? " case sensitively" : " case insensitively"); + } + + } // namespace StdString + + StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) { + return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) ); + } + StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) { + return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) ); + } + StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { + return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) ); + } + StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { + return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) ); + } + + StdString::RegexMatcher Matches(std::string const& regex, CaseSensitive::Choice caseSensitivity) { + return StdString::RegexMatcher(regex, caseSensitivity); + } + +} // namespace Matchers +} // namespace Catch +// end catch_matchers_string.cpp +// start catch_message.cpp + +// start catch_uncaught_exceptions.h + +namespace Catch { + bool uncaught_exceptions(); +} // end namespace Catch + +// end catch_uncaught_exceptions.h +namespace Catch { + + MessageInfo::MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + type( _type ), + sequence( ++globalCount ) + {} + + bool MessageInfo::operator==( MessageInfo const& other ) const { + return sequence == other.sequence; + } + + bool MessageInfo::operator<( MessageInfo const& other ) const { + return sequence < other.sequence; + } + + // This may need protecting if threading support is added + unsigned int MessageInfo::globalCount = 0; + + //////////////////////////////////////////////////////////////////////////// + + Catch::MessageBuilder::MessageBuilder( std::string const& macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType type ) + :m_info(macroName, lineInfo, type) {} + + //////////////////////////////////////////////////////////////////////////// + + ScopedMessage::ScopedMessage( MessageBuilder const& builder ) + : m_info( builder.m_info ) + { + m_info.message = builder.m_stream.str(); + getResultCapture().pushScopedMessage( m_info ); + } + + ScopedMessage::~ScopedMessage() { + if ( !uncaught_exceptions() ){ + getResultCapture().popScopedMessage(m_info); + } + } +} // end namespace Catch +// end catch_message.cpp +// start catch_output_redirect.cpp + +// start catch_output_redirect.h +#ifndef TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H +#define TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H + +#include <cstdio> +#include <iosfwd> +#include <string> + +namespace Catch { + + class RedirectedStream { + std::ostream& m_originalStream; + std::ostream& m_redirectionStream; + std::streambuf* m_prevBuf; + + public: + RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ); + ~RedirectedStream(); + }; + + class RedirectedStdOut { + ReusableStringStream m_rss; + RedirectedStream m_cout; + public: + RedirectedStdOut(); + auto str() const -> std::string; + }; + + // StdErr has two constituent streams in C++, std::cerr and std::clog + // This means that we need to redirect 2 streams into 1 to keep proper + // order of writes + class RedirectedStdErr { + ReusableStringStream m_rss; + RedirectedStream m_cerr; + RedirectedStream m_clog; + public: + RedirectedStdErr(); + auto str() const -> std::string; + }; + +#if defined(CATCH_CONFIG_NEW_CAPTURE) + + // Windows's implementation of std::tmpfile is terrible (it tries + // to create a file inside system folder, thus requiring elevated + // privileges for the binary), so we have to use tmpnam(_s) and + // create the file ourselves there. + class TempFile { + public: + TempFile(TempFile const&) = delete; + TempFile& operator=(TempFile const&) = delete; + TempFile(TempFile&&) = delete; + TempFile& operator=(TempFile&&) = delete; + + TempFile(); + ~TempFile(); + + std::FILE* getFile(); + std::string getContents(); + + private: + std::FILE* m_file = nullptr; + #if defined(_MSC_VER) + char m_buffer[L_tmpnam] = { 0 }; + #endif + }; + + class OutputRedirect { + public: + OutputRedirect(OutputRedirect const&) = delete; + OutputRedirect& operator=(OutputRedirect const&) = delete; + OutputRedirect(OutputRedirect&&) = delete; + OutputRedirect& operator=(OutputRedirect&&) = delete; + + OutputRedirect(std::string& stdout_dest, std::string& stderr_dest); + ~OutputRedirect(); + + private: + int m_originalStdout = -1; + int m_originalStderr = -1; + TempFile m_stdoutFile; + TempFile m_stderrFile; + std::string& m_stdoutDest; + std::string& m_stderrDest; + }; + +#endif + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H +// end catch_output_redirect.h +#include <cstdio> +#include <cstring> +#include <fstream> +#include <sstream> +#include <stdexcept> + +#if defined(CATCH_CONFIG_NEW_CAPTURE) + #if defined(_MSC_VER) + #include <io.h> //_dup and _dup2 + #define dup _dup + #define dup2 _dup2 + #define fileno _fileno + #else + #include <unistd.h> // dup and dup2 + #endif +#endif + +namespace Catch { + + RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ) + : m_originalStream( originalStream ), + m_redirectionStream( redirectionStream ), + m_prevBuf( m_originalStream.rdbuf() ) + { + m_originalStream.rdbuf( m_redirectionStream.rdbuf() ); + } + + RedirectedStream::~RedirectedStream() { + m_originalStream.rdbuf( m_prevBuf ); + } + + RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {} + auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); } + + RedirectedStdErr::RedirectedStdErr() + : m_cerr( Catch::cerr(), m_rss.get() ), + m_clog( Catch::clog(), m_rss.get() ) + {} + auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); } + +#if defined(CATCH_CONFIG_NEW_CAPTURE) + +#if defined(_MSC_VER) + TempFile::TempFile() { + if (tmpnam_s(m_buffer)) { + throw std::runtime_error("Could not get a temp filename"); + } + if (fopen_s(&m_file, m_buffer, "w")) { + char buffer[100]; + if (strerror_s(buffer, errno)) { + throw std::runtime_error("Could not translate errno to string"); + } + throw std::runtime_error("Could not open the temp file: " + std::string(m_buffer) + buffer); + } + } +#else + TempFile::TempFile() { + m_file = std::tmpfile(); + if (!m_file) { + throw std::runtime_error("Could not create a temp file."); + } + } + +#endif + + TempFile::~TempFile() { + // TBD: What to do about errors here? + std::fclose(m_file); + // We manually create the file on Windows only, on Linux + // it will be autodeleted +#if defined(_MSC_VER) + std::remove(m_buffer); +#endif + } + + FILE* TempFile::getFile() { + return m_file; + } + + std::string TempFile::getContents() { + std::stringstream sstr; + char buffer[100] = {}; + std::rewind(m_file); + while (std::fgets(buffer, sizeof(buffer), m_file)) { + sstr << buffer; + } + return sstr.str(); + } + + OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) : + m_originalStdout(dup(1)), + m_originalStderr(dup(2)), + m_stdoutDest(stdout_dest), + m_stderrDest(stderr_dest) { + dup2(fileno(m_stdoutFile.getFile()), 1); + dup2(fileno(m_stderrFile.getFile()), 2); + } + + OutputRedirect::~OutputRedirect() { + Catch::cout() << std::flush; + fflush(stdout); + // Since we support overriding these streams, we flush cerr + // even though std::cerr is unbuffered + Catch::cerr() << std::flush; + Catch::clog() << std::flush; + fflush(stderr); + + dup2(m_originalStdout, 1); + dup2(m_originalStderr, 2); + + m_stdoutDest += m_stdoutFile.getContents(); + m_stderrDest += m_stderrFile.getContents(); + } + +#endif // CATCH_CONFIG_NEW_CAPTURE + +} // namespace Catch + +#if defined(CATCH_CONFIG_NEW_CAPTURE) + #if defined(_MSC_VER) + #undef dup + #undef dup2 + #undef fileno + #endif +#endif +// end catch_output_redirect.cpp +// start catch_random_number_generator.cpp + +// start catch_random_number_generator.h + +#include <algorithm> +#include <random> + +namespace Catch { + + struct IConfig; + + std::mt19937& rng(); + void seedRng( IConfig const& config ); + unsigned int rngSeed(); + +} + +// end catch_random_number_generator.h +namespace Catch { + + std::mt19937& rng() { + static std::mt19937 s_rng; + return s_rng; + } + + void seedRng( IConfig const& config ) { + if( config.rngSeed() != 0 ) { + std::srand( config.rngSeed() ); + rng().seed( config.rngSeed() ); + } + } + + unsigned int rngSeed() { + return getCurrentContext().getConfig()->rngSeed(); + } +} +// end catch_random_number_generator.cpp +// start catch_registry_hub.cpp + +// start catch_test_case_registry_impl.h + +#include <vector> +#include <set> +#include <algorithm> +#include <ios> + +namespace Catch { + + class TestCase; + struct IConfig; + + std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ); + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + + void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ); + + std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ); + + class TestRegistry : public ITestCaseRegistry { + public: + virtual ~TestRegistry() = default; + + virtual void registerTest( TestCase const& testCase ); + + std::vector<TestCase> const& getAllTests() const override; + std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const override; + + private: + std::vector<TestCase> m_functions; + mutable RunTests::InWhatOrder m_currentSortOrder = RunTests::InDeclarationOrder; + mutable std::vector<TestCase> m_sortedFunctions; + std::size_t m_unnamedCount = 0; + std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised + }; + + /////////////////////////////////////////////////////////////////////////// + + class TestInvokerAsFunction : public ITestInvoker { + void(*m_testAsFunction)(); + public: + TestInvokerAsFunction( void(*testAsFunction)() ) noexcept; + + void invoke() const override; + }; + + std::string extractClassName( StringRef const& classOrQualifiedMethodName ); + + /////////////////////////////////////////////////////////////////////////// + +} // end namespace Catch + +// end catch_test_case_registry_impl.h +// start catch_reporter_registry.h + +#include <map> + +namespace Catch { + + class ReporterRegistry : public IReporterRegistry { + + public: + + ~ReporterRegistry() override; + + IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const override; + + void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ); + void registerListener( IReporterFactoryPtr const& factory ); + + FactoryMap const& getFactories() const override; + Listeners const& getListeners() const override; + + private: + FactoryMap m_factories; + Listeners m_listeners; + }; +} + +// end catch_reporter_registry.h +// start catch_tag_alias_registry.h + +// start catch_tag_alias.h + +#include <string> + +namespace Catch { + + struct TagAlias { + TagAlias(std::string const& _tag, SourceLineInfo _lineInfo); + + std::string tag; + SourceLineInfo lineInfo; + }; + +} // end namespace Catch + +// end catch_tag_alias.h +#include <map> + +namespace Catch { + + class TagAliasRegistry : public ITagAliasRegistry { + public: + ~TagAliasRegistry() override; + TagAlias const* find( std::string const& alias ) const override; + std::string expandAliases( std::string const& unexpandedTestSpec ) const override; + void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ); + + private: + std::map<std::string, TagAlias> m_registry; + }; + +} // end namespace Catch + +// end catch_tag_alias_registry.h +// start catch_startup_exception_registry.h + +#include <vector> +#include <exception> + +namespace Catch { + + class StartupExceptionRegistry { + public: + void add(std::exception_ptr const& exception) noexcept; + std::vector<std::exception_ptr> const& getExceptions() const noexcept; + private: + std::vector<std::exception_ptr> m_exceptions; + }; + +} // end namespace Catch + +// end catch_startup_exception_registry.h +namespace Catch { + + namespace { + + class RegistryHub : public IRegistryHub, public IMutableRegistryHub, + private NonCopyable { + + public: // IRegistryHub + RegistryHub() = default; + IReporterRegistry const& getReporterRegistry() const override { + return m_reporterRegistry; + } + ITestCaseRegistry const& getTestCaseRegistry() const override { + return m_testCaseRegistry; + } + IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() override { + return m_exceptionTranslatorRegistry; + } + ITagAliasRegistry const& getTagAliasRegistry() const override { + return m_tagAliasRegistry; + } + StartupExceptionRegistry const& getStartupExceptionRegistry() const override { + return m_exceptionRegistry; + } + + public: // IMutableRegistryHub + void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) override { + m_reporterRegistry.registerReporter( name, factory ); + } + void registerListener( IReporterFactoryPtr const& factory ) override { + m_reporterRegistry.registerListener( factory ); + } + void registerTest( TestCase const& testInfo ) override { + m_testCaseRegistry.registerTest( testInfo ); + } + void registerTranslator( const IExceptionTranslator* translator ) override { + m_exceptionTranslatorRegistry.registerTranslator( translator ); + } + void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override { + m_tagAliasRegistry.add( alias, tag, lineInfo ); + } + void registerStartupException() noexcept override { + m_exceptionRegistry.add(std::current_exception()); + } + + private: + TestRegistry m_testCaseRegistry; + ReporterRegistry m_reporterRegistry; + ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; + TagAliasRegistry m_tagAliasRegistry; + StartupExceptionRegistry m_exceptionRegistry; + }; + + // Single, global, instance + RegistryHub*& getTheRegistryHub() { + static RegistryHub* theRegistryHub = nullptr; + if( !theRegistryHub ) + theRegistryHub = new RegistryHub(); + return theRegistryHub; + } + } + + IRegistryHub& getRegistryHub() { + return *getTheRegistryHub(); + } + IMutableRegistryHub& getMutableRegistryHub() { + return *getTheRegistryHub(); + } + void cleanUp() { + delete getTheRegistryHub(); + getTheRegistryHub() = nullptr; + cleanUpContext(); + ReusableStringStream::cleanup(); + } + std::string translateActiveException() { + return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); + } + +} // end namespace Catch +// end catch_registry_hub.cpp +// start catch_reporter_registry.cpp + +namespace Catch { + + ReporterRegistry::~ReporterRegistry() = default; + + IStreamingReporterPtr ReporterRegistry::create( std::string const& name, IConfigPtr const& config ) const { + auto it = m_factories.find( name ); + if( it == m_factories.end() ) + return nullptr; + return it->second->create( ReporterConfig( config ) ); + } + + void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) { + m_factories.emplace(name, factory); + } + void ReporterRegistry::registerListener( IReporterFactoryPtr const& factory ) { + m_listeners.push_back( factory ); + } + + IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const { + return m_factories; + } + IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const { + return m_listeners; + } + +} +// end catch_reporter_registry.cpp +// start catch_result_type.cpp + +namespace Catch { + + bool isOk( ResultWas::OfType resultType ) { + return ( resultType & ResultWas::FailureBit ) == 0; + } + bool isJustInfo( int flags ) { + return flags == ResultWas::Info; + } + + ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { + return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) ); + } + + bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } + bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } + +} // end namespace Catch +// end catch_result_type.cpp +// start catch_run_context.cpp + +#include <cassert> +#include <algorithm> +#include <sstream> + +namespace Catch { + + RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) + : m_runInfo(_config->name()), + m_context(getCurrentMutableContext()), + m_config(_config), + m_reporter(std::move(reporter)), + m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal }, + m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions ) + { + m_context.setRunner(this); + m_context.setConfig(m_config); + m_context.setResultCapture(this); + m_reporter->testRunStarting(m_runInfo); + } + + RunContext::~RunContext() { + m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting())); + } + + void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) { + m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount)); + } + + void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount) { + m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting())); + } + + Totals RunContext::runTest(TestCase const& testCase) { + Totals prevTotals = m_totals; + + std::string redirectedCout; + std::string redirectedCerr; + + auto const& testInfo = testCase.getTestCaseInfo(); + + m_reporter->testCaseStarting(testInfo); + + m_activeTestCase = &testCase; + + ITracker& rootTracker = m_trackerContext.startRun(); + assert(rootTracker.isSectionTracker()); + static_cast<SectionTracker&>(rootTracker).addInitialFilters(m_config->getSectionsToRun()); + do { + m_trackerContext.startCycle(); + m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo)); + runCurrentTest(redirectedCout, redirectedCerr); + } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting()); + + Totals deltaTotals = m_totals.delta(prevTotals); + if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) { + deltaTotals.assertions.failed++; + deltaTotals.testCases.passed--; + deltaTotals.testCases.failed++; + } + m_totals.testCases += deltaTotals.testCases; + m_reporter->testCaseEnded(TestCaseStats(testInfo, + deltaTotals, + redirectedCout, + redirectedCerr, + aborting())); + + m_activeTestCase = nullptr; + m_testCaseTracker = nullptr; + + return deltaTotals; + } + + IConfigPtr RunContext::config() const { + return m_config; + } + + IStreamingReporter& RunContext::reporter() const { + return *m_reporter; + } + + void RunContext::assertionEnded(AssertionResult const & result) { + if (result.getResultType() == ResultWas::Ok) { + m_totals.assertions.passed++; + m_lastAssertionPassed = true; + } else if (!result.isOk()) { + m_lastAssertionPassed = false; + if( m_activeTestCase->getTestCaseInfo().okToFail() ) + m_totals.assertions.failedButOk++; + else + m_totals.assertions.failed++; + } + else { + m_lastAssertionPassed = true; + } + + // We have no use for the return value (whether messages should be cleared), because messages were made scoped + // and should be let to clear themselves out. + static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); + + // Reset working state + resetAssertionInfo(); + m_lastResult = result; + } + void RunContext::resetAssertionInfo() { + m_lastAssertionInfo.macroName = StringRef(); + m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr; + } + + bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) { + ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo)); + if (!sectionTracker.isOpen()) + return false; + m_activeSections.push_back(§ionTracker); + + m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; + + m_reporter->sectionStarting(sectionInfo); + + assertions = m_totals.assertions; + + return true; + } + + bool RunContext::testForMissingAssertions(Counts& assertions) { + if (assertions.total() != 0) + return false; + if (!m_config->warnAboutMissingAssertions()) + return false; + if (m_trackerContext.currentTracker().hasChildren()) + return false; + m_totals.assertions.failed++; + assertions.failed++; + return true; + } + + void RunContext::sectionEnded(SectionEndInfo const & endInfo) { + Counts assertions = m_totals.assertions - endInfo.prevAssertions; + bool missingAssertions = testForMissingAssertions(assertions); + + if (!m_activeSections.empty()) { + m_activeSections.back()->close(); + m_activeSections.pop_back(); + } + + m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions)); + m_messages.clear(); + } + + void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) { + if (m_unfinishedSections.empty()) + m_activeSections.back()->fail(); + else + m_activeSections.back()->close(); + m_activeSections.pop_back(); + + m_unfinishedSections.push_back(endInfo); + } + void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { + m_reporter->benchmarkStarting( info ); + } + void RunContext::benchmarkEnded( BenchmarkStats const& stats ) { + m_reporter->benchmarkEnded( stats ); + } + + void RunContext::pushScopedMessage(MessageInfo const & message) { + m_messages.push_back(message); + } + + void RunContext::popScopedMessage(MessageInfo const & message) { + m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); + } + + std::string RunContext::getCurrentTestName() const { + return m_activeTestCase + ? m_activeTestCase->getTestCaseInfo().name + : std::string(); + } + + const AssertionResult * RunContext::getLastResult() const { + return &(*m_lastResult); + } + + void RunContext::exceptionEarlyReported() { + m_shouldReportUnexpected = false; + } + + void RunContext::handleFatalErrorCondition( StringRef message ) { + // First notify reporter that bad things happened + m_reporter->fatalErrorEncountered(message); + + // Don't rebuild the result -- the stringification itself can cause more fatal errors + // Instead, fake a result data. + AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } ); + tempResult.message = message; + AssertionResult result(m_lastAssertionInfo, tempResult); + + assertionEnded(result); + + handleUnfinishedSections(); + + // Recreate section for test case (as we will lose the one that was in scope) + auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); + + Counts assertions; + assertions.failed = 1; + SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false); + m_reporter->sectionEnded(testCaseSectionStats); + + auto const& testInfo = m_activeTestCase->getTestCaseInfo(); + + Totals deltaTotals; + deltaTotals.testCases.failed = 1; + deltaTotals.assertions.failed = 1; + m_reporter->testCaseEnded(TestCaseStats(testInfo, + deltaTotals, + std::string(), + std::string(), + false)); + m_totals.testCases.failed++; + testGroupEnded(std::string(), m_totals, 1, 1); + m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false)); + } + + bool RunContext::lastAssertionPassed() { + return m_lastAssertionPassed; + } + + void RunContext::assertionPassed() { + m_lastAssertionPassed = true; + ++m_totals.assertions.passed; + resetAssertionInfo(); + } + + bool RunContext::aborting() const { + return m_totals.assertions.failed == static_cast<std::size_t>(m_config->abortAfter()); + } + + void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) { + auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); + m_reporter->sectionStarting(testCaseSection); + Counts prevAssertions = m_totals.assertions; + double duration = 0; + m_shouldReportUnexpected = true; + m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal }; + + seedRng(*m_config); + + Timer timer; + try { + if (m_reporter->getPreferences().shouldRedirectStdOut) { +#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) + RedirectedStdOut redirectedStdOut; + RedirectedStdErr redirectedStdErr; + + timer.start(); + invokeActiveTestCase(); + redirectedCout += redirectedStdOut.str(); + redirectedCerr += redirectedStdErr.str(); +#else + OutputRedirect r(redirectedCout, redirectedCerr); + timer.start(); + invokeActiveTestCase(); +#endif + } else { + timer.start(); + invokeActiveTestCase(); + } + duration = timer.getElapsedSeconds(); + } catch (TestFailureException&) { + // This just means the test was aborted due to failure + } catch (...) { + // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions + // are reported without translation at the point of origin. + if( m_shouldReportUnexpected ) { + AssertionReaction dummyReaction; + handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction ); + } + } + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions(assertions); + + m_testCaseTracker->close(); + handleUnfinishedSections(); + m_messages.clear(); + + SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); + m_reporter->sectionEnded(testCaseSectionStats); + } + + void RunContext::invokeActiveTestCase() { + FatalConditionHandler fatalConditionHandler; // Handle signals + m_activeTestCase->invoke(); + fatalConditionHandler.reset(); + } + + void RunContext::handleUnfinishedSections() { + // If sections ended prematurely due to an exception we stored their + // infos here so we can tear them down outside the unwind process. + for (auto it = m_unfinishedSections.rbegin(), + itEnd = m_unfinishedSections.rend(); + it != itEnd; + ++it) + sectionEnded(*it); + m_unfinishedSections.clear(); + } + + void RunContext::handleExpr( + AssertionInfo const& info, + ITransientExpression const& expr, + AssertionReaction& reaction + ) { + m_reporter->assertionStarting( info ); + + bool negated = isFalseTest( info.resultDisposition ); + bool result = expr.getResult() != negated; + + if( result ) { + if (!m_includeSuccessfulResults) { + assertionPassed(); + } + else { + reportExpr(info, ResultWas::Ok, &expr, negated); + } + } + else { + reportExpr(info, ResultWas::ExpressionFailed, &expr, negated ); + populateReaction( reaction ); + } + } + void RunContext::reportExpr( + AssertionInfo const &info, + ResultWas::OfType resultType, + ITransientExpression const *expr, + bool negated ) { + + m_lastAssertionInfo = info; + AssertionResultData data( resultType, LazyExpression( negated ) ); + + AssertionResult assertionResult{ info, data }; + assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; + + assertionEnded( assertionResult ); + } + + void RunContext::handleMessage( + AssertionInfo const& info, + ResultWas::OfType resultType, + StringRef const& message, + AssertionReaction& reaction + ) { + m_reporter->assertionStarting( info ); + + m_lastAssertionInfo = info; + + AssertionResultData data( resultType, LazyExpression( false ) ); + data.message = message; + AssertionResult assertionResult{ m_lastAssertionInfo, data }; + assertionEnded( assertionResult ); + if( !assertionResult.isOk() ) + populateReaction( reaction ); + } + void RunContext::handleUnexpectedExceptionNotThrown( + AssertionInfo const& info, + AssertionReaction& reaction + ) { + handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction); + } + + void RunContext::handleUnexpectedInflightException( + AssertionInfo const& info, + std::string const& message, + AssertionReaction& reaction + ) { + m_lastAssertionInfo = info; + + AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); + data.message = message; + AssertionResult assertionResult{ info, data }; + assertionEnded( assertionResult ); + populateReaction( reaction ); + } + + void RunContext::populateReaction( AssertionReaction& reaction ) { + reaction.shouldDebugBreak = m_config->shouldDebugBreak(); + reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal); + } + + void RunContext::handleIncomplete( + AssertionInfo const& info + ) { + m_lastAssertionInfo = info; + + AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); + data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; + AssertionResult assertionResult{ info, data }; + assertionEnded( assertionResult ); + } + void RunContext::handleNonExpr( + AssertionInfo const &info, + ResultWas::OfType resultType, + AssertionReaction &reaction + ) { + m_lastAssertionInfo = info; + + AssertionResultData data( resultType, LazyExpression( false ) ); + AssertionResult assertionResult{ info, data }; + assertionEnded( assertionResult ); + + if( !assertionResult.isOk() ) + populateReaction( reaction ); + } + + IResultCapture& getResultCapture() { + if (auto* capture = getCurrentContext().getResultCapture()) + return *capture; + else + CATCH_INTERNAL_ERROR("No result capture instance"); + } +} +// end catch_run_context.cpp +// start catch_section.cpp + +namespace Catch { + + Section::Section( SectionInfo const& info ) + : m_info( info ), + m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) + { + m_timer.start(); + } + + Section::~Section() { + if( m_sectionIncluded ) { + SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() }; + if( uncaught_exceptions() ) + getResultCapture().sectionEndedEarly( endInfo ); + else + getResultCapture().sectionEnded( endInfo ); + } + } + + // This indicates whether the section should be executed or not + Section::operator bool() const { + return m_sectionIncluded; + } + +} // end namespace Catch +// end catch_section.cpp +// start catch_section_info.cpp + +namespace Catch { + + SectionInfo::SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name ) + : name( _name ), + lineInfo( _lineInfo ) + {} + +} // end namespace Catch +// end catch_section_info.cpp +// start catch_session.cpp + +// start catch_session.h + +#include <memory> + +namespace Catch { + + class Session : NonCopyable { + public: + + Session(); + ~Session() override; + + void showHelp() const; + void libIdentify(); + + int applyCommandLine( int argc, char const * const * argv ); + + void useConfigData( ConfigData const& configData ); + + int run( int argc, char* argv[] ); + #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) + int run( int argc, wchar_t* const argv[] ); + #endif + int run(); + + clara::Parser const& cli() const; + void cli( clara::Parser const& newParser ); + ConfigData& configData(); + Config& config(); + private: + int runInternal(); + + clara::Parser m_cli; + ConfigData m_configData; + std::shared_ptr<Config> m_config; + bool m_startupExceptions = false; + }; + +} // end namespace Catch + +// end catch_session.h +// start catch_version.h + +#include <iosfwd> + +namespace Catch { + + // Versioning information + struct Version { + Version( Version const& ) = delete; + Version& operator=( Version const& ) = delete; + Version( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + char const * const _branchName, + unsigned int _buildNumber ); + + unsigned int const majorVersion; + unsigned int const minorVersion; + unsigned int const patchNumber; + + // buildNumber is only used if branchName is not null + char const * const branchName; + unsigned int const buildNumber; + + friend std::ostream& operator << ( std::ostream& os, Version const& version ); + }; + + Version const& libraryVersion(); +} + +// end catch_version.h +#include <cstdlib> +#include <iomanip> + +namespace Catch { + + namespace { + const int MaxExitCode = 255; + + IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) { + auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config); + CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'"); + + return reporter; + } + + IStreamingReporterPtr makeReporter(std::shared_ptr<Config> const& config) { + if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) { + return createReporter(config->getReporterName(), config); + } + + auto multi = std::unique_ptr<ListeningReporter>(new ListeningReporter); + + auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); + for (auto const& listener : listeners) { + multi->addListener(listener->create(Catch::ReporterConfig(config))); + } + multi->addReporter(createReporter(config->getReporterName(), config)); + return std::move(multi); + } + + Catch::Totals runTests(std::shared_ptr<Config> const& config) { + // FixMe: Add listeners in order first, then add reporters. + + auto reporter = makeReporter(config); + + RunContext context(config, std::move(reporter)); + + Totals totals; + + context.testGroupStarting(config->name(), 1, 1); + + TestSpec testSpec = config->testSpec(); + + auto const& allTestCases = getAllTestCasesSorted(*config); + for (auto const& testCase : allTestCases) { + if (!context.aborting() && matchTest(testCase, testSpec, *config)) + totals += context.runTest(testCase); + else + context.reporter().skipTest(testCase); + } + + if (config->warnAboutNoTests() && totals.testCases.total() == 0) { + ReusableStringStream testConfig; + + bool first = true; + for (const auto& input : config->getTestsOrTags()) { + if (!first) { testConfig << ' '; } + first = false; + testConfig << input; + } + + context.reporter().noMatchingTestCases(testConfig.str()); + totals.error = -1; + } + + context.testGroupEnded(config->name(), totals, 1, 1); + return totals; + } + + void applyFilenamesAsTags(Catch::IConfig const& config) { + auto& tests = const_cast<std::vector<TestCase>&>(getAllTestCasesSorted(config)); + for (auto& testCase : tests) { + auto tags = testCase.tags; + + std::string filename = testCase.lineInfo.file; + auto lastSlash = filename.find_last_of("\\/"); + if (lastSlash != std::string::npos) { + filename.erase(0, lastSlash); + filename[0] = '#'; + } + + auto lastDot = filename.find_last_of('.'); + if (lastDot != std::string::npos) { + filename.erase(lastDot); + } + + tags.push_back(std::move(filename)); + setTags(testCase, tags); + } + } + + } // anon namespace + + Session::Session() { + static bool alreadyInstantiated = false; + if( alreadyInstantiated ) { + try { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); } + catch(...) { getMutableRegistryHub().registerStartupException(); } + } + + const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions(); + if ( !exceptions.empty() ) { + m_startupExceptions = true; + Colour colourGuard( Colour::Red ); + Catch::cerr() << "Errors occurred during startup!" << '\n'; + // iterate over all exceptions and notify user + for ( const auto& ex_ptr : exceptions ) { + try { + std::rethrow_exception(ex_ptr); + } catch ( std::exception const& ex ) { + Catch::cerr() << Column( ex.what() ).indent(2) << '\n'; + } + } + } + + alreadyInstantiated = true; + m_cli = makeCommandLineParser( m_configData ); + } + Session::~Session() { + Catch::cleanUp(); + } + + void Session::showHelp() const { + Catch::cout() + << "\nCatch v" << libraryVersion() << "\n" + << m_cli << std::endl + << "For more detailed usage please see the project docs\n" << std::endl; + } + void Session::libIdentify() { + Catch::cout() + << std::left << std::setw(16) << "description: " << "A Catch test executable\n" + << std::left << std::setw(16) << "category: " << "testframework\n" + << std::left << std::setw(16) << "framework: " << "Catch Test\n" + << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; + } + + int Session::applyCommandLine( int argc, char const * const * argv ) { + if( m_startupExceptions ) + return 1; + + auto result = m_cli.parse( clara::Args( argc, argv ) ); + if( !result ) { + Catch::cerr() + << Colour( Colour::Red ) + << "\nError(s) in input:\n" + << Column( result.errorMessage() ).indent( 2 ) + << "\n\n"; + Catch::cerr() << "Run with -? for usage\n" << std::endl; + return MaxExitCode; + } + + if( m_configData.showHelp ) + showHelp(); + if( m_configData.libIdentify ) + libIdentify(); + m_config.reset(); + return 0; + } + + void Session::useConfigData( ConfigData const& configData ) { + m_configData = configData; + m_config.reset(); + } + + int Session::run( int argc, char* argv[] ) { + if( m_startupExceptions ) + return 1; + int returnCode = applyCommandLine( argc, argv ); + if( returnCode == 0 ) + returnCode = run(); + return returnCode; + } + +#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) + int Session::run( int argc, wchar_t* const argv[] ) { + + char **utf8Argv = new char *[ argc ]; + + for ( int i = 0; i < argc; ++i ) { + int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); + + utf8Argv[ i ] = new char[ bufSize ]; + + WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); + } + + int returnCode = run( argc, utf8Argv ); + + for ( int i = 0; i < argc; ++i ) + delete [] utf8Argv[ i ]; + + delete [] utf8Argv; + + return returnCode; + } +#endif + int Session::run() { + if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) { + Catch::cout() << "...waiting for enter/ return before starting" << std::endl; + static_cast<void>(std::getchar()); + } + int exitCode = runInternal(); + if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) { + Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl; + static_cast<void>(std::getchar()); + } + return exitCode; + } + + clara::Parser const& Session::cli() const { + return m_cli; + } + void Session::cli( clara::Parser const& newParser ) { + m_cli = newParser; + } + ConfigData& Session::configData() { + return m_configData; + } + Config& Session::config() { + if( !m_config ) + m_config = std::make_shared<Config>( m_configData ); + return *m_config; + } + + int Session::runInternal() { + if( m_startupExceptions ) + return 1; + + if( m_configData.showHelp || m_configData.libIdentify ) + return 0; + + try + { + config(); // Force config to be constructed + + seedRng( *m_config ); + + if( m_configData.filenamesAsTags ) + applyFilenamesAsTags( *m_config ); + + // Handle list request + if( Option<std::size_t> listed = list( config() ) ) + return static_cast<int>( *listed ); + + auto totals = runTests( m_config ); + // Note that on unices only the lower 8 bits are usually used, clamping + // the return value to 255 prevents false negative when some multiple + // of 256 tests has failed + return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast<int>(totals.assertions.failed))); + } + catch( std::exception& ex ) { + Catch::cerr() << ex.what() << std::endl; + return MaxExitCode; + } + } + +} // end namespace Catch +// end catch_session.cpp +// start catch_startup_exception_registry.cpp + +namespace Catch { + void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { + try { + m_exceptions.push_back(exception); + } + catch(...) { + // If we run out of memory during start-up there's really not a lot more we can do about it + std::terminate(); + } + } + + std::vector<std::exception_ptr> const& StartupExceptionRegistry::getExceptions() const noexcept { + return m_exceptions; + } + +} // end namespace Catch +// end catch_startup_exception_registry.cpp +// start catch_stream.cpp + +#include <cstdio> +#include <iostream> +#include <fstream> +#include <sstream> +#include <vector> +#include <memory> + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +#endif + +namespace Catch { + + Catch::IStream::~IStream() = default; + + namespace detail { namespace { + template<typename WriterF, std::size_t bufferSize=256> + class StreamBufImpl : public std::streambuf { + char data[bufferSize]; + WriterF m_writer; + + public: + StreamBufImpl() { + setp( data, data + sizeof(data) ); + } + + ~StreamBufImpl() noexcept { + StreamBufImpl::sync(); + } + + private: + int overflow( int c ) override { + sync(); + + if( c != EOF ) { + if( pbase() == epptr() ) + m_writer( std::string( 1, static_cast<char>( c ) ) ); + else + sputc( static_cast<char>( c ) ); + } + return 0; + } + + int sync() override { + if( pbase() != pptr() ) { + m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) ); + setp( pbase(), epptr() ); + } + return 0; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + struct OutputDebugWriter { + + void operator()( std::string const&str ) { + writeToDebugConsole( str ); + } + }; + + /////////////////////////////////////////////////////////////////////////// + + class FileStream : public IStream { + mutable std::ofstream m_ofs; + public: + FileStream( StringRef filename ) { + m_ofs.open( filename.c_str() ); + CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" ); + } + ~FileStream() override = default; + public: // IStream + std::ostream& stream() const override { + return m_ofs; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + class CoutStream : public IStream { + mutable std::ostream m_os; + public: + // Store the streambuf from cout up-front because + // cout may get redirected when running tests + CoutStream() : m_os( Catch::cout().rdbuf() ) {} + ~CoutStream() override = default; + + public: // IStream + std::ostream& stream() const override { return m_os; } + }; + + /////////////////////////////////////////////////////////////////////////// + + class DebugOutStream : public IStream { + std::unique_ptr<StreamBufImpl<OutputDebugWriter>> m_streamBuf; + mutable std::ostream m_os; + public: + DebugOutStream() + : m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ), + m_os( m_streamBuf.get() ) + {} + + ~DebugOutStream() override = default; + + public: // IStream + std::ostream& stream() const override { return m_os; } + }; + + }} // namespace anon::detail + + /////////////////////////////////////////////////////////////////////////// + + auto makeStream( StringRef const &filename ) -> IStream const* { + if( filename.empty() ) + return new detail::CoutStream(); + else if( filename[0] == '%' ) { + if( filename == "%debug" ) + return new detail::DebugOutStream(); + else + CATCH_ERROR( "Unrecognised stream: '" << filename << "'" ); + } + else + return new detail::FileStream( filename ); + } + + // This class encapsulates the idea of a pool of ostringstreams that can be reused. + struct StringStreams { + std::vector<std::unique_ptr<std::ostringstream>> m_streams; + std::vector<std::size_t> m_unused; + std::ostringstream m_referenceStream; // Used for copy state/ flags from + static StringStreams* s_instance; + + auto add() -> std::size_t { + if( m_unused.empty() ) { + m_streams.push_back( std::unique_ptr<std::ostringstream>( new std::ostringstream ) ); + return m_streams.size()-1; + } + else { + auto index = m_unused.back(); + m_unused.pop_back(); + return index; + } + } + + void release( std::size_t index ) { + m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state + m_unused.push_back(index); + } + + // !TBD: put in TLS + static auto instance() -> StringStreams& { + if( !s_instance ) + s_instance = new StringStreams(); + return *s_instance; + } + static void cleanup() { + delete s_instance; + s_instance = nullptr; + } + }; + + StringStreams* StringStreams::s_instance = nullptr; + + void ReusableStringStream::cleanup() { + StringStreams::cleanup(); + } + + ReusableStringStream::ReusableStringStream() + : m_index( StringStreams::instance().add() ), + m_oss( StringStreams::instance().m_streams[m_index].get() ) + {} + + ReusableStringStream::~ReusableStringStream() { + static_cast<std::ostringstream*>( m_oss )->str(""); + m_oss->clear(); + StringStreams::instance().release( m_index ); + } + + auto ReusableStringStream::str() const -> std::string { + return static_cast<std::ostringstream*>( m_oss )->str(); + } + + /////////////////////////////////////////////////////////////////////////// + +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions + std::ostream& cout() { return std::cout; } + std::ostream& cerr() { return std::cerr; } + std::ostream& clog() { return std::clog; } +#endif +} + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif +// end catch_stream.cpp +// start catch_string_manip.cpp + +#include <algorithm> +#include <ostream> +#include <cstring> +#include <cctype> + +namespace Catch { + + namespace { + char toLowerCh(char c) { + return static_cast<char>( std::tolower( c ) ); + } + } + + bool startsWith( std::string const& s, std::string const& prefix ) { + return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); + } + bool startsWith( std::string const& s, char prefix ) { + return !s.empty() && s[0] == prefix; + } + bool endsWith( std::string const& s, std::string const& suffix ) { + return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); + } + bool endsWith( std::string const& s, char suffix ) { + return !s.empty() && s[s.size()-1] == suffix; + } + bool contains( std::string const& s, std::string const& infix ) { + return s.find( infix ) != std::string::npos; + } + void toLowerInPlace( std::string& s ) { + std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); + } + std::string toLower( std::string const& s ) { + std::string lc = s; + toLowerInPlace( lc ); + return lc; + } + std::string trim( std::string const& str ) { + static char const* whitespaceChars = "\n\r\t "; + std::string::size_type start = str.find_first_not_of( whitespaceChars ); + std::string::size_type end = str.find_last_not_of( whitespaceChars ); + + return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); + } + + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { + bool replaced = false; + std::size_t i = str.find( replaceThis ); + while( i != std::string::npos ) { + replaced = true; + str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); + if( i < str.size()-withThis.size() ) + i = str.find( replaceThis, i+withThis.size() ); + else + i = std::string::npos; + } + return replaced; + } + + pluralise::pluralise( std::size_t count, std::string const& label ) + : m_count( count ), + m_label( label ) + {} + + std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { + os << pluraliser.m_count << ' ' << pluraliser.m_label; + if( pluraliser.m_count != 1 ) + os << 's'; + return os; + } + +} +// end catch_string_manip.cpp +// start catch_stringref.cpp + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +#endif + +#include <ostream> +#include <cstring> +#include <cstdint> + +namespace { + const uint32_t byte_2_lead = 0xC0; + const uint32_t byte_3_lead = 0xE0; + const uint32_t byte_4_lead = 0xF0; +} + +namespace Catch { + StringRef::StringRef( char const* rawChars ) noexcept + : StringRef( rawChars, static_cast<StringRef::size_type>(std::strlen(rawChars) ) ) + {} + + StringRef::operator std::string() const { + return std::string( m_start, m_size ); + } + + void StringRef::swap( StringRef& other ) noexcept { + std::swap( m_start, other.m_start ); + std::swap( m_size, other.m_size ); + std::swap( m_data, other.m_data ); + } + + auto StringRef::c_str() const -> char const* { + if( isSubstring() ) + const_cast<StringRef*>( this )->takeOwnership(); + return m_start; + } + auto StringRef::currentData() const noexcept -> char const* { + return m_start; + } + + auto StringRef::isOwned() const noexcept -> bool { + return m_data != nullptr; + } + auto StringRef::isSubstring() const noexcept -> bool { + return m_start[m_size] != '\0'; + } + + void StringRef::takeOwnership() { + if( !isOwned() ) { + m_data = new char[m_size+1]; + memcpy( m_data, m_start, m_size ); + m_data[m_size] = '\0'; + m_start = m_data; + } + } + auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef { + if( start < m_size ) + return StringRef( m_start+start, size ); + else + return StringRef(); + } + auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool { + return + size() == other.size() && + (std::strncmp( m_start, other.m_start, size() ) == 0); + } + auto StringRef::operator != ( StringRef const& other ) const noexcept -> bool { + return !operator==( other ); + } + + auto StringRef::operator[](size_type index) const noexcept -> char { + return m_start[index]; + } + + auto StringRef::numberOfCharacters() const noexcept -> size_type { + size_type noChars = m_size; + // Make adjustments for uft encodings + for( size_type i=0; i < m_size; ++i ) { + char c = m_start[i]; + if( ( c & byte_2_lead ) == byte_2_lead ) { + noChars--; + if (( c & byte_3_lead ) == byte_3_lead ) + noChars--; + if( ( c & byte_4_lead ) == byte_4_lead ) + noChars--; + } + } + return noChars; + } + + auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string { + std::string str; + str.reserve( lhs.size() + rhs.size() ); + str += lhs; + str += rhs; + return str; + } + auto operator + ( StringRef const& lhs, const char* rhs ) -> std::string { + return std::string( lhs ) + std::string( rhs ); + } + auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string { + return std::string( lhs ) + std::string( rhs ); + } + + auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& { + return os.write(str.currentData(), str.size()); + } + + auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& { + lhs.append(rhs.currentData(), rhs.size()); + return lhs; + } + +} // namespace Catch + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif +// end catch_stringref.cpp +// start catch_tag_alias.cpp + +namespace Catch { + TagAlias::TagAlias(std::string const & _tag, SourceLineInfo _lineInfo): tag(_tag), lineInfo(_lineInfo) {} +} +// end catch_tag_alias.cpp +// start catch_tag_alias_autoregistrar.cpp + +namespace Catch { + + RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) { + try { + getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo); + } catch (...) { + // Do not throw when constructing global objects, instead register the exception to be processed later + getMutableRegistryHub().registerStartupException(); + } + } + +} +// end catch_tag_alias_autoregistrar.cpp +// start catch_tag_alias_registry.cpp + +#include <sstream> + +namespace Catch { + + TagAliasRegistry::~TagAliasRegistry() {} + + TagAlias const* TagAliasRegistry::find( std::string const& alias ) const { + auto it = m_registry.find( alias ); + if( it != m_registry.end() ) + return &(it->second); + else + return nullptr; + } + + std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { + std::string expandedTestSpec = unexpandedTestSpec; + for( auto const& registryKvp : m_registry ) { + std::size_t pos = expandedTestSpec.find( registryKvp.first ); + if( pos != std::string::npos ) { + expandedTestSpec = expandedTestSpec.substr( 0, pos ) + + registryKvp.second.tag + + expandedTestSpec.substr( pos + registryKvp.first.size() ); + } + } + return expandedTestSpec; + } + + void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { + CATCH_ENFORCE( startsWith(alias, "[@") && endsWith(alias, ']'), + "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo ); + + CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second, + "error: tag alias, '" << alias << "' already registered.\n" + << "\tFirst seen at: " << find(alias)->lineInfo << "\n" + << "\tRedefined at: " << lineInfo ); + } + + ITagAliasRegistry::~ITagAliasRegistry() {} + + ITagAliasRegistry const& ITagAliasRegistry::get() { + return getRegistryHub().getTagAliasRegistry(); + } + +} // end namespace Catch +// end catch_tag_alias_registry.cpp +// start catch_test_case_info.cpp + +#include <cctype> +#include <exception> +#include <algorithm> +#include <sstream> + +namespace Catch { + + namespace { + TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { + if( startsWith( tag, '.' ) || + tag == "!hide" ) + return TestCaseInfo::IsHidden; + else if( tag == "!throws" ) + return TestCaseInfo::Throws; + else if( tag == "!shouldfail" ) + return TestCaseInfo::ShouldFail; + else if( tag == "!mayfail" ) + return TestCaseInfo::MayFail; + else if( tag == "!nonportable" ) + return TestCaseInfo::NonPortable; + else if( tag == "!benchmark" ) + return static_cast<TestCaseInfo::SpecialProperties>( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden ); + else + return TestCaseInfo::None; + } + bool isReservedTag( std::string const& tag ) { + return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast<unsigned char>(tag[0]) ); + } + void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { + CATCH_ENFORCE( !isReservedTag(tag), + "Tag name: [" << tag << "] is not allowed.\n" + << "Tag names starting with non alpha-numeric characters are reserved\n" + << _lineInfo ); + } + } + + TestCase makeTestCase( ITestInvoker* _testCase, + std::string const& _className, + NameAndTags const& nameAndTags, + SourceLineInfo const& _lineInfo ) + { + bool isHidden = false; + + // Parse out tags + std::vector<std::string> tags; + std::string desc, tag; + bool inTag = false; + std::string _descOrTags = nameAndTags.tags; + for (char c : _descOrTags) { + if( !inTag ) { + if( c == '[' ) + inTag = true; + else + desc += c; + } + else { + if( c == ']' ) { + TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); + if( ( prop & TestCaseInfo::IsHidden ) != 0 ) + isHidden = true; + else if( prop == TestCaseInfo::None ) + enforceNotReservedTag( tag, _lineInfo ); + + tags.push_back( tag ); + tag.clear(); + inTag = false; + } + else + tag += c; + } + } + if( isHidden ) { + tags.push_back( "." ); + } + + TestCaseInfo info( nameAndTags.name, _className, desc, tags, _lineInfo ); + return TestCase( _testCase, std::move(info) ); + } + + void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags ) { + std::sort(begin(tags), end(tags)); + tags.erase(std::unique(begin(tags), end(tags)), end(tags)); + testCaseInfo.lcaseTags.clear(); + + for( auto const& tag : tags ) { + std::string lcaseTag = toLower( tag ); + testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); + testCaseInfo.lcaseTags.push_back( lcaseTag ); + } + testCaseInfo.tags = std::move(tags); + } + + TestCaseInfo::TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::vector<std::string> const& _tags, + SourceLineInfo const& _lineInfo ) + : name( _name ), + className( _className ), + description( _description ), + lineInfo( _lineInfo ), + properties( None ) + { + setTags( *this, _tags ); + } + + bool TestCaseInfo::isHidden() const { + return ( properties & IsHidden ) != 0; + } + bool TestCaseInfo::throws() const { + return ( properties & Throws ) != 0; + } + bool TestCaseInfo::okToFail() const { + return ( properties & (ShouldFail | MayFail ) ) != 0; + } + bool TestCaseInfo::expectedToFail() const { + return ( properties & (ShouldFail ) ) != 0; + } + + std::string TestCaseInfo::tagsAsString() const { + std::string ret; + // '[' and ']' per tag + std::size_t full_size = 2 * tags.size(); + for (const auto& tag : tags) { + full_size += tag.size(); + } + ret.reserve(full_size); + for (const auto& tag : tags) { + ret.push_back('['); + ret.append(tag); + ret.push_back(']'); + } + + return ret; + } + + TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {} + + TestCase TestCase::withName( std::string const& _newName ) const { + TestCase other( *this ); + other.name = _newName; + return other; + } + + void TestCase::invoke() const { + test->invoke(); + } + + bool TestCase::operator == ( TestCase const& other ) const { + return test.get() == other.test.get() && + name == other.name && + className == other.className; + } + + bool TestCase::operator < ( TestCase const& other ) const { + return name < other.name; + } + + TestCaseInfo const& TestCase::getTestCaseInfo() const + { + return *this; + } + +} // end namespace Catch +// end catch_test_case_info.cpp +// start catch_test_case_registry_impl.cpp + +#include <sstream> + +namespace Catch { + + std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) { + + std::vector<TestCase> sorted = unsortedTestCases; + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( sorted.begin(), sorted.end() ); + break; + case RunTests::InRandomOrder: + seedRng( config ); + std::shuffle( sorted.begin(), sorted.end(), rng() ); + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + return sorted; + } + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { + return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); + } + + void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) { + std::set<TestCase> seenFunctions; + for( auto const& function : functions ) { + auto prev = seenFunctions.insert( function ); + CATCH_ENFORCE( prev.second, + "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << function.getTestCaseInfo().lineInfo ); + } + } + + std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) { + std::vector<TestCase> filtered; + filtered.reserve( testCases.size() ); + for( auto const& testCase : testCases ) + if( matchTest( testCase, testSpec, config ) ) + filtered.push_back( testCase ); + return filtered; + } + std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) { + return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); + } + + void TestRegistry::registerTest( TestCase const& testCase ) { + std::string name = testCase.getTestCaseInfo().name; + if( name.empty() ) { + ReusableStringStream rss; + rss << "Anonymous test case " << ++m_unnamedCount; + return registerTest( testCase.withName( rss.str() ) ); + } + m_functions.push_back( testCase ); + } + + std::vector<TestCase> const& TestRegistry::getAllTests() const { + return m_functions; + } + std::vector<TestCase> const& TestRegistry::getAllTestsSorted( IConfig const& config ) const { + if( m_sortedFunctions.empty() ) + enforceNoDuplicateTestCases( m_functions ); + + if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { + m_sortedFunctions = sortTests( config, m_functions ); + m_currentSortOrder = config.runOrder(); + } + return m_sortedFunctions; + } + + /////////////////////////////////////////////////////////////////////////// + TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {} + + void TestInvokerAsFunction::invoke() const { + m_testAsFunction(); + } + + std::string extractClassName( StringRef const& classOrQualifiedMethodName ) { + std::string className = classOrQualifiedMethodName; + if( startsWith( className, '&' ) ) + { + std::size_t lastColons = className.rfind( "::" ); + std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); + if( penultimateColons == std::string::npos ) + penultimateColons = 1; + className = className.substr( penultimateColons, lastColons-penultimateColons ); + } + return className; + } + +} // end namespace Catch +// end catch_test_case_registry_impl.cpp +// start catch_test_case_tracker.cpp + +#include <algorithm> +#include <cassert> +#include <stdexcept> +#include <memory> +#include <sstream> + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +#endif + +namespace Catch { +namespace TestCaseTracking { + + NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) + : name( _name ), + location( _location ) + {} + + ITracker::~ITracker() = default; + + TrackerContext& TrackerContext::instance() { + static TrackerContext s_instance; + return s_instance; + } + + ITracker& TrackerContext::startRun() { + m_rootTracker = std::make_shared<SectionTracker>( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, nullptr ); + m_currentTracker = nullptr; + m_runState = Executing; + return *m_rootTracker; + } + + void TrackerContext::endRun() { + m_rootTracker.reset(); + m_currentTracker = nullptr; + m_runState = NotStarted; + } + + void TrackerContext::startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; + } + void TrackerContext::completeCycle() { + m_runState = CompletedCycle; + } + + bool TrackerContext::completedCycle() const { + return m_runState == CompletedCycle; + } + ITracker& TrackerContext::currentTracker() { + return *m_currentTracker; + } + void TrackerContext::setCurrentTracker( ITracker* tracker ) { + m_currentTracker = tracker; + } + + TrackerBase::TrackerHasName::TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {} + bool TrackerBase::TrackerHasName::operator ()( ITrackerPtr const& tracker ) const { + return + tracker->nameAndLocation().location == m_nameAndLocation.location && + tracker->nameAndLocation().name == m_nameAndLocation.name; + } + + TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) + : m_nameAndLocation( nameAndLocation ), + m_ctx( ctx ), + m_parent( parent ) + {} + + NameAndLocation const& TrackerBase::nameAndLocation() const { + return m_nameAndLocation; + } + bool TrackerBase::isComplete() const { + return m_runState == CompletedSuccessfully || m_runState == Failed; + } + bool TrackerBase::isSuccessfullyCompleted() const { + return m_runState == CompletedSuccessfully; + } + bool TrackerBase::isOpen() const { + return m_runState != NotStarted && !isComplete(); + } + bool TrackerBase::hasChildren() const { + return !m_children.empty(); + } + + void TrackerBase::addChild( ITrackerPtr const& child ) { + m_children.push_back( child ); + } + + ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) { + auto it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) ); + return( it != m_children.end() ) + ? *it + : nullptr; + } + ITracker& TrackerBase::parent() { + assert( m_parent ); // Should always be non-null except for root + return *m_parent; + } + + void TrackerBase::openChild() { + if( m_runState != ExecutingChildren ) { + m_runState = ExecutingChildren; + if( m_parent ) + m_parent->openChild(); + } + } + + bool TrackerBase::isSectionTracker() const { return false; } + bool TrackerBase::isIndexTracker() const { return false; } + + void TrackerBase::open() { + m_runState = Executing; + moveToThis(); + if( m_parent ) + m_parent->openChild(); + } + + void TrackerBase::close() { + + // Close any still open children (e.g. generators) + while( &m_ctx.currentTracker() != this ) + m_ctx.currentTracker().close(); + + switch( m_runState ) { + case NeedsAnotherRun: + break; + + case Executing: + m_runState = CompletedSuccessfully; + break; + case ExecutingChildren: + if( m_children.empty() || m_children.back()->isComplete() ) + m_runState = CompletedSuccessfully; + break; + + case NotStarted: + case CompletedSuccessfully: + case Failed: + CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState ); + + default: + CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState ); + } + moveToParent(); + m_ctx.completeCycle(); + } + void TrackerBase::fail() { + m_runState = Failed; + if( m_parent ) + m_parent->markAsNeedingAnotherRun(); + moveToParent(); + m_ctx.completeCycle(); + } + void TrackerBase::markAsNeedingAnotherRun() { + m_runState = NeedsAnotherRun; + } + + void TrackerBase::moveToParent() { + assert( m_parent ); + m_ctx.setCurrentTracker( m_parent ); + } + void TrackerBase::moveToThis() { + m_ctx.setCurrentTracker( this ); + } + + SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( nameAndLocation, ctx, parent ) + { + if( parent ) { + while( !parent->isSectionTracker() ) + parent = &parent->parent(); + + SectionTracker& parentSection = static_cast<SectionTracker&>( *parent ); + addNextFilters( parentSection.m_filters ); + } + } + + bool SectionTracker::isSectionTracker() const { return true; } + + SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { + std::shared_ptr<SectionTracker> section; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { + assert( childTracker ); + assert( childTracker->isSectionTracker() ); + section = std::static_pointer_cast<SectionTracker>( childTracker ); + } + else { + section = std::make_shared<SectionTracker>( nameAndLocation, ctx, ¤tTracker ); + currentTracker.addChild( section ); + } + if( !ctx.completedCycle() ) + section->tryOpen(); + return *section; + } + + void SectionTracker::tryOpen() { + if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) ) + open(); + } + + void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) { + if( !filters.empty() ) { + m_filters.push_back(""); // Root - should never be consulted + m_filters.push_back(""); // Test Case - not a section filter + m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); + } + } + void SectionTracker::addNextFilters( std::vector<std::string> const& filters ) { + if( filters.size() > 1 ) + m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() ); + } + + IndexTracker::IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ) + : TrackerBase( nameAndLocation, ctx, parent ), + m_size( size ) + {} + + bool IndexTracker::isIndexTracker() const { return true; } + + IndexTracker& IndexTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) { + std::shared_ptr<IndexTracker> tracker; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { + assert( childTracker ); + assert( childTracker->isIndexTracker() ); + tracker = std::static_pointer_cast<IndexTracker>( childTracker ); + } + else { + tracker = std::make_shared<IndexTracker>( nameAndLocation, ctx, ¤tTracker, size ); + currentTracker.addChild( tracker ); + } + + if( !ctx.completedCycle() && !tracker->isComplete() ) { + if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) + tracker->moveNext(); + tracker->open(); + } + + return *tracker; + } + + int IndexTracker::index() const { return m_index; } + + void IndexTracker::moveNext() { + m_index++; + m_children.clear(); + } + + void IndexTracker::close() { + TrackerBase::close(); + if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) + m_runState = Executing; + } + +} // namespace TestCaseTracking + +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; +using TestCaseTracking::IndexTracker; + +} // namespace Catch + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif +// end catch_test_case_tracker.cpp +// start catch_test_registry.cpp + +namespace Catch { + + auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker* { + return new(std::nothrow) TestInvokerAsFunction( testAsFunction ); + } + + NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {} + + AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept { + try { + getMutableRegistryHub() + .registerTest( + makeTestCase( + invoker, + extractClassName( classOrMethod ), + nameAndTags, + lineInfo)); + } catch (...) { + // Do not throw when constructing global objects, instead register the exception to be processed later + getMutableRegistryHub().registerStartupException(); + } + } + + AutoReg::~AutoReg() = default; +} +// end catch_test_registry.cpp +// start catch_test_spec.cpp + +#include <algorithm> +#include <string> +#include <vector> +#include <memory> + +namespace Catch { + + TestSpec::Pattern::~Pattern() = default; + TestSpec::NamePattern::~NamePattern() = default; + TestSpec::TagPattern::~TagPattern() = default; + TestSpec::ExcludedPattern::~ExcludedPattern() = default; + + TestSpec::NamePattern::NamePattern( std::string const& name ) + : m_wildcardPattern( toLower( name ), CaseSensitive::No ) + {} + bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const { + return m_wildcardPattern.matches( toLower( testCase.name ) ); + } + + TestSpec::TagPattern::TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} + bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const { + return std::find(begin(testCase.lcaseTags), + end(testCase.lcaseTags), + m_tag) != end(testCase.lcaseTags); + } + + TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} + bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } + + bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const { + // All patterns in a filter must match for the filter to be a match + for( auto const& pattern : m_patterns ) { + if( !pattern->matches( testCase ) ) + return false; + } + return true; + } + + bool TestSpec::hasFilters() const { + return !m_filters.empty(); + } + bool TestSpec::matches( TestCaseInfo const& testCase ) const { + // A TestSpec matches if any filter matches + for( auto const& filter : m_filters ) + if( filter.matches( testCase ) ) + return true; + return false; + } +} +// end catch_test_spec.cpp +// start catch_test_spec_parser.cpp + +namespace Catch { + + TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} + + TestSpecParser& TestSpecParser::parse( std::string const& arg ) { + m_mode = None; + m_exclusion = false; + m_start = std::string::npos; + m_arg = m_tagAliases->expandAliases( arg ); + m_escapeChars.clear(); + for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) + visitChar( m_arg[m_pos] ); + if( m_mode == Name ) + addPattern<TestSpec::NamePattern>(); + return *this; + } + TestSpec TestSpecParser::testSpec() { + addFilter(); + return m_testSpec; + } + + void TestSpecParser::visitChar( char c ) { + if( m_mode == None ) { + switch( c ) { + case ' ': return; + case '~': m_exclusion = true; return; + case '[': return startNewMode( Tag, ++m_pos ); + case '"': return startNewMode( QuotedName, ++m_pos ); + case '\\': return escape(); + default: startNewMode( Name, m_pos ); break; + } + } + if( m_mode == Name ) { + if( c == ',' ) { + addPattern<TestSpec::NamePattern>(); + addFilter(); + } + else if( c == '[' ) { + if( subString() == "exclude:" ) + m_exclusion = true; + else + addPattern<TestSpec::NamePattern>(); + startNewMode( Tag, ++m_pos ); + } + else if( c == '\\' ) + escape(); + } + else if( m_mode == EscapedName ) + m_mode = Name; + else if( m_mode == QuotedName && c == '"' ) + addPattern<TestSpec::NamePattern>(); + else if( m_mode == Tag && c == ']' ) + addPattern<TestSpec::TagPattern>(); + } + void TestSpecParser::startNewMode( Mode mode, std::size_t start ) { + m_mode = mode; + m_start = start; + } + void TestSpecParser::escape() { + if( m_mode == None ) + m_start = m_pos; + m_mode = EscapedName; + m_escapeChars.push_back( m_pos ); + } + std::string TestSpecParser::subString() const { return m_arg.substr( m_start, m_pos - m_start ); } + + void TestSpecParser::addFilter() { + if( !m_currentFilter.m_patterns.empty() ) { + m_testSpec.m_filters.push_back( m_currentFilter ); + m_currentFilter = TestSpec::Filter(); + } + } + + TestSpec parseTestSpec( std::string const& arg ) { + return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); + } + +} // namespace Catch +// end catch_test_spec_parser.cpp +// start catch_timer.cpp + +#include <chrono> + +static const uint64_t nanosecondsInSecond = 1000000000; + +namespace Catch { + + auto getCurrentNanosecondsSinceEpoch() -> uint64_t { + return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); + } + + namespace { + auto estimateClockResolution() -> uint64_t { + uint64_t sum = 0; + static const uint64_t iterations = 1000000; + + auto startTime = getCurrentNanosecondsSinceEpoch(); + + for( std::size_t i = 0; i < iterations; ++i ) { + + uint64_t ticks; + uint64_t baseTicks = getCurrentNanosecondsSinceEpoch(); + do { + ticks = getCurrentNanosecondsSinceEpoch(); + } while( ticks == baseTicks ); + + auto delta = ticks - baseTicks; + sum += delta; + + // If we have been calibrating for over 3 seconds -- the clock + // is terrible and we should move on. + // TBD: How to signal that the measured resolution is probably wrong? + if (ticks > startTime + 3 * nanosecondsInSecond) { + return sum / i; + } + } + + // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers + // - and potentially do more iterations if there's a high variance. + return sum/iterations; + } + } + auto getEstimatedClockResolution() -> uint64_t { + static auto s_resolution = estimateClockResolution(); + return s_resolution; + } + + void Timer::start() { + m_nanoseconds = getCurrentNanosecondsSinceEpoch(); + } + auto Timer::getElapsedNanoseconds() const -> uint64_t { + return getCurrentNanosecondsSinceEpoch() - m_nanoseconds; + } + auto Timer::getElapsedMicroseconds() const -> uint64_t { + return getElapsedNanoseconds()/1000; + } + auto Timer::getElapsedMilliseconds() const -> unsigned int { + return static_cast<unsigned int>(getElapsedMicroseconds()/1000); + } + auto Timer::getElapsedSeconds() const -> double { + return getElapsedMicroseconds()/1000000.0; + } + +} // namespace Catch +// end catch_timer.cpp +// start catch_tostring.cpp + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +# pragma clang diagnostic ignored "-Wglobal-constructors" +#endif + +// Enable specific decls locally +#if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +#define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +#endif + +#include <cmath> +#include <iomanip> + +namespace Catch { + +namespace Detail { + + const std::string unprintableString = "{?}"; + + namespace { + const int hexThreshold = 255; + + struct Endianness { + enum Arch { Big, Little }; + + static Arch which() { + union _{ + int asInt; + char asChar[sizeof (int)]; + } u; + + u.asInt = 1; + return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; + } + }; + } + + std::string rawMemoryToString( const void *object, std::size_t size ) { + // Reverse order for little endian architectures + int i = 0, end = static_cast<int>( size ), inc = 1; + if( Endianness::which() == Endianness::Little ) { + i = end-1; + end = inc = -1; + } + + unsigned char const *bytes = static_cast<unsigned char const *>(object); + ReusableStringStream rss; + rss << "0x" << std::setfill('0') << std::hex; + for( ; i != end; i += inc ) + rss << std::setw(2) << static_cast<unsigned>(bytes[i]); + return rss.str(); + } +} + +template<typename T> +std::string fpToString( T value, int precision ) { + if (std::isnan(value)) { + return "nan"; + } + + ReusableStringStream rss; + rss << std::setprecision( precision ) + << std::fixed + << value; + std::string d = rss.str(); + std::size_t i = d.find_last_not_of( '0' ); + if( i != std::string::npos && i != d.size()-1 ) { + if( d[i] == '.' ) + i++; + d = d.substr( 0, i+1 ); + } + return d; +} + +//// ======================================================= //// +// +// Out-of-line defs for full specialization of StringMaker +// +//// ======================================================= //// + +std::string StringMaker<std::string>::convert(const std::string& str) { + if (!getCurrentContext().getConfig()->showInvisibles()) { + return '"' + str + '"'; + } + + std::string s("\""); + for (char c : str) { + switch (c) { + case '\n': + s.append("\\n"); + break; + case '\t': + s.append("\\t"); + break; + default: + s.push_back(c); + break; + } + } + s.append("\""); + return s; +} + +#ifdef CATCH_CONFIG_WCHAR +std::string StringMaker<std::wstring>::convert(const std::wstring& wstr) { + std::string s; + s.reserve(wstr.size()); + for (auto c : wstr) { + s += (c <= 0xff) ? static_cast<char>(c) : '?'; + } + return ::Catch::Detail::stringify(s); +} +#endif + +std::string StringMaker<char const*>::convert(char const* str) { + if (str) { + return ::Catch::Detail::stringify(std::string{ str }); + } else { + return{ "{null string}" }; + } +} +std::string StringMaker<char*>::convert(char* str) { + if (str) { + return ::Catch::Detail::stringify(std::string{ str }); + } else { + return{ "{null string}" }; + } +} +#ifdef CATCH_CONFIG_WCHAR +std::string StringMaker<wchar_t const*>::convert(wchar_t const * str) { + if (str) { + return ::Catch::Detail::stringify(std::wstring{ str }); + } else { + return{ "{null string}" }; + } +} +std::string StringMaker<wchar_t *>::convert(wchar_t * str) { + if (str) { + return ::Catch::Detail::stringify(std::wstring{ str }); + } else { + return{ "{null string}" }; + } +} +#endif + +std::string StringMaker<int>::convert(int value) { + return ::Catch::Detail::stringify(static_cast<long long>(value)); +} +std::string StringMaker<long>::convert(long value) { + return ::Catch::Detail::stringify(static_cast<long long>(value)); +} +std::string StringMaker<long long>::convert(long long value) { + ReusableStringStream rss; + rss << value; + if (value > Detail::hexThreshold) { + rss << " (0x" << std::hex << value << ')'; + } + return rss.str(); +} + +std::string StringMaker<unsigned int>::convert(unsigned int value) { + return ::Catch::Detail::stringify(static_cast<unsigned long long>(value)); +} +std::string StringMaker<unsigned long>::convert(unsigned long value) { + return ::Catch::Detail::stringify(static_cast<unsigned long long>(value)); +} +std::string StringMaker<unsigned long long>::convert(unsigned long long value) { + ReusableStringStream rss; + rss << value; + if (value > Detail::hexThreshold) { + rss << " (0x" << std::hex << value << ')'; + } + return rss.str(); +} + +std::string StringMaker<bool>::convert(bool b) { + return b ? "true" : "false"; +} + +std::string StringMaker<char>::convert(char value) { + if (value == '\r') { + return "'\\r'"; + } else if (value == '\f') { + return "'\\f'"; + } else if (value == '\n') { + return "'\\n'"; + } else if (value == '\t') { + return "'\\t'"; + } else if ('\0' <= value && value < ' ') { + return ::Catch::Detail::stringify(static_cast<unsigned int>(value)); + } else { + char chstr[] = "' '"; + chstr[1] = value; + return chstr; + } +} +std::string StringMaker<signed char>::convert(signed char c) { + return ::Catch::Detail::stringify(static_cast<char>(c)); +} +std::string StringMaker<unsigned char>::convert(unsigned char c) { + return ::Catch::Detail::stringify(static_cast<char>(c)); +} + +std::string StringMaker<std::nullptr_t>::convert(std::nullptr_t) { + return "nullptr"; +} + +std::string StringMaker<float>::convert(float value) { + return fpToString(value, 5) + 'f'; +} +std::string StringMaker<double>::convert(double value) { + return fpToString(value, 10); +} + +std::string ratio_string<std::atto>::symbol() { return "a"; } +std::string ratio_string<std::femto>::symbol() { return "f"; } +std::string ratio_string<std::pico>::symbol() { return "p"; } +std::string ratio_string<std::nano>::symbol() { return "n"; } +std::string ratio_string<std::micro>::symbol() { return "u"; } +std::string ratio_string<std::milli>::symbol() { return "m"; } + +} // end namespace Catch + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif + +// end catch_tostring.cpp +// start catch_totals.cpp + +namespace Catch { + + Counts Counts::operator - ( Counts const& other ) const { + Counts diff; + diff.passed = passed - other.passed; + diff.failed = failed - other.failed; + diff.failedButOk = failedButOk - other.failedButOk; + return diff; + } + + Counts& Counts::operator += ( Counts const& other ) { + passed += other.passed; + failed += other.failed; + failedButOk += other.failedButOk; + return *this; + } + + std::size_t Counts::total() const { + return passed + failed + failedButOk; + } + bool Counts::allPassed() const { + return failed == 0 && failedButOk == 0; + } + bool Counts::allOk() const { + return failed == 0; + } + + Totals Totals::operator - ( Totals const& other ) const { + Totals diff; + diff.assertions = assertions - other.assertions; + diff.testCases = testCases - other.testCases; + return diff; + } + + Totals& Totals::operator += ( Totals const& other ) { + assertions += other.assertions; + testCases += other.testCases; + return *this; + } + + Totals Totals::delta( Totals const& prevTotals ) const { + Totals diff = *this - prevTotals; + if( diff.assertions.failed > 0 ) + ++diff.testCases.failed; + else if( diff.assertions.failedButOk > 0 ) + ++diff.testCases.failedButOk; + else + ++diff.testCases.passed; + return diff; + } + +} +// end catch_totals.cpp +// start catch_uncaught_exceptions.cpp + +#include <exception> + +namespace Catch { + bool uncaught_exceptions() { +#if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) + return std::uncaught_exceptions() > 0; +#else + return std::uncaught_exception(); +#endif + } +} // end namespace Catch +// end catch_uncaught_exceptions.cpp +// start catch_version.cpp + +#include <ostream> + +namespace Catch { + + Version::Version + ( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + char const * const _branchName, + unsigned int _buildNumber ) + : majorVersion( _majorVersion ), + minorVersion( _minorVersion ), + patchNumber( _patchNumber ), + branchName( _branchName ), + buildNumber( _buildNumber ) + {} + + std::ostream& operator << ( std::ostream& os, Version const& version ) { + os << version.majorVersion << '.' + << version.minorVersion << '.' + << version.patchNumber; + // branchName is never null -> 0th char is \0 if it is empty + if (version.branchName[0]) { + os << '-' << version.branchName + << '.' << version.buildNumber; + } + return os; + } + + Version const& libraryVersion() { + static Version version( 2, 3, 0, "", 0 ); + return version; + } + +} +// end catch_version.cpp +// start catch_wildcard_pattern.cpp + +#include <sstream> + +namespace Catch { + + WildcardPattern::WildcardPattern( std::string const& pattern, + CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_pattern( adjustCase( pattern ) ) + { + if( startsWith( m_pattern, '*' ) ) { + m_pattern = m_pattern.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_pattern, '*' ) ) { + m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); + m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd ); + } + } + + bool WildcardPattern::matches( std::string const& str ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_pattern == adjustCase( str ); + case WildcardAtStart: + return endsWith( adjustCase( str ), m_pattern ); + case WildcardAtEnd: + return startsWith( adjustCase( str ), m_pattern ); + case WildcardAtBothEnds: + return contains( adjustCase( str ), m_pattern ); + default: + CATCH_INTERNAL_ERROR( "Unknown enum" ); + } + } + + std::string WildcardPattern::adjustCase( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; + } +} +// end catch_wildcard_pattern.cpp +// start catch_xmlwriter.cpp + +#include <iomanip> + +using uchar = unsigned char; + +namespace Catch { + +namespace { + + size_t trailingBytes(unsigned char c) { + if ((c & 0xE0) == 0xC0) { + return 2; + } + if ((c & 0xF0) == 0xE0) { + return 3; + } + if ((c & 0xF8) == 0xF0) { + return 4; + } + CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); + } + + uint32_t headerValue(unsigned char c) { + if ((c & 0xE0) == 0xC0) { + return c & 0x1F; + } + if ((c & 0xF0) == 0xE0) { + return c & 0x0F; + } + if ((c & 0xF8) == 0xF0) { + return c & 0x07; + } + CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); + } + + void hexEscapeChar(std::ostream& os, unsigned char c) { + os << "\\x" + << std::uppercase << std::hex << std::setfill('0') << std::setw(2) + << static_cast<int>(c); + } + +} // anonymous namespace + + XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) + : m_str( str ), + m_forWhat( forWhat ) + {} + + void XmlEncode::encodeTo( std::ostream& os ) const { + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: http://www.w3.org/TR/xml/#syntax) + + for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { + uchar c = m_str[idx]; + switch (c) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: http://www.w3.org/TR/xml/#syntax + if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']') + os << ">"; + else + os << c; + break; + + case '\"': + if (m_forWhat == ForAttributes) + os << """; + else + os << c; + break; + + default: + // Check for control characters and invalid utf-8 + + // Escape control characters in standard ascii + // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 + if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) { + hexEscapeChar(os, c); + break; + } + + // Plain ASCII: Write it to stream + if (c < 0x7F) { + os << c; + break; + } + + // UTF-8 territory + // Check if the encoding is valid and if it is not, hex escape bytes. + // Important: We do not check the exact decoded values for validity, only the encoding format + // First check that this bytes is a valid lead byte: + // This means that it is not encoded as 1111 1XXX + // Or as 10XX XXXX + if (c < 0xC0 || + c >= 0xF8) { + hexEscapeChar(os, c); + break; + } + + auto encBytes = trailingBytes(c); + // Are there enough bytes left to avoid accessing out-of-bounds memory? + if (idx + encBytes - 1 >= m_str.size()) { + hexEscapeChar(os, c); + break; + } + // The header is valid, check data + // The next encBytes bytes must together be a valid utf-8 + // This means: bitpattern 10XX XXXX and the extracted value is sane (ish) + bool valid = true; + uint32_t value = headerValue(c); + for (std::size_t n = 1; n < encBytes; ++n) { + uchar nc = m_str[idx + n]; + valid &= ((nc & 0xC0) == 0x80); + value = (value << 6) | (nc & 0x3F); + } + + if ( + // Wrong bit pattern of following bytes + (!valid) || + // Overlong encodings + (value < 0x80) || + (0x80 <= value && value < 0x800 && encBytes > 2) || + (0x800 < value && value < 0x10000 && encBytes > 3) || + // Encoded value out of range + (value >= 0x110000) + ) { + hexEscapeChar(os, c); + break; + } + + // If we got here, this is in fact a valid(ish) utf-8 sequence + for (std::size_t n = 0; n < encBytes; ++n) { + os << m_str[idx + n]; + } + idx += encBytes - 1; + break; + } + } + } + + std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } + + XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer ) + : m_writer( writer ) + {} + + XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept + : m_writer( other.m_writer ){ + other.m_writer = nullptr; + } + XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept { + if ( m_writer ) { + m_writer->endElement(); + } + m_writer = other.m_writer; + other.m_writer = nullptr; + return *this; + } + + XmlWriter::ScopedElement::~ScopedElement() { + if( m_writer ) + m_writer->endElement(); + } + + XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) { + m_writer->writeText( text, indent ); + return *this; + } + + XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) + { + writeDeclaration(); + } + + XmlWriter::~XmlWriter() { + while( !m_tags.empty() ) + endElement(); + } + + XmlWriter& XmlWriter::startElement( std::string const& name ) { + ensureTagClosed(); + newlineIfNecessary(); + m_os << m_indent << '<' << name; + m_tags.push_back( name ); + m_indent += " "; + m_tagIsOpen = true; + return *this; + } + + XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) { + ScopedElement scoped( this ); + startElement( name ); + return scoped; + } + + XmlWriter& XmlWriter::endElement() { + newlineIfNecessary(); + m_indent = m_indent.substr( 0, m_indent.size()-2 ); + if( m_tagIsOpen ) { + m_os << "/>"; + m_tagIsOpen = false; + } + else { + m_os << m_indent << "</" << m_tags.back() << ">"; + } + m_os << std::endl; + m_tags.pop_back(); + return *this; + } + + XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) + m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; + return *this; + } + + XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) { + m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; + return *this; + } + + XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if( tagWasOpen && indent ) + m_os << m_indent; + m_os << XmlEncode( text ); + m_needsNewline = true; + } + return *this; + } + + XmlWriter& XmlWriter::writeComment( std::string const& text ) { + ensureTagClosed(); + m_os << m_indent << "<!--" << text << "-->"; + m_needsNewline = true; + return *this; + } + + void XmlWriter::writeStylesheetRef( std::string const& url ) { + m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n"; + } + + XmlWriter& XmlWriter::writeBlankLine() { + ensureTagClosed(); + m_os << '\n'; + return *this; + } + + void XmlWriter::ensureTagClosed() { + if( m_tagIsOpen ) { + m_os << ">" << std::endl; + m_tagIsOpen = false; + } + } + + void XmlWriter::writeDeclaration() { + m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; + } + + void XmlWriter::newlineIfNecessary() { + if( m_needsNewline ) { + m_os << std::endl; + m_needsNewline = false; + } + } +} +// end catch_xmlwriter.cpp +// start catch_reporter_bases.cpp + +#include <cstring> +#include <cfloat> +#include <cstdio> +#include <cassert> +#include <memory> + +namespace Catch { + void prepareExpandedExpression(AssertionResult& result) { + result.getExpandedExpression(); + } + + // Because formatting using c++ streams is stateful, drop down to C is required + // Alternatively we could use stringstream, but its performance is... not good. + std::string getFormattedDuration( double duration ) { + // Max exponent + 1 is required to represent the whole part + // + 1 for decimal point + // + 3 for the 3 decimal places + // + 1 for null terminator + const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; + char buffer[maxDoubleSize]; + + // Save previous errno, to prevent sprintf from overwriting it + ErrnoGuard guard; +#ifdef _MSC_VER + sprintf_s(buffer, "%.3f", duration); +#else + sprintf(buffer, "%.3f", duration); +#endif + return std::string(buffer); + } + + TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config) + :StreamingReporterBase(_config) {} + + void TestEventListenerBase::assertionStarting(AssertionInfo const &) {} + + bool TestEventListenerBase::assertionEnded(AssertionStats const &) { + return false; + } + +} // end namespace Catch +// end catch_reporter_bases.cpp +// start catch_reporter_compact.cpp + +namespace { + +#ifdef CATCH_PLATFORM_MAC + const char* failedString() { return "FAILED"; } + const char* passedString() { return "PASSED"; } +#else + const char* failedString() { return "failed"; } + const char* passedString() { return "passed"; } +#endif + + // Colour::LightGrey + Catch::Colour::Code dimColour() { return Catch::Colour::FileName; } + + std::string bothOrAll( std::size_t count ) { + return count == 1 ? std::string() : + count == 2 ? "both " : "all " ; + } + +} // anon namespace + +namespace Catch { +namespace { +// Colour, message variants: +// - white: No tests ran. +// - red: Failed [both/all] N test cases, failed [both/all] M assertions. +// - white: Passed [both/all] N test cases (no assertions). +// - red: Failed N tests cases, failed M assertions. +// - green: Passed [both/all] N tests cases with M assertions. +void printTotals(std::ostream& out, const Totals& totals) { + if (totals.testCases.total() == 0) { + out << "No tests ran."; + } else if (totals.testCases.failed == totals.testCases.total()) { + Colour colour(Colour::ResultError); + const std::string qualify_assertions_failed = + totals.assertions.failed == totals.assertions.total() ? + bothOrAll(totals.assertions.failed) : std::string(); + out << + "Failed " << bothOrAll(totals.testCases.failed) + << pluralise(totals.testCases.failed, "test case") << ", " + "failed " << qualify_assertions_failed << + pluralise(totals.assertions.failed, "assertion") << '.'; + } else if (totals.assertions.total() == 0) { + out << + "Passed " << bothOrAll(totals.testCases.total()) + << pluralise(totals.testCases.total(), "test case") + << " (no assertions)."; + } else if (totals.assertions.failed) { + Colour colour(Colour::ResultError); + out << + "Failed " << pluralise(totals.testCases.failed, "test case") << ", " + "failed " << pluralise(totals.assertions.failed, "assertion") << '.'; + } else { + Colour colour(Colour::ResultSuccess); + out << + "Passed " << bothOrAll(totals.testCases.passed) + << pluralise(totals.testCases.passed, "test case") << + " with " << pluralise(totals.assertions.passed, "assertion") << '.'; + } +} + +// Implementation of CompactReporter formatting +class AssertionPrinter { +public: + AssertionPrinter& operator= (AssertionPrinter const&) = delete; + AssertionPrinter(AssertionPrinter const&) = delete; + AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) + : stream(_stream) + , result(_stats.assertionResult) + , messages(_stats.infoMessages) + , itMessage(_stats.infoMessages.begin()) + , printInfoMessages(_printInfoMessages) {} + + void print() { + printSourceInfo(); + + itMessage = messages.begin(); + + switch (result.getResultType()) { + case ResultWas::Ok: + printResultType(Colour::ResultSuccess, passedString()); + printOriginalExpression(); + printReconstructedExpression(); + if (!result.hasExpression()) + printRemainingMessages(Colour::None); + else + printRemainingMessages(); + break; + case ResultWas::ExpressionFailed: + if (result.isOk()) + printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok")); + else + printResultType(Colour::Error, failedString()); + printOriginalExpression(); + printReconstructedExpression(); + printRemainingMessages(); + break; + case ResultWas::ThrewException: + printResultType(Colour::Error, failedString()); + printIssue("unexpected exception with message:"); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::FatalErrorCondition: + printResultType(Colour::Error, failedString()); + printIssue("fatal error condition with message:"); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::DidntThrowException: + printResultType(Colour::Error, failedString()); + printIssue("expected exception, got none"); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::Info: + printResultType(Colour::None, "info"); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::Warning: + printResultType(Colour::None, "warning"); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::ExplicitFailure: + printResultType(Colour::Error, failedString()); + printIssue("explicitly"); + printRemainingMessages(Colour::None); + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + printResultType(Colour::Error, "** internal error **"); + break; + } + } + +private: + void printSourceInfo() const { + Colour colourGuard(Colour::FileName); + stream << result.getSourceInfo() << ':'; + } + + void printResultType(Colour::Code colour, std::string const& passOrFail) const { + if (!passOrFail.empty()) { + { + Colour colourGuard(colour); + stream << ' ' << passOrFail; + } + stream << ':'; + } + } + + void printIssue(std::string const& issue) const { + stream << ' ' << issue; + } + + void printExpressionWas() { + if (result.hasExpression()) { + stream << ';'; + { + Colour colour(dimColour()); + stream << " expression was:"; + } + printOriginalExpression(); + } + } + + void printOriginalExpression() const { + if (result.hasExpression()) { + stream << ' ' << result.getExpression(); + } + } + + void printReconstructedExpression() const { + if (result.hasExpandedExpression()) { + { + Colour colour(dimColour()); + stream << " for: "; + } + stream << result.getExpandedExpression(); + } + } + + void printMessage() { + if (itMessage != messages.end()) { + stream << " '" << itMessage->message << '\''; + ++itMessage; + } + } + + void printRemainingMessages(Colour::Code colour = dimColour()) { + if (itMessage == messages.end()) + return; + + // using messages.end() directly yields (or auto) compilation error: + std::vector<MessageInfo>::const_iterator itEnd = messages.end(); + const std::size_t N = static_cast<std::size_t>(std::distance(itMessage, itEnd)); + + { + Colour colourGuard(colour); + stream << " with " << pluralise(N, "message") << ':'; + } + + for (; itMessage != itEnd; ) { + // If this assertion is a warning ignore any INFO messages + if (printInfoMessages || itMessage->type != ResultWas::Info) { + stream << " '" << itMessage->message << '\''; + if (++itMessage != itEnd) { + Colour colourGuard(dimColour()); + stream << " and"; + } + } + } + } + +private: + std::ostream& stream; + AssertionResult const& result; + std::vector<MessageInfo> messages; + std::vector<MessageInfo>::const_iterator itMessage; + bool printInfoMessages; +}; + +} // anon namespace + + std::string CompactReporter::getDescription() { + return "Reports test results on a single line, suitable for IDEs"; + } + + ReporterPreferences CompactReporter::getPreferences() const { + return m_reporterPrefs; + } + + void CompactReporter::noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << '\'' << std::endl; + } + + void CompactReporter::assertionStarting( AssertionInfo const& ) {} + + bool CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + + stream << std::endl; + return true; + } + + void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { + if (m_config->showDurations() == ShowDurations::Always) { + stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; + } + } + + void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) { + printTotals( stream, _testRunStats.totals ); + stream << '\n' << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + CompactReporter::~CompactReporter() {} + + CATCH_REGISTER_REPORTER( "compact", CompactReporter ) + +} // end namespace Catch +// end catch_reporter_compact.cpp +// start catch_reporter_console.cpp + +#include <cfloat> +#include <cstdio> + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch + // Note that 4062 (not all labels are handled + // and default is missing) is enabled +#endif + +namespace Catch { + +namespace { + +// Formatter impl for ConsoleReporter +class ConsoleAssertionPrinter { +public: + ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete; + ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete; + ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) + : stream(_stream), + stats(_stats), + result(_stats.assertionResult), + colour(Colour::None), + message(result.getMessage()), + messages(_stats.infoMessages), + printInfoMessages(_printInfoMessages) { + switch (result.getResultType()) { + case ResultWas::Ok: + colour = Colour::Success; + passOrFail = "PASSED"; + //if( result.hasMessage() ) + if (_stats.infoMessages.size() == 1) + messageLabel = "with message"; + if (_stats.infoMessages.size() > 1) + messageLabel = "with messages"; + break; + case ResultWas::ExpressionFailed: + if (result.isOk()) { + colour = Colour::Success; + passOrFail = "FAILED - but was ok"; + } else { + colour = Colour::Error; + passOrFail = "FAILED"; + } + if (_stats.infoMessages.size() == 1) + messageLabel = "with message"; + if (_stats.infoMessages.size() > 1) + messageLabel = "with messages"; + break; + case ResultWas::ThrewException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to unexpected exception with "; + if (_stats.infoMessages.size() == 1) + messageLabel += "message"; + if (_stats.infoMessages.size() > 1) + messageLabel += "messages"; + break; + case ResultWas::FatalErrorCondition: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to a fatal error condition"; + break; + case ResultWas::DidntThrowException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "because no exception was thrown where one was expected"; + break; + case ResultWas::Info: + messageLabel = "info"; + break; + case ResultWas::Warning: + messageLabel = "warning"; + break; + case ResultWas::ExplicitFailure: + passOrFail = "FAILED"; + colour = Colour::Error; + if (_stats.infoMessages.size() == 1) + messageLabel = "explicitly with message"; + if (_stats.infoMessages.size() > 1) + messageLabel = "explicitly with messages"; + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + passOrFail = "** internal error **"; + colour = Colour::Error; + break; + } + } + + void print() const { + printSourceInfo(); + if (stats.totals.assertions.total() > 0) { + if (result.isOk()) + stream << '\n'; + printResultType(); + printOriginalExpression(); + printReconstructedExpression(); + } else { + stream << '\n'; + } + printMessage(); + } + +private: + void printResultType() const { + if (!passOrFail.empty()) { + Colour colourGuard(colour); + stream << passOrFail << ":\n"; + } + } + void printOriginalExpression() const { + if (result.hasExpression()) { + Colour colourGuard(Colour::OriginalExpression); + stream << " "; + stream << result.getExpressionInMacro(); + stream << '\n'; + } + } + void printReconstructedExpression() const { + if (result.hasExpandedExpression()) { + stream << "with expansion:\n"; + Colour colourGuard(Colour::ReconstructedExpression); + stream << Column(result.getExpandedExpression()).indent(2) << '\n'; + } + } + void printMessage() const { + if (!messageLabel.empty()) + stream << messageLabel << ':' << '\n'; + for (auto const& msg : messages) { + // If this assertion is a warning ignore any INFO messages + if (printInfoMessages || msg.type != ResultWas::Info) + stream << Column(msg.message).indent(2) << '\n'; + } + } + void printSourceInfo() const { + Colour colourGuard(Colour::FileName); + stream << result.getSourceInfo() << ": "; + } + + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + Colour::Code colour; + std::string passOrFail; + std::string messageLabel; + std::string message; + std::vector<MessageInfo> messages; + bool printInfoMessages; +}; + +std::size_t makeRatio(std::size_t number, std::size_t total) { + std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0; + return (ratio == 0 && number > 0) ? 1 : ratio; +} + +std::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k) { + if (i > j && i > k) + return i; + else if (j > k) + return j; + else + return k; +} + +struct ColumnInfo { + enum Justification { Left, Right }; + std::string name; + int width; + Justification justification; +}; +struct ColumnBreak {}; +struct RowBreak {}; + +class Duration { + enum class Unit { + Auto, + Nanoseconds, + Microseconds, + Milliseconds, + Seconds, + Minutes + }; + static const uint64_t s_nanosecondsInAMicrosecond = 1000; + static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond; + static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond; + static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond; + + uint64_t m_inNanoseconds; + Unit m_units; + +public: + explicit Duration(uint64_t inNanoseconds, Unit units = Unit::Auto) + : m_inNanoseconds(inNanoseconds), + m_units(units) { + if (m_units == Unit::Auto) { + if (m_inNanoseconds < s_nanosecondsInAMicrosecond) + m_units = Unit::Nanoseconds; + else if (m_inNanoseconds < s_nanosecondsInAMillisecond) + m_units = Unit::Microseconds; + else if (m_inNanoseconds < s_nanosecondsInASecond) + m_units = Unit::Milliseconds; + else if (m_inNanoseconds < s_nanosecondsInAMinute) + m_units = Unit::Seconds; + else + m_units = Unit::Minutes; + } + + } + + auto value() const -> double { + switch (m_units) { + case Unit::Microseconds: + return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMicrosecond); + case Unit::Milliseconds: + return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMillisecond); + case Unit::Seconds: + return m_inNanoseconds / static_cast<double>(s_nanosecondsInASecond); + case Unit::Minutes: + return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute); + default: + return static_cast<double>(m_inNanoseconds); + } + } + auto unitsAsString() const -> std::string { + switch (m_units) { + case Unit::Nanoseconds: + return "ns"; + case Unit::Microseconds: + return "µs"; + case Unit::Milliseconds: + return "ms"; + case Unit::Seconds: + return "s"; + case Unit::Minutes: + return "m"; + default: + return "** internal error **"; + } + + } + friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& { + return os << duration.value() << " " << duration.unitsAsString(); + } +}; +} // end anon namespace + +class TablePrinter { + std::ostream& m_os; + std::vector<ColumnInfo> m_columnInfos; + std::ostringstream m_oss; + int m_currentColumn = -1; + bool m_isOpen = false; + +public: + TablePrinter( std::ostream& os, std::vector<ColumnInfo> columnInfos ) + : m_os( os ), + m_columnInfos( std::move( columnInfos ) ) {} + + auto columnInfos() const -> std::vector<ColumnInfo> const& { + return m_columnInfos; + } + + void open() { + if (!m_isOpen) { + m_isOpen = true; + *this << RowBreak(); + for (auto const& info : m_columnInfos) + *this << info.name << ColumnBreak(); + *this << RowBreak(); + m_os << Catch::getLineOfChars<'-'>() << "\n"; + } + } + void close() { + if (m_isOpen) { + *this << RowBreak(); + m_os << std::endl; + m_isOpen = false; + } + } + + template<typename T> + friend TablePrinter& operator << (TablePrinter& tp, T const& value) { + tp.m_oss << value; + return tp; + } + + friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) { + auto colStr = tp.m_oss.str(); + // This takes account of utf8 encodings + auto strSize = Catch::StringRef(colStr).numberOfCharacters(); + tp.m_oss.str(""); + tp.open(); + if (tp.m_currentColumn == static_cast<int>(tp.m_columnInfos.size() - 1)) { + tp.m_currentColumn = -1; + tp.m_os << "\n"; + } + tp.m_currentColumn++; + + auto colInfo = tp.m_columnInfos[tp.m_currentColumn]; + auto padding = (strSize + 2 < static_cast<std::size_t>(colInfo.width)) + ? std::string(colInfo.width - (strSize + 2), ' ') + : std::string(); + if (colInfo.justification == ColumnInfo::Left) + tp.m_os << colStr << padding << " "; + else + tp.m_os << padding << colStr << " "; + return tp; + } + + friend TablePrinter& operator << (TablePrinter& tp, RowBreak) { + if (tp.m_currentColumn > 0) { + tp.m_os << "\n"; + tp.m_currentColumn = -1; + } + return tp; + } +}; + +ConsoleReporter::ConsoleReporter(ReporterConfig const& config) + : StreamingReporterBase(config), + m_tablePrinter(new TablePrinter(config.stream(), + { + { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left }, + { "iters", 8, ColumnInfo::Right }, + { "elapsed ns", 14, ColumnInfo::Right }, + { "average", 14, ColumnInfo::Right } + })) {} +ConsoleReporter::~ConsoleReporter() = default; + +std::string ConsoleReporter::getDescription() { + return "Reports test results as plain lines of text"; +} + +void ConsoleReporter::noMatchingTestCases(std::string const& spec) { + stream << "No test cases matched '" << spec << '\'' << std::endl; +} + +void ConsoleReporter::assertionStarting(AssertionInfo const&) {} + +bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); + + // Drop out if result was successful but we're not printing them. + if (!includeResults && result.getResultType() != ResultWas::Warning) + return false; + + lazyPrint(); + + ConsoleAssertionPrinter printer(stream, _assertionStats, includeResults); + printer.print(); + stream << std::endl; + return true; +} + +void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) { + m_headerPrinted = false; + StreamingReporterBase::sectionStarting(_sectionInfo); +} +void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) { + m_tablePrinter->close(); + if (_sectionStats.missingAssertions) { + lazyPrint(); + Colour colour(Colour::ResultError); + if (m_sectionStack.size() > 1) + stream << "\nNo assertions in section"; + else + stream << "\nNo assertions in test case"; + stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; + } + if (m_config->showDurations() == ShowDurations::Always) { + stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; + } + if (m_headerPrinted) { + m_headerPrinted = false; + } + StreamingReporterBase::sectionEnded(_sectionStats); +} + +void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) { + lazyPrintWithoutClosingBenchmarkTable(); + + auto nameCol = Column( info.name ).width( static_cast<std::size_t>( m_tablePrinter->columnInfos()[0].width - 2 ) ); + + bool firstLine = true; + for (auto line : nameCol) { + if (!firstLine) + (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak(); + else + firstLine = false; + + (*m_tablePrinter) << line << ColumnBreak(); + } +} +void ConsoleReporter::benchmarkEnded(BenchmarkStats const& stats) { + Duration average(stats.elapsedTimeInNanoseconds / stats.iterations); + (*m_tablePrinter) + << stats.iterations << ColumnBreak() + << stats.elapsedTimeInNanoseconds << ColumnBreak() + << average << ColumnBreak(); +} + +void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) { + m_tablePrinter->close(); + StreamingReporterBase::testCaseEnded(_testCaseStats); + m_headerPrinted = false; +} +void ConsoleReporter::testGroupEnded(TestGroupStats const& _testGroupStats) { + if (currentGroupInfo.used) { + printSummaryDivider(); + stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; + printTotals(_testGroupStats.totals); + stream << '\n' << std::endl; + } + StreamingReporterBase::testGroupEnded(_testGroupStats); +} +void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) { + printTotalsDivider(_testRunStats.totals); + printTotals(_testRunStats.totals); + stream << std::endl; + StreamingReporterBase::testRunEnded(_testRunStats); +} + +void ConsoleReporter::lazyPrint() { + + m_tablePrinter->close(); + lazyPrintWithoutClosingBenchmarkTable(); +} + +void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() { + + if (!currentTestRunInfo.used) + lazyPrintRunInfo(); + if (!currentGroupInfo.used) + lazyPrintGroupInfo(); + + if (!m_headerPrinted) { + printTestCaseAndSectionHeader(); + m_headerPrinted = true; + } +} +void ConsoleReporter::lazyPrintRunInfo() { + stream << '\n' << getLineOfChars<'~'>() << '\n'; + Colour colour(Colour::SecondaryText); + stream << currentTestRunInfo->name + << " is a Catch v" << libraryVersion() << " host application.\n" + << "Run with -? for options\n\n"; + + if (m_config->rngSeed() != 0) + stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; + + currentTestRunInfo.used = true; +} +void ConsoleReporter::lazyPrintGroupInfo() { + if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1) { + printClosedHeader("Group: " + currentGroupInfo->name); + currentGroupInfo.used = true; + } +} +void ConsoleReporter::printTestCaseAndSectionHeader() { + assert(!m_sectionStack.empty()); + printOpenHeader(currentTestCaseInfo->name); + + if (m_sectionStack.size() > 1) { + Colour colourGuard(Colour::Headers); + + auto + it = m_sectionStack.begin() + 1, // Skip first section (test case) + itEnd = m_sectionStack.end(); + for (; it != itEnd; ++it) + printHeaderString(it->name, 2); + } + + SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; + + if (!lineInfo.empty()) { + stream << getLineOfChars<'-'>() << '\n'; + Colour colourGuard(Colour::FileName); + stream << lineInfo << '\n'; + } + stream << getLineOfChars<'.'>() << '\n' << std::endl; +} + +void ConsoleReporter::printClosedHeader(std::string const& _name) { + printOpenHeader(_name); + stream << getLineOfChars<'.'>() << '\n'; +} +void ConsoleReporter::printOpenHeader(std::string const& _name) { + stream << getLineOfChars<'-'>() << '\n'; + { + Colour colourGuard(Colour::Headers); + printHeaderString(_name); + } +} + +// if string has a : in first line will set indent to follow it on +// subsequent lines +void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) { + std::size_t i = _string.find(": "); + if (i != std::string::npos) + i += 2; + else + i = 0; + stream << Column(_string).indent(indent + i).initialIndent(indent) << '\n'; +} + +struct SummaryColumn { + + SummaryColumn( std::string _label, Colour::Code _colour ) + : label( std::move( _label ) ), + colour( _colour ) {} + SummaryColumn addRow( std::size_t count ) { + ReusableStringStream rss; + rss << count; + std::string row = rss.str(); + for (auto& oldRow : rows) { + while (oldRow.size() < row.size()) + oldRow = ' ' + oldRow; + while (oldRow.size() > row.size()) + row = ' ' + row; + } + rows.push_back(row); + return *this; + } + + std::string label; + Colour::Code colour; + std::vector<std::string> rows; + +}; + +void ConsoleReporter::printTotals( Totals const& totals ) { + if (totals.testCases.total() == 0) { + stream << Colour(Colour::Warning) << "No tests ran\n"; + } else if (totals.assertions.total() > 0 && totals.testCases.allPassed()) { + stream << Colour(Colour::ResultSuccess) << "All tests passed"; + stream << " (" + << pluralise(totals.assertions.passed, "assertion") << " in " + << pluralise(totals.testCases.passed, "test case") << ')' + << '\n'; + } else { + + std::vector<SummaryColumn> columns; + columns.push_back(SummaryColumn("", Colour::None) + .addRow(totals.testCases.total()) + .addRow(totals.assertions.total())); + columns.push_back(SummaryColumn("passed", Colour::Success) + .addRow(totals.testCases.passed) + .addRow(totals.assertions.passed)); + columns.push_back(SummaryColumn("failed", Colour::ResultError) + .addRow(totals.testCases.failed) + .addRow(totals.assertions.failed)); + columns.push_back(SummaryColumn("failed as expected", Colour::ResultExpectedFailure) + .addRow(totals.testCases.failedButOk) + .addRow(totals.assertions.failedButOk)); + + printSummaryRow("test cases", columns, 0); + printSummaryRow("assertions", columns, 1); + } +} +void ConsoleReporter::printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row) { + for (auto col : cols) { + std::string value = col.rows[row]; + if (col.label.empty()) { + stream << label << ": "; + if (value != "0") + stream << value; + else + stream << Colour(Colour::Warning) << "- none -"; + } else if (value != "0") { + stream << Colour(Colour::LightGrey) << " | "; + stream << Colour(col.colour) + << value << ' ' << col.label; + } + } + stream << '\n'; +} + +void ConsoleReporter::printTotalsDivider(Totals const& totals) { + if (totals.testCases.total() > 0) { + std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total()); + std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total()); + std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total()); + while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1) + findMax(failedRatio, failedButOkRatio, passedRatio)++; + while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1) + findMax(failedRatio, failedButOkRatio, passedRatio)--; + + stream << Colour(Colour::Error) << std::string(failedRatio, '='); + stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '='); + if (totals.testCases.allPassed()) + stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '='); + else + stream << Colour(Colour::Success) << std::string(passedRatio, '='); + } else { + stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '='); + } + stream << '\n'; +} +void ConsoleReporter::printSummaryDivider() { + stream << getLineOfChars<'-'>() << '\n'; +} + +CATCH_REGISTER_REPORTER("console", ConsoleReporter) + +} // end namespace Catch + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif +// end catch_reporter_console.cpp +// start catch_reporter_junit.cpp + +#include <cassert> +#include <sstream> +#include <ctime> +#include <algorithm> + +namespace Catch { + + namespace { + std::string getCurrentTimestamp() { + // Beware, this is not reentrant because of backward compatibility issues + // Also, UTC only, again because of backward compatibility (%z is C++11) + time_t rawtime; + std::time(&rawtime); + auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); + +#ifdef _MSC_VER + std::tm timeInfo = {}; + gmtime_s(&timeInfo, &rawtime); +#else + std::tm* timeInfo; + timeInfo = std::gmtime(&rawtime); +#endif + + char timeStamp[timeStampSize]; + const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; + +#ifdef _MSC_VER + std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); +#else + std::strftime(timeStamp, timeStampSize, fmt, timeInfo); +#endif + return std::string(timeStamp); + } + + std::string fileNameTag(const std::vector<std::string> &tags) { + auto it = std::find_if(begin(tags), + end(tags), + [] (std::string const& tag) {return tag.front() == '#'; }); + if (it != tags.end()) + return it->substr(1); + return std::string(); + } + } // anonymous namespace + + JunitReporter::JunitReporter( ReporterConfig const& _config ) + : CumulativeReporterBase( _config ), + xml( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + m_reporterPrefs.shouldReportAllAssertions = true; + } + + JunitReporter::~JunitReporter() {} + + std::string JunitReporter::getDescription() { + return "Reports test results in an XML format that looks like Ant's junitreport target"; + } + + void JunitReporter::noMatchingTestCases( std::string const& /*spec*/ ) {} + + void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) { + CumulativeReporterBase::testRunStarting( runInfo ); + xml.startElement( "testsuites" ); + } + + void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) { + suiteTimer.start(); + stdOutForSuite.clear(); + stdErrForSuite.clear(); + unexpectedExceptions = 0; + CumulativeReporterBase::testGroupStarting( groupInfo ); + } + + void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) { + m_okToFail = testCaseInfo.okToFail(); + } + + bool JunitReporter::assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) + unexpectedExceptions++; + return CumulativeReporterBase::assertionEnded( assertionStats ); + } + + void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { + stdOutForSuite += testCaseStats.stdOut; + stdErrForSuite += testCaseStats.stdErr; + CumulativeReporterBase::testCaseEnded( testCaseStats ); + } + + void JunitReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { + double suiteTime = suiteTimer.getElapsedSeconds(); + CumulativeReporterBase::testGroupEnded( testGroupStats ); + writeGroup( *m_testGroups.back(), suiteTime ); + } + + void JunitReporter::testRunEndedCumulative() { + xml.endElement(); + } + + void JunitReporter::writeGroup( TestGroupNode const& groupNode, double suiteTime ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); + TestGroupStats const& stats = groupNode.value; + xml.writeAttribute( "name", stats.groupInfo.name ); + xml.writeAttribute( "errors", unexpectedExceptions ); + xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); + xml.writeAttribute( "tests", stats.totals.assertions.total() ); + xml.writeAttribute( "hostname", "tbd" ); // !TBD + if( m_config->showDurations() == ShowDurations::Never ) + xml.writeAttribute( "time", "" ); + else + xml.writeAttribute( "time", suiteTime ); + xml.writeAttribute( "timestamp", getCurrentTimestamp() ); + + // Write test cases + for( auto const& child : groupNode.children ) + writeTestCase( *child ); + + xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), false ); + xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), false ); + } + + void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) { + TestCaseStats const& stats = testCaseNode.value; + + // All test cases have exactly one section - which represents the + // test case itself. That section may have 0-n nested sections + assert( testCaseNode.children.size() == 1 ); + SectionNode const& rootSection = *testCaseNode.children.front(); + + std::string className = stats.testInfo.className; + + if( className.empty() ) { + className = fileNameTag(stats.testInfo.tags); + if ( className.empty() ) + className = "global"; + } + + if ( !m_config->name().empty() ) + className = m_config->name() + "." + className; + + writeSection( className, "", rootSection ); + } + + void JunitReporter::writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode ) { + std::string name = trim( sectionNode.stats.sectionInfo.name ); + if( !rootName.empty() ) + name = rootName + '/' + name; + + if( !sectionNode.assertions.empty() || + !sectionNode.stdOut.empty() || + !sectionNode.stdErr.empty() ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); + if( className.empty() ) { + xml.writeAttribute( "classname", name ); + xml.writeAttribute( "name", "root" ); + } + else { + xml.writeAttribute( "classname", className ); + xml.writeAttribute( "name", name ); + } + xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) ); + + writeAssertions( sectionNode ); + + if( !sectionNode.stdOut.empty() ) + xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); + if( !sectionNode.stdErr.empty() ) + xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); + } + for( auto const& childNode : sectionNode.childSections ) + if( className.empty() ) + writeSection( name, "", *childNode ); + else + writeSection( className, name, *childNode ); + } + + void JunitReporter::writeAssertions( SectionNode const& sectionNode ) { + for( auto const& assertion : sectionNode.assertions ) + writeAssertion( assertion ); + } + + void JunitReporter::writeAssertion( AssertionStats const& stats ) { + AssertionResult const& result = stats.assertionResult; + if( !result.isOk() ) { + std::string elementName; + switch( result.getResultType() ) { + case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: + elementName = "error"; + break; + case ResultWas::ExplicitFailure: + elementName = "failure"; + break; + case ResultWas::ExpressionFailed: + elementName = "failure"; + break; + case ResultWas::DidntThrowException: + elementName = "failure"; + break; + + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + elementName = "internalError"; + break; + } + + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); + + xml.writeAttribute( "message", result.getExpandedExpression() ); + xml.writeAttribute( "type", result.getTestMacroName() ); + + ReusableStringStream rss; + if( !result.getMessage().empty() ) + rss << result.getMessage() << '\n'; + for( auto const& msg : stats.infoMessages ) + if( msg.type == ResultWas::Info ) + rss << msg.message << '\n'; + + rss << "at " << result.getSourceInfo(); + xml.writeText( rss.str(), false ); + } + } + + CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + +} // end namespace Catch +// end catch_reporter_junit.cpp +// start catch_reporter_listening.cpp + +#include <cassert> + +namespace Catch { + + ListeningReporter::ListeningReporter() { + // We will assume that listeners will always want all assertions + m_preferences.shouldReportAllAssertions = true; + } + + void ListeningReporter::addListener( IStreamingReporterPtr&& listener ) { + m_listeners.push_back( std::move( listener ) ); + } + + void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) { + assert(!m_reporter && "Listening reporter can wrap only 1 real reporter"); + m_reporter = std::move( reporter ); + m_preferences.shouldRedirectStdOut = m_reporter->getPreferences().shouldRedirectStdOut; + } + + ReporterPreferences ListeningReporter::getPreferences() const { + return m_preferences; + } + + std::set<Verbosity> ListeningReporter::getSupportedVerbosities() { + return std::set<Verbosity>{ }; + } + + void ListeningReporter::noMatchingTestCases( std::string const& spec ) { + for ( auto const& listener : m_listeners ) { + listener->noMatchingTestCases( spec ); + } + m_reporter->noMatchingTestCases( spec ); + } + + void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) { + for ( auto const& listener : m_listeners ) { + listener->benchmarkStarting( benchmarkInfo ); + } + m_reporter->benchmarkStarting( benchmarkInfo ); + } + void ListeningReporter::benchmarkEnded( BenchmarkStats const& benchmarkStats ) { + for ( auto const& listener : m_listeners ) { + listener->benchmarkEnded( benchmarkStats ); + } + m_reporter->benchmarkEnded( benchmarkStats ); + } + + void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) { + for ( auto const& listener : m_listeners ) { + listener->testRunStarting( testRunInfo ); + } + m_reporter->testRunStarting( testRunInfo ); + } + + void ListeningReporter::testGroupStarting( GroupInfo const& groupInfo ) { + for ( auto const& listener : m_listeners ) { + listener->testGroupStarting( groupInfo ); + } + m_reporter->testGroupStarting( groupInfo ); + } + + void ListeningReporter::testCaseStarting( TestCaseInfo const& testInfo ) { + for ( auto const& listener : m_listeners ) { + listener->testCaseStarting( testInfo ); + } + m_reporter->testCaseStarting( testInfo ); + } + + void ListeningReporter::sectionStarting( SectionInfo const& sectionInfo ) { + for ( auto const& listener : m_listeners ) { + listener->sectionStarting( sectionInfo ); + } + m_reporter->sectionStarting( sectionInfo ); + } + + void ListeningReporter::assertionStarting( AssertionInfo const& assertionInfo ) { + for ( auto const& listener : m_listeners ) { + listener->assertionStarting( assertionInfo ); + } + m_reporter->assertionStarting( assertionInfo ); + } + + // The return value indicates if the messages buffer should be cleared: + bool ListeningReporter::assertionEnded( AssertionStats const& assertionStats ) { + for( auto const& listener : m_listeners ) { + static_cast<void>( listener->assertionEnded( assertionStats ) ); + } + return m_reporter->assertionEnded( assertionStats ); + } + + void ListeningReporter::sectionEnded( SectionStats const& sectionStats ) { + for ( auto const& listener : m_listeners ) { + listener->sectionEnded( sectionStats ); + } + m_reporter->sectionEnded( sectionStats ); + } + + void ListeningReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { + for ( auto const& listener : m_listeners ) { + listener->testCaseEnded( testCaseStats ); + } + m_reporter->testCaseEnded( testCaseStats ); + } + + void ListeningReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { + for ( auto const& listener : m_listeners ) { + listener->testGroupEnded( testGroupStats ); + } + m_reporter->testGroupEnded( testGroupStats ); + } + + void ListeningReporter::testRunEnded( TestRunStats const& testRunStats ) { + for ( auto const& listener : m_listeners ) { + listener->testRunEnded( testRunStats ); + } + m_reporter->testRunEnded( testRunStats ); + } + + void ListeningReporter::skipTest( TestCaseInfo const& testInfo ) { + for ( auto const& listener : m_listeners ) { + listener->skipTest( testInfo ); + } + m_reporter->skipTest( testInfo ); + } + + bool ListeningReporter::isMulti() const { + return true; + } + +} // end namespace Catch +// end catch_reporter_listening.cpp +// start catch_reporter_xml.cpp + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch + // Note that 4062 (not all labels are handled + // and default is missing) is enabled +#endif + +namespace Catch { + XmlReporter::XmlReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_xml(_config.stream()) + { + m_reporterPrefs.shouldRedirectStdOut = true; + m_reporterPrefs.shouldReportAllAssertions = true; + } + + XmlReporter::~XmlReporter() = default; + + std::string XmlReporter::getDescription() { + return "Reports test results as an XML document"; + } + + std::string XmlReporter::getStylesheetRef() const { + return std::string(); + } + + void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) { + m_xml + .writeAttribute( "filename", sourceInfo.file ) + .writeAttribute( "line", sourceInfo.line ); + } + + void XmlReporter::noMatchingTestCases( std::string const& s ) { + StreamingReporterBase::noMatchingTestCases( s ); + } + + void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) { + StreamingReporterBase::testRunStarting( testInfo ); + std::string stylesheetRef = getStylesheetRef(); + if( !stylesheetRef.empty() ) + m_xml.writeStylesheetRef( stylesheetRef ); + m_xml.startElement( "Catch" ); + if( !m_config->name().empty() ) + m_xml.writeAttribute( "name", m_config->name() ); + } + + void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) { + StreamingReporterBase::testGroupStarting( groupInfo ); + m_xml.startElement( "Group" ) + .writeAttribute( "name", groupInfo.name ); + } + + void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) { + StreamingReporterBase::testCaseStarting(testInfo); + m_xml.startElement( "TestCase" ) + .writeAttribute( "name", trim( testInfo.name ) ) + .writeAttribute( "description", testInfo.description ) + .writeAttribute( "tags", testInfo.tagsAsString() ); + + writeSourceInfo( testInfo.lineInfo ); + + if ( m_config->showDurations() == ShowDurations::Always ) + m_testCaseTimer.start(); + m_xml.ensureTagClosed(); + } + + void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) { + StreamingReporterBase::sectionStarting( sectionInfo ); + if( m_sectionDepth++ > 0 ) { + m_xml.startElement( "Section" ) + .writeAttribute( "name", trim( sectionInfo.name ) ); + writeSourceInfo( sectionInfo.lineInfo ); + m_xml.ensureTagClosed(); + } + } + + void XmlReporter::assertionStarting( AssertionInfo const& ) { } + + bool XmlReporter::assertionEnded( AssertionStats const& assertionStats ) { + + AssertionResult const& result = assertionStats.assertionResult; + + bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); + + if( includeResults || result.getResultType() == ResultWas::Warning ) { + // Print any info messages in <Info> tags. + for( auto const& msg : assertionStats.infoMessages ) { + if( msg.type == ResultWas::Info && includeResults ) { + m_xml.scopedElement( "Info" ) + .writeText( msg.message ); + } else if ( msg.type == ResultWas::Warning ) { + m_xml.scopedElement( "Warning" ) + .writeText( msg.message ); + } + } + } + + // Drop out if result was successful but we're not printing them. + if( !includeResults && result.getResultType() != ResultWas::Warning ) + return true; + + // Print the expression if there is one. + if( result.hasExpression() ) { + m_xml.startElement( "Expression" ) + .writeAttribute( "success", result.succeeded() ) + .writeAttribute( "type", result.getTestMacroName() ); + + writeSourceInfo( result.getSourceInfo() ); + + m_xml.scopedElement( "Original" ) + .writeText( result.getExpression() ); + m_xml.scopedElement( "Expanded" ) + .writeText( result.getExpandedExpression() ); + } + + // And... Print a result applicable to each result type. + switch( result.getResultType() ) { + case ResultWas::ThrewException: + m_xml.startElement( "Exception" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); + break; + case ResultWas::FatalErrorCondition: + m_xml.startElement( "FatalErrorCondition" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); + break; + case ResultWas::Info: + m_xml.scopedElement( "Info" ) + .writeText( result.getMessage() ); + break; + case ResultWas::Warning: + // Warning will already have been written + break; + case ResultWas::ExplicitFailure: + m_xml.startElement( "Failure" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); + break; + default: + break; + } + + if( result.hasExpression() ) + m_xml.endElement(); + + return true; + } + + void XmlReporter::sectionEnded( SectionStats const& sectionStats ) { + StreamingReporterBase::sectionEnded( sectionStats ); + if( --m_sectionDepth > 0 ) { + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); + e.writeAttribute( "successes", sectionStats.assertions.passed ); + e.writeAttribute( "failures", sectionStats.assertions.failed ); + e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); + + m_xml.endElement(); + } + } + + void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { + StreamingReporterBase::testCaseEnded( testCaseStats ); + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); + e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); + + if( !testCaseStats.stdOut.empty() ) + m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); + if( !testCaseStats.stdErr.empty() ) + m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); + + m_xml.endElement(); + } + + void XmlReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { + StreamingReporterBase::testGroupEnded( testGroupStats ); + // TODO: Check testGroupStats.aborting and act accordingly. + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) + .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) { + StreamingReporterBase::testRunEnded( testRunStats ); + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testRunStats.totals.assertions.passed ) + .writeAttribute( "failures", testRunStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + CATCH_REGISTER_REPORTER( "xml", XmlReporter ) + +} // end namespace Catch + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif +// end catch_reporter_xml.cpp + +namespace Catch { + LeakDetector leakDetector; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// end catch_impl.hpp +#endif + +#ifdef CATCH_CONFIG_MAIN +// start catch_default_main.hpp + +#ifndef __OBJC__ + +#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) +// Standard C/C++ Win32 Unicode wmain entry point +extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { +#else +// Standard C/C++ main entry point +int main (int argc, char * argv[]) { +#endif + + return Catch::Session().run( argc, argv ); +} + +#else // __OBJC__ + +// Objective-C entry point +int main (int argc, char * const argv[]) { +#if !CATCH_ARC_ENABLED + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; +#endif + + Catch::registerTestMethods(); + int result = Catch::Session().run( argc, (char**)argv ); + +#if !CATCH_ARC_ENABLED + [pool drain]; +#endif + + return result; +} + +#endif // __OBJC__ + +// end catch_default_main.hpp +#endif + +#if !defined(CATCH_CONFIG_IMPL_ONLY) + +#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED +# undef CLARA_CONFIG_MAIN +#endif + +#if !defined(CATCH_CONFIG_DISABLE) +////// +// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ +#ifdef CATCH_CONFIG_PREFIX_ALL + +#define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) + +#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", __VA_ARGS__ ) +#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) +#endif// CATCH_CONFIG_DISABLE_MATCHERS +#define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) + +#define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) +#define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) + +#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", __VA_ARGS__ ) +#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) + +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) + +#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) +#endif // CATCH_CONFIG_DISABLE_MATCHERS + +#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) +#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) +#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) ) + +#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) +#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) +#define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) +#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) +#define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) +#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) + +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() + +// "BDD-style" convenience wrappers +#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) +#define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) +#define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And when: " << desc ) +#define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) +#define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) + +// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required +#else + +#define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) + +#define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) +#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) + +#define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) +#define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) + +#define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) + +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) + +#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) +#endif // CATCH_CONFIG_DISABLE_MATCHERS + +#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) +#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) +#define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) ) + +#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) +#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) +#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) +#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) +#define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) +#define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() + +#endif + +#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) + +// "BDD-style" convenience wrappers +#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) + +#define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) +#define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) +#define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And when: " << desc ) +#define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) +#define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) + +using Catch::Detail::Approx; + +#else // CATCH_CONFIG_DISABLE + +////// +// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ +#ifdef CATCH_CONFIG_PREFIX_ALL + +#define CATCH_REQUIRE( ... ) (void)(0) +#define CATCH_REQUIRE_FALSE( ... ) (void)(0) + +#define CATCH_REQUIRE_THROWS( ... ) (void)(0) +#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) +#endif// CATCH_CONFIG_DISABLE_MATCHERS +#define CATCH_REQUIRE_NOTHROW( ... ) (void)(0) + +#define CATCH_CHECK( ... ) (void)(0) +#define CATCH_CHECK_FALSE( ... ) (void)(0) +#define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__) +#define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) +#define CATCH_CHECK_NOFAIL( ... ) (void)(0) + +#define CATCH_CHECK_THROWS( ... ) (void)(0) +#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) (void)(0) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define CATCH_CHECK_NOTHROW( ... ) (void)(0) + +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_CHECK_THAT( arg, matcher ) (void)(0) + +#define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS + +#define CATCH_INFO( msg ) (void)(0) +#define CATCH_WARN( msg ) (void)(0) +#define CATCH_CAPTURE( msg ) (void)(0) + +#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define CATCH_METHOD_AS_TEST_CASE( method, ... ) +#define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0) +#define CATCH_SECTION( ... ) +#define CATCH_DYNAMIC_SECTION( ... ) +#define CATCH_FAIL( ... ) (void)(0) +#define CATCH_FAIL_CHECK( ... ) (void)(0) +#define CATCH_SUCCEED( ... ) (void)(0) + +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) + +// "BDD-style" convenience wrappers +#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) +#define CATCH_GIVEN( desc ) +#define CATCH_WHEN( desc ) +#define CATCH_AND_WHEN( desc ) +#define CATCH_THEN( desc ) +#define CATCH_AND_THEN( desc ) + +// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required +#else + +#define REQUIRE( ... ) (void)(0) +#define REQUIRE_FALSE( ... ) (void)(0) + +#define REQUIRE_THROWS( ... ) (void)(0) +#define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) +#define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define REQUIRE_NOTHROW( ... ) (void)(0) + +#define CHECK( ... ) (void)(0) +#define CHECK_FALSE( ... ) (void)(0) +#define CHECKED_IF( ... ) if (__VA_ARGS__) +#define CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) +#define CHECK_NOFAIL( ... ) (void)(0) + +#define CHECK_THROWS( ... ) (void)(0) +#define CHECK_THROWS_AS( expr, exceptionType ) (void)(0) +#define CHECK_THROWS_WITH( expr, matcher ) (void)(0) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define CHECK_NOTHROW( ... ) (void)(0) + +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CHECK_THAT( arg, matcher ) (void)(0) + +#define REQUIRE_THAT( arg, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS + +#define INFO( msg ) (void)(0) +#define WARN( msg ) (void)(0) +#define CAPTURE( msg ) (void)(0) + +#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define METHOD_AS_TEST_CASE( method, ... ) +#define REGISTER_TEST_CASE( Function, ... ) (void)(0) +#define SECTION( ... ) +#define DYNAMIC_SECTION( ... ) +#define FAIL( ... ) (void)(0) +#define FAIL_CHECK( ... ) (void)(0) +#define SUCCEED( ... ) (void)(0) +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) + +#endif + +#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) + +// "BDD-style" convenience wrappers +#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) + +#define GIVEN( desc ) +#define WHEN( desc ) +#define AND_WHEN( desc ) +#define THEN( desc ) +#define AND_THEN( desc ) + +using Catch::Detail::Approx; + +#endif + +#endif // ! CATCH_CONFIG_IMPL_ONLY + +// start catch_reenable_warnings.h + + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(pop) +# else +# pragma clang diagnostic pop +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic pop +#endif + +// end catch_reenable_warnings.h +// end catch.hpp +#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + diff --git a/matching/include/cell_with_value.h b/matching/include/cell_with_value.h new file mode 100644 index 0000000..3548a11 --- /dev/null +++ b/matching/include/cell_with_value.h @@ -0,0 +1,141 @@ +#ifndef MATCHING_DISTANCE_CELL_WITH_VALUE_H +#define MATCHING_DISTANCE_CELL_WITH_VALUE_H + +#include <algorithm> + +#include "common_defs.h" +#include "common_util.h" +#include "dual_box.h" + +namespace md { + + enum class ValuePoint { + center, + lower_left, + lower_right, + upper_left, + upper_right + }; + + inline std::ostream& operator<<(std::ostream& os, const ValuePoint& vp) + { + switch(vp) { + case ValuePoint::upper_left : + os << "upper_left"; + break; + case ValuePoint::upper_right : + os << "upper_right"; + break; + case ValuePoint::lower_left : + os << "lower_left"; + break; + case ValuePoint::lower_right : + os << "lower_right"; + break; + case ValuePoint::center: + os << "center"; + break; + default: + os << "FORGOTTEN ValuePoint"; + } + return os; + } + + const std::vector<ValuePoint> k_all_vps = {ValuePoint::center, ValuePoint::lower_left, ValuePoint::upper_left, + ValuePoint::upper_right, ValuePoint::lower_right}; + + const std::vector<ValuePoint> k_corner_vps = {ValuePoint::lower_left, ValuePoint::upper_left, + ValuePoint::upper_right, ValuePoint::lower_right}; + + // represents a cell in the dual space with the value + // of the weighted bottleneck distance + template<class Real_> + class CellWithValue { + public: + using Real = Real_; + + CellWithValue() = default; + + CellWithValue(const CellWithValue&) = default; + + CellWithValue(CellWithValue&&) = default; + + CellWithValue& operator=(const CellWithValue& other)& = default; + + CellWithValue& operator=(CellWithValue&& other) = default; + + CellWithValue(const DualBox<Real>& b, int level) + :dual_box_(b), level_(level) { } + + DualBox<Real> dual_box() const { return dual_box_; } + + DualPoint<Real> center() const { return dual_box_.center(); } + + Real value_at(ValuePoint vp) const; + + bool has_value_at(ValuePoint vp) const; + + DualPoint<Real> value_point(ValuePoint vp) const; + + int level() const { return level_; } + + void set_value_at(ValuePoint vp, Real new_value); + + bool has_corner_value() const; + + Real stored_upper_bound() const; + + Real max_corner_value() const; + + Real min_value() const; + + bool has_max_possible_value() const { return has_max_possible_value_; } + + std::vector<CellWithValue> get_refined_cells() const; + + void set_max_possible_value(Real new_upper_bound); + + int num_values() const; + +#ifdef MD_DEBUG + long long int id { 0 }; + + static long long int max_id; + + std::vector<long long int> parent_ids; +#endif + + private: + + bool has_central_value() const { return central_value_ >= 0; } + + bool has_lower_left_value() const { return lower_left_value_ >= 0; } + + bool has_lower_right_value() const { return lower_right_value_ >= 0; } + + bool has_upper_left_value() const { return upper_left_value_ >= 0; } + + bool has_upper_right_value() const { return upper_right_value_ >= 0; } + + + DualBox<Real> dual_box_; + Real central_value_ {-1.0}; + Real lower_left_value_ {-1.0}; + Real lower_right_value_ {-1.0}; + Real upper_left_value_ {-1.0}; + Real upper_right_value_ {-1.0}; + + Real max_possible_value_ {0.0}; + + int level_ {0}; + + bool has_max_possible_value_ {false}; + }; + + template<class Real> + std::ostream& operator<<(std::ostream& os, const CellWithValue<Real>& cell); +} // namespace md + +#include "cell_with_value.hpp" + +#endif //MATCHING_DISTANCE_CELL_WITH_VALUE_H diff --git a/matching/include/cell_with_value.hpp b/matching/include/cell_with_value.hpp new file mode 100644 index 0000000..88b2569 --- /dev/null +++ b/matching/include/cell_with_value.hpp @@ -0,0 +1,224 @@ +namespace md { + +#ifdef MD_DEBUG + long long int CellWithValue<Real>::max_id = 0; +#endif + + template<class Real> + Real CellWithValue<Real>::value_at(ValuePoint vp) const + { + switch(vp) { + case ValuePoint::upper_left : + return upper_left_value_; + case ValuePoint::upper_right : + return upper_right_value_; + case ValuePoint::lower_left : + return lower_left_value_; + case ValuePoint::lower_right : + return lower_right_value_; + case ValuePoint::center: + return central_value_; + } + // to shut up compiler warning + return 1.0 / 0.0; + } + + template<class Real> + bool CellWithValue<Real>::has_value_at(ValuePoint vp) const + { + switch(vp) { + case ValuePoint::upper_left : + return upper_left_value_ >= 0; + case ValuePoint::upper_right : + return upper_right_value_ >= 0; + case ValuePoint::lower_left : + return lower_left_value_ >= 0; + case ValuePoint::lower_right : + return lower_right_value_ >= 0; + case ValuePoint::center: + return central_value_ >= 0; + } + // to shut up compiler warning + return 1.0 / 0.0; + } + + template<class Real> + DualPoint<Real> CellWithValue<Real>::value_point(md::ValuePoint vp) const + { + switch(vp) { + case ValuePoint::upper_left : + return dual_box().upper_left(); + case ValuePoint::upper_right : + return dual_box().upper_right(); + case ValuePoint::lower_left : + return dual_box().lower_left(); + case ValuePoint::lower_right : + return dual_box().lower_right(); + case ValuePoint::center: + return dual_box().center(); + } + // to shut up compiler warning + return DualPoint<Real>(); + } + + template<class Real> + bool CellWithValue<Real>::has_corner_value() const + { + return has_lower_left_value() or has_lower_right_value() or has_upper_left_value() + or has_upper_right_value(); + } + + template<class Real> + Real CellWithValue<Real>::stored_upper_bound() const + { + assert(has_max_possible_value_); + return max_possible_value_; + } + + template<class Real> + Real CellWithValue<Real>::max_corner_value() const + { + return std::max({lower_left_value_, lower_right_value_, upper_left_value_, upper_right_value_}); + } + + template<class Real> + Real CellWithValue<Real>::min_value() const + { + Real result = std::numeric_limits<Real>::max(); + for(auto vp : k_all_vps) { + if (not has_value_at(vp)) { + continue; + } + result = std::min(result, value_at(vp)); + } + return result; + } + + template<class Real> + std::vector<CellWithValue<Real>> CellWithValue<Real>::get_refined_cells() const + { + std::vector<CellWithValue<Real>> result; + result.reserve(4); + for(const auto& refined_box : dual_box_.refine()) { + + CellWithValue<Real> refined_cell(refined_box, level() + 1); + +#ifdef MD_DEBUG + refined_cell.parent_ids = parent_ids; + refined_cell.parent_ids.push_back(id); + refined_cell.id = ++max_id; +#endif + + if (refined_box.lower_left() == dual_box_.lower_left()) { + // _|_ + // H|_ + + refined_cell.set_value_at(ValuePoint::lower_left, lower_left_value_); + refined_cell.set_value_at(ValuePoint::upper_right, central_value_); + + } else if (refined_box.upper_right() == dual_box_.upper_right()) { + // _|H + // _|_ + + refined_cell.set_value_at(ValuePoint::lower_left, central_value_); + refined_cell.set_value_at(ValuePoint::upper_right, upper_right_value_); + + } else if (refined_box.lower_right() == dual_box_.lower_right()) { + // _|_ + // _|H + + refined_cell.set_value_at(ValuePoint::lower_right, lower_right_value_); + refined_cell.set_value_at(ValuePoint::upper_left, central_value_); + + } else if (refined_box.upper_left() == dual_box_.upper_left()) { + + // H|_ + // _|_ + + refined_cell.set_value_at(ValuePoint::lower_right, central_value_); + refined_cell.set_value_at(ValuePoint::upper_left, upper_left_value_); + } + result.emplace_back(refined_cell); + } + return result; + } + + template<class Real> + void CellWithValue<Real>::set_value_at(ValuePoint vp, Real new_value) + { + if (has_value_at(vp)) + spd::error("CellWithValue<Real>: trying to re-assign value!, this = {}, vp = {}", *this, vp); + + switch(vp) { + case ValuePoint::upper_left : + upper_left_value_ = new_value; + break; + case ValuePoint::upper_right : + upper_right_value_ = new_value; + break; + case ValuePoint::lower_left : + lower_left_value_ = new_value; + break; + case ValuePoint::lower_right : + lower_right_value_ = new_value; + break; + case ValuePoint::center: + central_value_ = new_value; + break; + } + } + + template<class Real> + int CellWithValue<Real>::num_values() const + { + int result = 0; + for(ValuePoint vp : k_all_vps) { + result += has_value_at(vp); + } + return result; + } + + + template<class Real> + void CellWithValue<Real>::set_max_possible_value(Real new_upper_bound) + { + assert(new_upper_bound >= central_value_); + assert(new_upper_bound >= lower_left_value_); + assert(new_upper_bound >= lower_right_value_); + assert(new_upper_bound >= upper_left_value_); + assert(new_upper_bound >= upper_right_value_); + has_max_possible_value_ = true; + max_possible_value_ = new_upper_bound; + } + + + template<class Real> + std::ostream& operator<<(std::ostream& os, const CellWithValue<Real>& cell) + { + os << "CellWithValue(box = " << cell.dual_box() << ", "; + +#ifdef MD_DEBUG + os << "id = " << cell.id; + if (not cell.parent_ids.empty()) + os << ", parent_ids = " << container_to_string(cell.parent_ids) << ", "; +#endif + + for(ValuePoint vp : k_all_vps) { + if (cell.has_value_at(vp)) { + os << "value = " << cell.value_at(vp); + os << ", at " << vp << " " << cell.value_point(vp); + } + } + + os << ", max_corner_value = "; + if (cell.has_max_possible_value()) { + os << cell.stored_upper_bound(); + } else { + os << "-"; + } + + os << ", level = " << cell.level() << ")"; + return os; + } + +} // namespace md diff --git a/matching/include/common_defs.h b/matching/include/common_defs.h new file mode 100644 index 0000000..8d01325 --- /dev/null +++ b/matching/include/common_defs.h @@ -0,0 +1,10 @@ +#ifndef MATCHING_DISTANCE_DEF_DEBUG_H +#define MATCHING_DISTANCE_DEF_DEBUG_H + +//#define MD_EXPERIMENTAL_TIMING +//#define MD_PRINT_HEAT_MAP +//#define MD_DEBUG +//#define MD_DO_CHECKS +//#define MD_DO_FULL_CHECK + +#endif //MATCHING_DISTANCE_DEF_DEBUG_H diff --git a/matching/include/common_util.h b/matching/include/common_util.h new file mode 100644 index 0000000..778536f --- /dev/null +++ b/matching/include/common_util.h @@ -0,0 +1,188 @@ +#ifndef MATCHING_DISTANCE_COMMON_UTIL_H +#define MATCHING_DISTANCE_COMMON_UTIL_H + +#include <cassert> +#include <vector> +#include <utility> +#include <cmath> +#include <ostream> +#include <sstream> +#include <string> +#include <map> +#include <functional> + +#include <spdlog/spdlog.h> +#include <spdlog/fmt/ostr.h> + +namespace spd = spdlog; + +#include "common_defs.h" +#include "phat/helpers/misc.h" + +namespace md { + + using Index = phat::index; + using IndexVec = std::vector<Index>; + + //static constexpr Real pi = M_PI; + + using Column = std::vector<Index>; + + template<class Real> + struct Point { + Real x; + Real y; + + Point(Real x = 0, Real y = 0) + :x(x), y(y) { } + + inline Real norm() const { return sqrt(x * x + y * y); } + + inline void normalize() + { + Real nor = norm(); + x /= nor; + y /= nor; + } + + inline void translate(Real a) + { + x += a; + y += a; + } + + inline bool operator==(const Point& v) const + { + return this->x == v.x && this->y == v.y; + } + + // compare both coordinates, as needed in persistence + // do not overload operator<, requirements are not satisfied + inline bool is_less(const Point& other, bool strict = false) const + { + if (x <= other.x and y <= other.y) { + if (strict) { + return x != other.x or y != other.y; + } + else { + return true; + } + } + return false; + } + }; + + + template<class Real> + using PointVec = std::vector<Point<Real>>; + + template<class Real> + Point<Real> operator+(const Point<Real>& u, const Point<Real>& v); + + template<class Real> + Point<Real> operator-(const Point<Real>& u, const Point<Real>& v); + + + template<class Real> + Point<Real> least_upper_bound(const Point<Real>& u, const Point<Real>& v); + + template<class Real> + Point<Real> greatest_lower_bound(const Point<Real>& u, const Point<Real>& v); + + template<class Real> + Point<Real> max_point(); + + template<class Real> + Point<Real> min_point(); + + template<class Real> + std::ostream& operator<<(std::ostream& ostr, const Point<Real>& vec); + + template<class Real> + using DiagramPoint = std::pair<Real, Real>; + + template<class Real> + using Diagram = std::vector<DiagramPoint<Real>>; + + + // to keep diagrams in all dimensions + // TODO: store in Hera format? + template<class Real> + class DiagramKeeper { + public: + + DiagramKeeper() { }; + + void add_point(int dim, Real birth, Real death); + + Diagram<Real> get_diagram(int dim) const; + + void clear() { data_.clear(); } + + private: + std::map<int, Diagram<Real>> data_; + }; + + template<typename C> + std::string container_to_string(const C& cont) + { + std::stringstream ss; + ss << "["; + int i = 0; + for (const auto& x : cont) { + i++; + ss << x; + if (i != (int) cont.size()) + ss << ", "; + } + ss << "]"; + return ss.str(); + } + + // return true, if s is empty or starts with # (commented out line) + // whitespaces in the beginning of s are ignored + inline bool ignore_line(const std::string& s) + { + for(auto c : s) { + if (isspace(c)) + continue; + return (c == '#'); + } + return true; + } + + + // split string by delimeter + template<typename Out> + void split_by_delim(const std::string &s, char delim, Out result) { + std::stringstream ss(s); + std::string item; + while (std::getline(ss, item, delim)) { + *(result++) = item; + } + } + + inline std::vector<std::string> split_by_delim(const std::string &s, char delim) { + std::vector<std::string> elems; + split_by_delim(s, delim, std::back_inserter(elems)); + return elems; + } +} + +namespace std { + template<class Real> + struct hash<md::Point<Real>> + { + std::size_t operator()(const md::Point<Real>& p) const + { + auto hx = std::hash<decltype(p.x)>()(p.x); + auto hy = std::hash<decltype(p.y)>()(p.y); + return hx ^ (hy << 1); + } + }; +}; + +#include "common_util.hpp" + + +#endif //MATCHING_DISTANCE_COMMON_UTIL_H diff --git a/matching/include/common_util.hpp b/matching/include/common_util.hpp new file mode 100644 index 0000000..76d97af --- /dev/null +++ b/matching/include/common_util.hpp @@ -0,0 +1,96 @@ +#include <vector> +#include <utility> +#include <cmath> +#include <ostream> +#include <limits> +#include <algorithm> + +#include <common_util.h> + +#include "spdlog/spdlog.h" +#include "spdlog/fmt/ostr.h" + +namespace md { + + template<class Real> + Point<Real> operator+(const Point<Real>& u, const Point<Real>& v) + { + return Point<Real>(u.x + v.x, u.y + v.y); + } + + template<class Real> + Point<Real> operator-(const Point<Real>& u, const Point<Real>& v) + { + return Point<Real>(u.x - v.x, u.y - v.y); + } + + template<class Real> + Point<Real> least_upper_bound(const Point<Real>& u, const Point<Real>& v) + { + return Point<Real>(std::max(u.x, v.x), std::max(u.y, v.y)); + } + + template<class Real> + Point<Real> greatest_lower_bound(const Point<Real>& u, const Point<Real>& v) + { + return Point<Real>(std::min(u.x, v.x), std::min(u.y, v.y)); + } + + template<class Real> + Point<Real> max_point() + { + return Point<Real>(std::numeric_limits<Real>::max(), std::numeric_limits<Real>::min()); + } + + template<class Real> + Point<Real> min_point() + { + return Point<Real>(-std::numeric_limits<Real>::max(), -std::numeric_limits<Real>::min()); + } + + template<class Real> + std::ostream& operator<<(std::ostream& ostr, const Point<Real>& vec) + { + ostr << "(" << vec.x << ", " << vec.y << ")"; + return ostr; + } + + template<class Real> + Real l_infty_norm(const Point<Real>& v) + { + return std::max(std::abs(v.x), std::abs(v.y)); + } + + template<class Real> + Real l_2_norm(const Point<Real>& v) + { + return v.norm(); + } + + template<class Real> + Real l_2_dist(const Point<Real>& x, const Point<Real>& y) + { + return l_2_norm(x - y); + } + + template<class Real> + Real l_infty_dist(const Point<Real>& x, const Point<Real>& y) + { + return l_infty_norm(x - y); + } + + template<class Real> + void DiagramKeeper<Real>::add_point(int dim, Real birth, Real death) + { + data_[dim].emplace_back(birth, death); + } + + template<class Real> + Diagram<Real> DiagramKeeper<Real>::get_diagram(int dim) const + { + if (data_.count(dim) == 1) + return data_.at(dim); + else + return Diagram<Real>(); + } +} diff --git a/matching/include/dual_box.h b/matching/include/dual_box.h new file mode 100644 index 0000000..0e4f4d5 --- /dev/null +++ b/matching/include/dual_box.h @@ -0,0 +1,83 @@ +#ifndef MATCHING_DISTANCE_DUAL_BOX_H +#define MATCHING_DISTANCE_DUAL_BOX_H + +#include <ostream> +#include <limits> +#include <vector> +#include <random> + +#include "spdlog/spdlog.h" +#include "spdlog/fmt/ostr.h" + + +#include "common_util.h" +#include "dual_point.h" + +namespace md { + + + template<class Real> + class DualBox { + public: + + DualBox(DualPoint<Real> ll, DualPoint<Real> ur); + + DualBox() = default; + DualBox(const DualBox&) = default; + DualBox(DualBox&&) = default; + + DualBox& operator=(const DualBox& other) & = default; + DualBox& operator=(DualBox&& other) = default; + + + DualPoint<Real> center() const { return midpoint(lower_left_, upper_right_); } + DualPoint<Real> lower_left() const { return lower_left_; } + DualPoint<Real> upper_right() const { return upper_right_; } + + DualPoint<Real> lower_right() const; + DualPoint<Real> upper_left() const; + + AxisType axis_type() const { return lower_left_.axis_type(); } + AngleType angle_type() const { return lower_left_.angle_type(); } + + Real mu_min() const { return lower_left_.mu(); } + Real mu_max() const { return upper_right_.mu(); } + Real lambda_min() const { return lower_left_.lambda(); } + Real lambda_max() const { return upper_right_.lambda(); } + + // return true, if all lines in dual_box are flat + bool is_flat() const { return upper_right_.is_flat(); } + bool is_steep() const { return lower_left_.is_steep(); } + + std::vector<DualBox> refine() const; + std::vector<DualPoint<Real>> corners() const; + std::vector<DualPoint<Real>> critical_points(const Point<Real>& p) const; + // sample n points from the box uniformly; for tests + std::vector<DualPoint<Real>> random_points(int n) const; + + // return 2 dual points at the boundary + // where push changes from horizontal to vertical + std::vector<DualPoint<Real>> push_change_points(const Point<Real>& p) const; + + // check that a has same sign, angles are all flat or all steep + bool sanity_check() const; + bool contains(const DualPoint<Real>& dp) const; + + bool operator==(const DualBox& other) const; + + private: + DualPoint<Real> lower_left_; + DualPoint<Real> upper_right_; + }; + + template<class Real> + std::ostream& operator<<(std::ostream& os, const DualBox<Real>& db) + { + os << "DualBox(" << db.lower_left() << ", " << db.upper_right() << ")"; + return os; + } +} + +#include "dual_box.hpp" + +#endif //MATCHING_DISTANCE_DUAL_BOX_H diff --git a/matching/include/dual_box.hpp b/matching/include/dual_box.hpp new file mode 100644 index 0000000..85f7f27 --- /dev/null +++ b/matching/include/dual_box.hpp @@ -0,0 +1,190 @@ +namespace md { + + template<class Real> + DualBox<Real>::DualBox(DualPoint<Real> ll, DualPoint<Real> ur) + :lower_left_(ll), upper_right_(ur) + { + } + + template<class Real> + std::vector<DualPoint<Real>> DualBox<Real>::corners() const + { + return {lower_left_, + DualPoint<Real>(axis_type(), angle_type(), lower_left_.lambda(), upper_right_.mu()), + upper_right_, + DualPoint<Real>(axis_type(), angle_type(), upper_right_.lambda(), lower_left_.mu())}; + } + + template<class Real> + std::vector<DualPoint<Real>> DualBox<Real>::push_change_points(const Point<Real>& p) const + { + std::vector<DualPoint<Real>> result; + result.reserve(2); + + bool is_y_type = lower_left_.is_y_type(); + bool is_flat = lower_left_.is_flat(); + + auto mu_from_lambda = [p, is_y_type, is_flat](Real lambda) { + bool is_x_type = not is_y_type, is_steep = not is_flat; + if (is_y_type && is_flat) { + return p.y - lambda * p.x; + } else if (is_y_type && is_steep) { + return p.y - p.x / lambda; + } else if (is_x_type && is_flat) { + return p.x - p.y / lambda; + } else if (is_x_type && is_steep) { + return p.x - lambda * p.y; + } + // to shut up compiler warning + return static_cast<Real>(1.0 / 0.0); + }; + + auto lambda_from_mu = [p, is_y_type, is_flat](Real mu) { + bool is_x_type = not is_y_type, is_steep = not is_flat; + if (is_y_type && is_flat) { + return (p.y - mu) / p.x; + } else if (is_y_type && is_steep) { + return p.x / (p.y - mu); + } else if (is_x_type && is_flat) { + return p.y / (p.x - mu); + } else if (is_x_type && is_steep) { + return (p.x - mu) / p.y; + } + // to shut up compiler warning + return static_cast<Real>(1.0 / 0.0); + }; + + // all inequalities below are strict: equality means it is a corner + // && critical_points() returns corners anyway + + Real mu_intersect_min = mu_from_lambda(lambda_min()); + + if (mu_min() < mu_intersect_min && mu_intersect_min < mu_max()) + result.emplace_back(axis_type(), angle_type(), lambda_min(), mu_intersect_min); + + Real mu_intersect_max = mu_from_lambda(lambda_max()); + + if (mu_max() < mu_intersect_max && mu_intersect_max < mu_max()) + result.emplace_back(axis_type(), angle_type(), lambda_max(), mu_intersect_max); + + Real lambda_intersect_min = lambda_from_mu(mu_min()); + + if (lambda_min() < lambda_intersect_min && lambda_intersect_min < lambda_max()) + result.emplace_back(axis_type(), angle_type(), lambda_intersect_min, mu_min()); + + Real lambda_intersect_max = lambda_from_mu(mu_max()); + if (lambda_min() < lambda_intersect_max && lambda_intersect_max < lambda_max()) + result.emplace_back(axis_type(), angle_type(), lambda_intersect_max, mu_max()); + + assert(result.size() <= 2); + + if (result.size() > 2) { + fmt::print("Error in push_change_points, p = {}, dual_box = {}, result = {}\n", p, *this, + container_to_string(result)); + throw std::runtime_error("push_change_points returned more than 2 points"); + } + + return result; + } + + template<class Real> + std::vector<DualPoint<Real>> DualBox<Real>::critical_points(const Point<Real>& /*p*/) const + { + // maximal difference is attained at corners + return corners(); +// std::vector<DualPoint<Real>> result; +// result.reserve(6); +// for(auto dp : corners()) result.push_back(dp); +// for(auto dp : push_change_points(p)) result.push_back(dp); +// return result; + } + + template<class Real> + std::vector<DualPoint<Real>> DualBox<Real>::random_points(int n) const + { + assert(n >= 0); + std::mt19937_64 gen(1); + std::vector<DualPoint<Real>> result; + result.reserve(n); + std::uniform_real_distribution<Real> mu_distr(mu_min(), mu_max()); + std::uniform_real_distribution<Real> lambda_distr(lambda_min(), lambda_max()); + for(int i = 0; i < n; ++i) { + result.emplace_back(axis_type(), angle_type(), lambda_distr(gen), mu_distr(gen)); + } + return result; + } + + template<class Real> + bool DualBox<Real>::sanity_check() const + { + lower_left_.sanity_check(); + upper_right_.sanity_check(); + + if (lower_left_.angle_type() != upper_right_.angle_type()) + throw std::runtime_error("angle types differ"); + + if (lower_left_.axis_type() != upper_right_.axis_type()) + throw std::runtime_error("axis types differ"); + + if (lower_left_.lambda() >= upper_right_.lambda()) + throw std::runtime_error("lambda of lower_left_ greater than lambda of upper_right "); + + if (lower_left_.mu() >= upper_right_.mu()) + throw std::runtime_error("mu of lower_left_ greater than mu of upper_right "); + + return true; + } + + template<class Real> + std::vector<DualBox<Real>> DualBox<Real>::refine() const + { + std::vector<DualBox<Real>> result; + + result.reserve(4); + + Real lambda_middle = (lower_left().lambda() + upper_right().lambda()) / 2.0; + Real mu_middle = (lower_left().mu() + upper_right().mu()) / 2.0; + + DualPoint<Real> refinement_center(axis_type(), angle_type(), lambda_middle, mu_middle); + + result.emplace_back(lower_left_, refinement_center); + + result.emplace_back(DualPoint<Real>(axis_type(), angle_type(), lambda_middle, mu_min()), + DualPoint<Real>(axis_type(), angle_type(), lambda_max(), mu_middle)); + + result.emplace_back(refinement_center, upper_right_); + + result.emplace_back(DualPoint<Real>(axis_type(), angle_type(), lambda_min(), mu_middle), + DualPoint<Real>(axis_type(), angle_type(), lambda_middle, mu_max())); + return result; + } + + template<class Real> + bool DualBox<Real>::operator==(const DualBox& other) const + { + return lower_left() == other.lower_left() && + upper_right() == other.upper_right(); + } + + template<class Real> + bool DualBox<Real>::contains(const DualPoint<Real>& dp) const + { + return dp.angle_type() == angle_type() && dp.axis_type() == axis_type() && + mu_max() >= dp.mu() && + mu_min() <= dp.mu() && + lambda_min() <= dp.lambda() && + lambda_max() >= dp.lambda(); + } + + template<class Real> + DualPoint<Real> DualBox<Real>::lower_right() const + { + return DualPoint<Real>(lower_left_.axis_type(), lower_left_.angle_type(), lambda_max(), mu_min()); + } + + template<class Real> + DualPoint<Real> DualBox<Real>::upper_left() const + { + return DualPoint<Real>(lower_left_.axis_type(), lower_left_.angle_type(), lambda_min(), mu_max()); + } +} diff --git a/matching/include/dual_point.h b/matching/include/dual_point.h new file mode 100644 index 0000000..8438860 --- /dev/null +++ b/matching/include/dual_point.h @@ -0,0 +1,107 @@ +#ifndef MATCHING_DISTANCE_DUAL_POINT_H +#define MATCHING_DISTANCE_DUAL_POINT_H + +#include <vector> +#include <ostream> +#include <tuple> + +#include "common_util.h" +#include "box.h" + +namespace md { + + enum class AxisType { + x_type, y_type + }; + enum class AngleType { + flat, steep + }; + + // class has two flags of AxisType and AngleType. + // ATTENTION. == operator is not overloaded, + // so, e.g., line y = x has 4 different non-equal representation. + // we are unlikely to ever need this, because 4 cases are + // always treated separately. + template<class Real_> + class DualPoint { + public: + using Real = Real_; + + DualPoint() = default; + + DualPoint(const DualPoint&) = default; + + DualPoint(DualPoint&&) = default; + + DualPoint& operator=(const DualPoint& other)& = default; + + DualPoint& operator=(DualPoint&& other) = default; + + DualPoint(AxisType axis_type, AngleType angle_type, Real lambda, Real mu); + + Real lambda() const { return lambda_; } + + Real mu() const { return mu_; } + + // angle between line and x-axis + Real gamma() const; + + bool is_steep() const { return angle_type_ == AngleType::steep; } + + bool is_flat() const { return angle_type_ == AngleType::flat; } + + bool is_x_type() const { return axis_type_ == AxisType::x_type; } + + bool is_y_type() const { return axis_type_ == AxisType::y_type; } + + bool operator<(const DualPoint& rhs) const; + + AxisType axis_type() const { return axis_type_; } + AngleType angle_type() const { return angle_type_; } + + // throw exception, if fields are invalid + // return true otherwise + bool sanity_check() const; + + Real weighted_push(Point<Real> p) const; + Point<Real> push(Point<Real> p) const; + + bool is_horizontal() const; + bool is_vertical() const; + + bool goes_below(Point<Real> p) const; + bool goes_above(Point<Real> p) const; + + bool contains(Point<Real> p) const; + + Real x_slope() const; + Real y_slope() const; + + Real x_intercept() const; + Real y_intercept() const; + + Real x_from_y(Real y) const; + Real y_from_x(Real x) const; + + Real weight() const; + + bool operator==(const DualPoint& other) const; + + private: + AxisType axis_type_ {AxisType::y_type}; + AngleType angle_type_ {AngleType::flat}; + // both initial values are invalid: lambda must be between 0 and 1 + Real lambda_ {-1.0}; + Real mu_ {-1.0}; + }; + + template<class Real> + std::ostream& operator<<(std::ostream& os, const DualPoint<Real>& dp); + + template<class Real> + DualPoint<Real> midpoint(DualPoint<Real> x, DualPoint<Real> y); +}; + +#include "dual_point.hpp" + +#endif //MATCHING_DISTANCE_DUAL_POINT_H diff --git a/matching/include/dual_point.hpp b/matching/include/dual_point.hpp new file mode 100644 index 0000000..04e25f2 --- /dev/null +++ b/matching/include/dual_point.hpp @@ -0,0 +1,299 @@ +namespace md { + + inline std::ostream& operator<<(std::ostream& os, const AxisType& at) + { + if (at == AxisType::x_type) + os << "x-type"; + else + os << "y-type"; + return os; + } + + inline std::ostream& operator<<(std::ostream& os, const AngleType& at) + { + if (at == AngleType::flat) + os << "flat"; + else + os << "steep"; + return os; + } + + template<class Real> + std::ostream& operator<<(std::ostream& os, const DualPoint<Real>& dp) + { + os << "Line(" << dp.axis_type() << ", "; + os << dp.angle_type() << ", "; + os << dp.lambda() << ", "; + os << dp.mu() << ", equation: "; + if (not dp.is_vertical()) { + os << "y = " << dp.y_slope() << " x + " << dp.y_intercept(); + } else { + os << "x = " << dp.x_intercept(); + } + os << " )"; + return os; + } + + template<class Real> + bool DualPoint<Real>::operator<(const DualPoint<Real>& rhs) const + { + return std::tie(axis_type_, angle_type_, lambda_, mu_) + < std::tie(rhs.axis_type_, rhs.angle_type_, rhs.lambda_, rhs.mu_); + } + + template<class Real> + DualPoint<Real>::DualPoint(AxisType axis_type, AngleType angle_type, Real lambda, Real mu) + : + axis_type_(axis_type), + angle_type_(angle_type), + lambda_(lambda), + mu_(mu) + { + assert(sanity_check()); + } + + template<class Real> + bool DualPoint<Real>::sanity_check() const + { + if (lambda_ < 0.0) + throw std::runtime_error("Invalid line, negative lambda"); + if (lambda_ > 1.0) + throw std::runtime_error("Invalid line, lambda > 1"); + if (mu_ < 0.0) + throw std::runtime_error("Invalid line, negative mu"); + return true; + } + + template<class Real> + Real DualPoint<Real>::gamma() const + { + if (is_steep()) + return atan(Real(1.0) / lambda_); + else + return atan(lambda_); + } + + template<class Real> + DualPoint<Real> midpoint(DualPoint<Real> x, DualPoint<Real> y) + { + assert(x.angle_type() == y.angle_type() and x.axis_type() == y.axis_type()); + Real lambda_mid = (x.lambda() + y.lambda()) / 2; + Real mu_mid = (x.mu() + y.mu()) / 2; + return DualPoint<Real>(x.axis_type(), x.angle_type(), lambda_mid, mu_mid); + + } + + // return k in the line equation y = kx + b + template<class Real> + Real DualPoint<Real>::y_slope() const + { + if (is_flat()) + return lambda(); + else + return Real(1.0) / lambda(); + } + + // return k in the line equation x = ky + b + template<class Real> + Real DualPoint<Real>::x_slope() const + { + if (is_flat()) + return Real(1.0) / lambda(); + else + return lambda(); + } + + // return b in the line equation y = kx + b + template<class Real> + Real DualPoint<Real>::y_intercept() const + { + if (is_y_type()) { + return mu(); + } else { + // x = x_slope * y + mu = x_slope * (y + mu / x_slope) + // x-intercept is -mu/x_slope = -mu * y_slope + return -mu() * y_slope(); + } + } + + // return k in the line equation x = ky + b + template<class Real> + Real DualPoint<Real>::x_intercept() const + { + if (is_x_type()) { + return mu(); + } else { + // y = y_slope * x + mu = y_slope (x + mu / y_slope) + // x_intercept is -mu/y_slope = -mu * x_slope + return -mu() * x_slope(); + } + } + + template<class Real> + Real DualPoint<Real>::x_from_y(Real y) const + { + if (is_horizontal()) + throw std::runtime_error("x_from_y called on horizontal line"); + else + return x_slope() * y + x_intercept(); + } + + template<class Real> + Real DualPoint<Real>::y_from_x(Real x) const + { + if (is_vertical()) + throw std::runtime_error("x_from_y called on horizontal line"); + else + return y_slope() * x + y_intercept(); + } + + template<class Real> + bool DualPoint<Real>::is_horizontal() const + { + return is_flat() and lambda() == 0; + } + + template<class Real> + bool DualPoint<Real>::is_vertical() const + { + return is_steep() and lambda() == 0; + } + + template<class Real> + bool DualPoint<Real>::contains(Point<Real> p) const + { + if (is_vertical()) + return p.x == x_from_y(p.y); + else + return p.y == y_from_x(p.x); + } + + template<class Real> + bool DualPoint<Real>::goes_below(Point<Real> p) const + { + if (is_vertical()) + return p.x <= x_from_y(p.y); + else + return p.y >= y_from_x(p.x); + } + + template<class Real> + bool DualPoint<Real>::goes_above(Point<Real> p) const + { + if (is_vertical()) + return p.x >= x_from_y(p.y); + else + return p.y <= y_from_x(p.x); + } + + template<class Real> + Point<Real> DualPoint<Real>::push(Point<Real> p) const + { + Point<Real> result; + // if line is below p, we push horizontally + bool horizontal_push = goes_below(p); + if (is_x_type()) { + if (is_flat()) { + if (horizontal_push) { + result.x = p.y / lambda() + mu(); + result.y = p.y; + } else { + // vertical push + result.x = p.x; + result.y = lambda() * (p.x - mu()); + } + } else { + // steep + if (horizontal_push) { + result.x = lambda() * p.y + mu(); + result.y = p.y; + } else { + // vertical push + result.x = p.x; + result.y = (p.x - mu()) / lambda(); + } + } + } else { + // y-type + if (is_flat()) { + if (horizontal_push) { + result.x = (p.y - mu()) / lambda(); + result.y = p.y; + } else { + // vertical push + result.x = p.x; + result.y = lambda() * p.x + mu(); + } + } else { + // steep + if (horizontal_push) { + result.x = (p.y - mu()) * lambda(); + result.y = p.y; + } else { + // vertical push + result.x = p.x; + result.y = p.x / lambda() + mu(); + } + } + } + return result; + } + + template<class Real> + Real DualPoint<Real>::weighted_push(Point<Real> p) const + { + // if line is below p, we push horizontally + bool horizontal_push = goes_below(p); + if (is_x_type()) { + if (is_flat()) { + if (horizontal_push) { + return p.y; + } else { + // vertical push + return lambda() * (p.x - mu()); + } + } else { + // steep + if (horizontal_push) { + return lambda() * p.y; + } else { + // vertical push + return (p.x - mu()); + } + } + } else { + // y-type + if (is_flat()) { + if (horizontal_push) { + return p.y - mu(); + } else { + // vertical push + return lambda() * p.x; + } + } else { + // steep + if (horizontal_push) { + return lambda() * (p.y - mu()); + } else { + // vertical push + return p.x; + } + } + } + } + + template<class Real> + bool DualPoint<Real>::operator==(const DualPoint<Real>& other) const + { + return axis_type() == other.axis_type() and + angle_type() == other.angle_type() and + mu() == other.mu() and + lambda() == other.lambda(); + } + + template<class Real> + Real DualPoint<Real>::weight() const + { + return lambda_ / sqrt(1 + lambda_ * lambda_); + } +} // namespace md diff --git a/matching/include/matching_distance.h b/matching/include/matching_distance.h new file mode 100644 index 0000000..e1679dc --- /dev/null +++ b/matching/include/matching_distance.h @@ -0,0 +1,290 @@ +#pragma once + +#include <vector> +#include <limits> +#include <utility> +#include <ostream> +#include <chrono> +#include <tuple> +#include <algorithm> + + +#include "common_defs.h" +#include "cell_with_value.h" +#include "box.h" +#include "dual_point.h" +#include "dual_box.h" +#include "persistence_module.h" +#include "bifiltration.h" +#include "bottleneck.h" + +namespace md { + +#ifdef MD_PRINT_HEAT_MAP + template<class Real> + using HeatMap = std::map<DualPoint<Real>, Real>; + + template<class Real> + using HeatMaps = std::map<int, HeatMap<Real>>; +#endif + + enum class BoundStrategy { + bruteforce, + local_dual_bound, + local_dual_bound_refined, + local_dual_bound_for_each_point, + local_combined + }; + + enum class TraverseStrategy { + depth_first, + breadth_first, + breadth_first_value, + upper_bound + }; + + inline std::ostream& operator<<(std::ostream& os, const BoundStrategy& s) + { + switch(s) { + case BoundStrategy::bruteforce : + os << "bruteforce"; + break; + case BoundStrategy::local_dual_bound : + os << "local_grob"; + break; + case BoundStrategy::local_combined : + os << "local_combined"; + break; + case BoundStrategy::local_dual_bound_refined : + os << "local_refined"; + break; + case BoundStrategy::local_dual_bound_for_each_point : + os << "local_for_each_point"; + break; + default: + os << "FORGOTTEN BOUND STRATEGY"; + } + return os; + } + + inline std::ostream& operator<<(std::ostream& os, const TraverseStrategy& s) + { + switch(s) { + case TraverseStrategy::depth_first : + os << "DFS"; + break; + case TraverseStrategy::breadth_first : + os << "BFS"; + break; + case TraverseStrategy::breadth_first_value : + os << "BFS-VAL"; + break; + case TraverseStrategy::upper_bound : + os << "UB"; + break; + default: + os << "FORGOTTEN TRAVERSE STRATEGY"; + } + return os; + } + + inline std::istream& operator>>(std::istream& is, TraverseStrategy& s) + { + std::string ss; + is >> ss; + if (ss == "DFS") { + s = TraverseStrategy::depth_first; + } else if (ss == "BFS") { + s = TraverseStrategy::breadth_first; + } else if (ss == "BFS-VAL") { + s = TraverseStrategy::breadth_first_value; + } else if (ss == "UB") { + s = TraverseStrategy::upper_bound; + } else { + throw std::runtime_error("UNKNOWN TRAVERSE STRATEGY"); + } + return is; + } + + + inline std::istream& operator>>(std::istream& is, BoundStrategy& s) + { + std::string ss; + is >> ss; + if (ss == "bruteforce") { + s = BoundStrategy::bruteforce; + } else if (ss == "local_grob") { + s = BoundStrategy::local_dual_bound; + } else if (ss == "local_combined") { + s = BoundStrategy::local_combined; + } else if (ss == "local_refined") { + s = BoundStrategy::local_dual_bound_refined; + } else if (ss == "local_for_each_point") { + s = BoundStrategy::local_dual_bound_for_each_point; + } else { + throw std::runtime_error("UNKNOWN BOUND STRATEGY"); + } + return is; + } + + inline BoundStrategy bs_from_string(std::string s) + { + std::stringstream ss(s); + BoundStrategy result; + ss >> result; + return result; + } + + inline TraverseStrategy ts_from_string(std::string s) + { + std::stringstream ss(s); + TraverseStrategy result; + ss >> result; + return result; + } + + template<class Real> + struct CalculationParams { + static constexpr int ALL_DIMENSIONS = -1; + + Real hera_epsilon {0.001}; // relative error in hera call + Real delta {0.1}; // relative error for matching distance + int max_depth {8}; // maximal number of refinenemnts + int initialization_depth {2}; + int dim {0}; // in which dim to calculate the distance; use ALL_DIMENSIONS to get max over all dims + BoundStrategy bound_strategy {BoundStrategy::local_combined}; + TraverseStrategy traverse_strategy {TraverseStrategy::breadth_first}; + bool tolerate_max_iter_exceeded {false}; + Real actual_error {std::numeric_limits<Real>::max()}; + int actual_max_depth {0}; + int n_hera_calls {0}; // for experiments only; is set in matching_distance function, input value is ignored + + // stop looping over points immediately, if current point's displacement is too large + // to prune the cell + // if true, cells are pruned immediately, and bounds may increase + // (just return something large enough to not prune the cell) + bool stop_asap { true }; + + // print statistics on each quad-tree level + bool print_stats { false }; + +#ifdef MD_PRINT_HEAT_MAP + HeatMaps<Real> heat_maps; +#endif + }; + + + template<class Real_, class DiagramProvider> + class DistanceCalculator { + + using Real = Real_; + using CellValueVector = std::vector<CellWithValue<Real>>; + + public: + DistanceCalculator(const DiagramProvider& a, + const DiagramProvider& b, + CalculationParams<Real>& params); + + Real distance(); + + int get_hera_calls_number() const; + +#ifndef MD_TEST_CODE + private: +#endif + + DiagramProvider module_a_; + DiagramProvider module_b_; + + CalculationParams<Real>& params_; + + int n_hera_calls_; + std::map<int, int> n_hera_calls_per_level_; + Real distance_; + + // if calculate_on_intermediate, then weighted distance + // will be calculated on centers of each grid in between + CellValueVector get_refined_grid(int init_depth, bool calculate_on_intermediate, bool calculate_on_last = true); + + CellValueVector get_initial_dual_grid(Real& lower_bound); + +#ifdef MD_PRINT_HEAT_MAP + void heatmap_in_dimension(int dim, int depth); +#endif + + Real get_max_x(int module) const; + + Real get_max_y(int module) const; + + void set_cell_central_value(CellWithValue<Real>& dual_cell); + + Real get_distance(); + + Real get_distance_pq(); + + Real get_max_possible_value(const CellWithValue<Real>* first_cell_ptr, int n_cells); + + Real get_upper_bound(const CellWithValue<Real>& dual_cell, Real good_enough_upper_bound) const; + + Real get_single_dgm_bound(const CellWithValue<Real>& dual_cell, ValuePoint vp, int module, + Real good_enough_value) const; + + // this bound depends only on dual box + Real get_local_dual_bound(int module, const DualBox<Real>& dual_box) const; + + Real get_local_dual_bound(const DualBox<Real>& dual_box) const; + + // this bound depends only on dual box, is more accurate + Real get_local_refined_bound(int module, const DualBox<Real>& dual_box) const; + + Real get_local_refined_bound(const DualBox<Real>& dual_box) const; + + Real get_good_enough_upper_bound(Real lower_bound) const; + + Real get_max_displacement_single_point(const CellWithValue<Real>& dual_cell, ValuePoint value_point, + const Point<Real>& p) const; + + void check_upper_bound(const CellWithValue<Real>& dual_cell) const; + + Real distance_on_line(DualPoint<Real> line); + Real distance_on_line_const(DualPoint<Real> line) const; + + Real current_error(Real lower_bound, Real upper_bound); + }; + + template<class Real> + Real matching_distance(const Bifiltration<Real>& bif_a, const Bifiltration<Real>& bif_b, + CalculationParams<Real>& params); + + template<class Real> + Real matching_distance(const ModulePresentation<Real>& mod_a, const ModulePresentation<Real>& mod_b, + CalculationParams<Real>& params); + + // for upper bound experiment + struct UbExperimentRecord { + double error; + double lower_bound; + double upper_bound; + CellWithValue<double> cell; + long long int time; + long long int n_hera_calls; + }; + + inline std::ostream& operator<<(std::ostream& os, const UbExperimentRecord& r) + { + os << r.time << "\t" << r.n_hera_calls << "\t" << r.error << "\t" << r.lower_bound << "\t" << r.upper_bound; + return os; + } + + + template<class K, class V> + void print_map(const std::map<K, V>& dic) + { + for(const auto kv : dic) { + fmt::print("{} -> {}\n", kv.first, kv.second); + } + } + +} // namespace md + +#include "matching_distance.hpp" diff --git a/matching/include/matching_distance.hpp b/matching/include/matching_distance.hpp new file mode 100644 index 0000000..7cff073 --- /dev/null +++ b/matching/include/matching_distance.hpp @@ -0,0 +1,812 @@ +namespace md { + + template<class R, class T> + void DistanceCalculator<R, T>::check_upper_bound(const CellWithValue<R>& dual_cell) const + { + spd::debug("Enter check_get_max_delta_on_cell"); + const int n_samples_lambda = 100; + const int n_samples_mu = 100; + DualBox<R> db = dual_cell.dual_box(); + R min_lambda = db.lambda_min(); + R max_lambda = db.lambda_max(); + R min_mu = db.mu_min(); + R max_mu = db.mu_max(); + + R h_lambda = (max_lambda - min_lambda) / n_samples_lambda; + R h_mu = (max_mu - min_mu) / n_samples_mu; + for(int i = 1; i < n_samples_lambda; ++i) { + for(int j = 1; j < n_samples_mu; ++j) { + R lambda = min_lambda + i * h_lambda; + R mu = min_mu + j * h_mu; + DualPoint<R> l(db.axis_type(), db.angle_type(), lambda, mu); + R other_result = distance_on_line_const(l); + R diff = fabs(dual_cell.stored_upper_bound() - other_result); + if (other_result > dual_cell.stored_upper_bound()) { + spd::error( + "in check_upper_bound, upper_bound = {}, other_result = {}, diff = {}\ndual_cell = {}", + dual_cell.stored_upper_bound(), other_result, diff, dual_cell); + throw std::runtime_error("Wrong delta estimate"); + } + } + } + spd::debug("Exit check_get_max_delta_on_cell"); + } + + // for all lines l, l' inside dual box, + // find the upper bound on the difference of weighted pushes of p + template<class R, class T> + R + DistanceCalculator<R, T>::get_max_displacement_single_point(const CellWithValue<R>& dual_cell, ValuePoint vp, + const Point<R>& p) const + { + assert(p.x >= 0 && p.y >= 0); + +#ifdef MD_DEBUG + std::vector<long long int> debug_ids = {3, 13, 54, 218, 350, 382, 484, 795, 2040, 8415, 44076}; + bool debug = false; // std::find(debug_ids.begin(), debug_ids.end(), dual_cell.id) != debug_ids.end(); +#endif + DualPoint<R> line = dual_cell.value_point(vp); + const R base_value = line.weighted_push(p); + + spd::debug("Enter get_max_displacement_single_point, p = {},\ndual_cell = {},\nline = {}, base_value = {}\n", p, + dual_cell, line, base_value); + + R result = 0.0; + for(DualPoint<R> dp : dual_cell.dual_box().critical_points(p)) { + R dp_value = dp.weighted_push(p); + spd::debug( + "In get_max_displacement_single_point, p = {}, critical dp = {},\ndp_value = {}, diff = {},\ndual_cell = {}\n", + p, dp, dp_value, fabs(base_value - dp_value), dual_cell); + result = std::max(result, fabs(base_value - dp_value)); + } + +#ifdef MD_DO_FULL_CHECK + auto db = dual_cell.dual_box(); + std::uniform_real_distribution<R> dlambda(db.lambda_min(), db.lambda_max()); + std::uniform_real_distribution<R> dmu(db.mu_min(), db.mu_max()); + std::mt19937 gen(1); + for(int i = 0; i < 1000; ++i) { + R lambda = dlambda(gen); + R mu = dmu(gen); + DualPoint<R> dp_random { db.axis_type(), db.angle_type(), lambda, mu }; + R dp_value = dp_random.weighted_push(p); + if (fabs(base_value - dp_value) > result) { + spd::error("in get_max_displacement_single_point, p = {}, vp = {}\ndb = {}\nresult = {}, base_value = {}, dp_value = {}, dp_random = {}", + p, vp, db, result, base_value, dp_value, dp_random); + throw std::runtime_error("error in get_max_displacement_single_value"); + } + } +#endif + + return result; + } + + template<class R, class T> + typename DistanceCalculator<R, T>::CellValueVector DistanceCalculator<R, T>::get_initial_dual_grid(R& lower_bound) + { + CellValueVector result = get_refined_grid(params_.initialization_depth, false, true); + + lower_bound = -1; + for(const auto& dc : result) { + lower_bound = std::max(lower_bound, dc.max_corner_value()); + } + + assert(lower_bound >= 0); + + for(auto& dual_cell : result) { + R good_enough_ub = get_good_enough_upper_bound(lower_bound); + R max_value_on_cell = get_upper_bound(dual_cell, good_enough_ub); + dual_cell.set_max_possible_value(max_value_on_cell); + +#ifdef MD_DO_FULL_CHECK + check_upper_bound(dual_cell); +#endif + + spd::debug("DEBUG INIT: added cell {}", dual_cell); + } + + return result; + } + + template<class R, class T> + typename DistanceCalculator<R, T>::CellValueVector + DistanceCalculator<R, T>::get_refined_grid(int init_depth, bool calculate_on_intermediate, bool calculate_on_last) + { + const R y_max = std::max(module_a_.max_y(), module_b_.max_y()); + const R x_max = std::max(module_a_.max_x(), module_b_.max_x()); + + const R lambda_min = 0; + const R lambda_max = 1; + + const R mu_min = 0; + + DualBox<R> x_flat(DualPoint<R>(AxisType::x_type, AngleType::flat, lambda_min, mu_min), + DualPoint<R>(AxisType::x_type, AngleType::flat, lambda_max, x_max)); + + DualBox<R> x_steep(DualPoint<R>(AxisType::x_type, AngleType::steep, lambda_min, mu_min), + DualPoint<R>(AxisType::x_type, AngleType::steep, lambda_max, x_max)); + + DualBox<R> y_flat(DualPoint<R>(AxisType::y_type, AngleType::flat, lambda_min, mu_min), + DualPoint<R>(AxisType::y_type, AngleType::flat, lambda_max, y_max)); + + DualBox<R> y_steep(DualPoint<R>(AxisType::y_type, AngleType::steep, lambda_min, mu_min), + DualPoint<R>(AxisType::y_type, AngleType::steep, lambda_max, y_max)); + + CellWithValue<R> x_flat_cell(x_flat, 0); + CellWithValue<R> x_steep_cell(x_steep, 0); + CellWithValue<R> y_flat_cell(y_flat, 0); + CellWithValue<R> y_steep_cell(y_steep, 0); + + if (init_depth == 0) { + DualPoint<R> diagonal_x_flat(AxisType::x_type, AngleType::flat, 1, 0); + + R diagonal_value = distance_on_line(diagonal_x_flat); + n_hera_calls_per_level_[0]++; + + x_flat_cell.set_value_at(ValuePoint::lower_right, diagonal_value); + y_flat_cell.set_value_at(ValuePoint::lower_right, diagonal_value); + x_steep_cell.set_value_at(ValuePoint::lower_right, diagonal_value); + y_steep_cell.set_value_at(ValuePoint::lower_right, diagonal_value); + } + +#ifdef MD_DEBUG + x_flat_cell.id = 1; + x_steep_cell.id = 2; + y_flat_cell.id = 3; + y_steep_cell.id = 4; + CellWithValue<R>::max_id = 4; +#endif + + CellValueVector result {x_flat_cell, x_steep_cell, y_flat_cell, y_steep_cell}; + + if (init_depth == 0) { + return result; + } + + CellValueVector refined_result; + + for(int i = 1; i <= init_depth; ++i) { + refined_result.clear(); + for(const auto& dual_cell : result) { + for(auto refined_cell : dual_cell.get_refined_cells()) { + // we calculate for init_dept - 1, not init_depth, + // because we want the cells to have value at a corner + if ((i == init_depth - 1 and calculate_on_last) or calculate_on_intermediate) + set_cell_central_value(refined_cell); + refined_result.push_back(refined_cell); + } + } + result = std::move(refined_result); + } + return result; + } + + template<class R, class T> + DistanceCalculator<R, T>::DistanceCalculator(const T& a, + const T& b, + CalculationParams<R>& params) + : + module_a_(a), + module_b_(b), + params_(params) + { + // make all coordinates non-negative + auto min_coord = std::min(module_a_.minimal_coordinate(), + module_b_.minimal_coordinate()); + spd::debug("in DistanceCalculator ctor, min_coord = {}", min_coord); + if (min_coord < 0) { + module_a_.translate(-min_coord); + module_b_.translate(-min_coord); + } + + assert(std::min({module_a_.min_x(), module_b_.min_x(), module_a_.min_y(), + module_b_.min_y()}) >= 0); + + spd::debug("DistanceCalculator constructed, module_a: max_x = {}, max_y = {}, module_b: max_x = {}, max_y = {}", + module_a_.max_x(), module_a_.max_y(), module_b_.max_x(), module_b_.max_y()); + } + + template<class R, class T> + R DistanceCalculator<R, T>::get_max_x(int module) const + { + return (module == 0) ? module_a_.max_x() : module_b_.max_x(); + } + + template<class R, class T> + R DistanceCalculator<R, T>::get_max_y(int module) const + { + return (module == 0) ? module_a_.max_y() : module_b_.max_y(); + } + + template<class R, class T> + R + DistanceCalculator<R, T>::get_local_refined_bound(const DualBox<R>& dual_box) const + { + return get_local_refined_bound(0, dual_box) + get_local_refined_bound(1, dual_box); + } + + template<class R, class T> + R + DistanceCalculator<R, T>::get_local_refined_bound(int module, const DualBox<R>& dual_box) const + { + spd::debug("Enter get_local_refined_bound, dual_box = {}", dual_box); + R d_lambda = dual_box.lambda_max() - dual_box.lambda_min(); + R d_mu = dual_box.mu_max() - dual_box.mu_min(); + R result; + if (dual_box.axis_type() == AxisType::x_type) { + if (dual_box.is_flat()) { + result = dual_box.lambda_max() * d_mu + (get_max_x(module) - dual_box.mu_min()) * d_lambda; + } else { + result = d_mu + get_max_y(module) * d_lambda; + } + } else { + // y-type + if (dual_box.is_flat()) { + result = d_mu + get_max_x(module) * d_lambda; + } else { + // steep + result = dual_box.lambda_max() * d_mu + (get_max_y(module) - dual_box.mu_min()) * d_lambda; + } + } + return result; + } + + template<class R, class T> + R DistanceCalculator<R, T>::get_local_dual_bound(int module, const DualBox<R>& dual_box) const + { + R dlambda = dual_box.lambda_max() - dual_box.lambda_min(); + R dmu = dual_box.mu_max() - dual_box.mu_min(); + + if (dual_box.is_flat()) { + return get_max_x(module) * dlambda + dmu; + } else { + return get_max_y(module) * dlambda + dmu; + } + } + + template<class R, class T> + R DistanceCalculator<R, T>::get_local_dual_bound(const DualBox<R>& dual_box) const + { + return get_local_dual_bound(0, dual_box) + get_local_dual_bound(1, dual_box); + } + + template<class R, class T> + R DistanceCalculator<R, T>::get_upper_bound(const CellWithValue<R>& dual_cell, R good_enough_ub) const + { + assert(good_enough_ub >= 0); + + switch(params_.bound_strategy) { + case BoundStrategy::bruteforce: + return std::numeric_limits<R>::max(); + + case BoundStrategy::local_dual_bound: + return dual_cell.min_value() + get_local_dual_bound(dual_cell.dual_box()); + + case BoundStrategy::local_dual_bound_refined: + return dual_cell.min_value() + get_local_refined_bound(dual_cell.dual_box()); + + case BoundStrategy::local_combined: { + R cheap_upper_bound = dual_cell.min_value() + get_local_refined_bound(dual_cell.dual_box()); + if (cheap_upper_bound < good_enough_ub) { + return cheap_upper_bound; + } else { + [[fallthrough]]; + } + } + + case BoundStrategy::local_dual_bound_for_each_point: { + R result = std::numeric_limits<R>::max(); + for(ValuePoint vp : k_corner_vps) { + if (not dual_cell.has_value_at(vp)) { + continue; + } + + R base_value = dual_cell.value_at(vp); + R bound_dgm_a = get_single_dgm_bound(dual_cell, vp, 0, good_enough_ub); + + if (params_.stop_asap and bound_dgm_a + base_value >= good_enough_ub) { + // we want to return a valid upper bound, not just something that will prevent discarding the cell + // and we don't want to compute pushes for points in second bifiltration. + // so just return a constant time bound + return dual_cell.min_value() + get_local_refined_bound(dual_cell.dual_box()); + } + + R bound_dgm_b = get_single_dgm_bound(dual_cell, vp, 1, + std::max(R(0), good_enough_ub - bound_dgm_a)); + + result = std::min(result, base_value + bound_dgm_a + bound_dgm_b); + +#ifdef MD_DEBUG + spd::debug("In get_upper_bound, cell = {}", dual_cell); + spd::debug("In get_upper_bound, vp = {}, base_value = {}, bound_dgm_a = {}, bound_dgm_b = {}, result = {}", vp, base_value, bound_dgm_a, bound_dgm_b, result); +#endif + + if (params_.stop_asap and result < good_enough_ub) { + break; + } + } + return result; + } + } + // to suppress compiler warning + return std::numeric_limits<R>::max(); + } + + // find maximal displacement of weighted points of m for all lines in dual_box + template<class R, class T> + R + DistanceCalculator<R, T>::get_single_dgm_bound(const CellWithValue<R>& dual_cell, + ValuePoint vp, + int module, + R good_enough_value) const + { + R result = 0; + Point<R> max_point; + + spd::debug( + "Enter get_single_dgm_bound, module = {}, dual_cell = {}, vp = {}, good_enough_value = {}, stop_asap = {}\n", + module, dual_cell, vp, good_enough_value, params_.stop_asap); + + const T& m = (module == 0) ? module_a_ : module_b_; + for(const auto& position : m.positions()) { + spd::debug("in get_single_dgm_bound, simplex = {}\n", position); + + R x = get_max_displacement_single_point(dual_cell, vp, position); + + spd::debug("In get_single_dgm_bound, point = {}, displacement = {}", position, x); + + if (x > result) { + result = x; + max_point = position; + spd::debug("In get_single_dgm_bound, point = {}, result now = displacement = {}", position, x); + } + + if (params_.stop_asap and result > good_enough_value) { + // we want to return a valid upper bound, + // now we just see it is worse than we need, but it may be even more + // just return a valid upper bound + spd::debug("result {} > good_enough_value {}, exit and return refined bound {}", result, + good_enough_value, get_local_refined_bound(dual_cell.dual_box())); + result = get_local_refined_bound(dual_cell.dual_box()); + break; + } + } + + spd::debug("Exit get_single_dgm_bound,\ndual_cell = {}\nmodule = {}, result = {}, max_point = {}", dual_cell, + module, result, max_point); + + return result; + } + + template<class R, class T> + R DistanceCalculator<R, T>::distance() + { + return get_distance_pq(); + } + + // calculate weighted bottleneneck distance between slices on line + // increments hera calls counter + template<class R, class T> + R DistanceCalculator<R, T>::distance_on_line(DualPoint<R> line) + { + ++n_hera_calls_; + R result = distance_on_line_const(line); + return result; + } + + template<class R, class T> + R DistanceCalculator<R, T>::distance_on_line_const(DualPoint<R> line) const + { + // TODO: think about this - how to call Hera + auto dgm_a = module_a_.weighted_slice_diagram(line); + auto dgm_b = module_b_.weighted_slice_diagram(line); + R result; + if (params_.hera_epsilon > static_cast<R>(0)) { + result = hera::bottleneckDistApprox(dgm_a, dgm_b, params_.hera_epsilon) / ( params_.hera_epsilon + 1); + } else { + result = hera::bottleneckDistExact(dgm_a, dgm_b); + } + if (n_hera_calls_ % 100 == 1) { + spd::debug("Calling Hera, dgm_a.size = {}, dgm_b.size = {}, line = {}, result = {}", dgm_a.size(), + dgm_b.size(), line, result); + } else { + spd::debug("Calling Hera, dgm_a.size = {}, dgm_b.size = {}, line = {}, result = {}", dgm_a.size(), + dgm_b.size(), line, result); + } + return result; + } + + template<class R, class T> + R DistanceCalculator<R, T>::get_good_enough_upper_bound(R lower_bound) const + { + R result; + // in upper_bound strategy we only prune cells if they cannot improve the lower bound, + // otherwise the experiment is supposed to run indefinitely + if (params_.traverse_strategy == TraverseStrategy::upper_bound) { + result = lower_bound; + } else { + result = (1.0 + params_.delta) * lower_bound; + } + return result; + } + + // helper function + // calculate weighted bt distance on cell center, + // assign distance value to cell, keep it in heat_map, and return + template<class R, class T> + void DistanceCalculator<R, T>::set_cell_central_value(CellWithValue<R>& dual_cell) + { + DualPoint<R> central_line {dual_cell.center()}; + + spd::debug("In set_cell_central_value, processing dual cell = {}, line = {}", dual_cell.dual_box(), + central_line); + R new_value = distance_on_line(central_line); + n_hera_calls_per_level_[dual_cell.level() + 1]++; + dual_cell.set_value_at(ValuePoint::center, new_value); + params_.actual_max_depth = std::max(params_.actual_max_depth, dual_cell.level() + 1); + +#ifdef PRINT_HEAT_MAP + if (params_.bound_strategy == BoundStrategy::bruteforce) { + spd::debug("In set_cell_central_value, adding to heat_map pair {} - {}", dual_cell.center(), new_value); + if (dual_cell.level() > params_.initialization_depth + 1 + and params_.heat_maps[dual_cell.level()].count(dual_cell.center()) > 0) { + auto existing = params_.heat_maps[dual_cell.level()].find(dual_cell.center()); + spd::debug("EXISTING: {} -> {}", existing->first, existing->second); + } + assert(dual_cell.level() <= params_.initialization_depth + 1 + or params_.heat_maps[dual_cell.level()].count(dual_cell.center()) == 0); + params_.heat_maps[dual_cell.level()][dual_cell.center()] = new_value; + } +#endif + } + + // quick-and-dirty hack to efficiently traverse priority queue with dual cells + // returns maximal possible value on all cells in queue + // assumes that the underlying container is vector! + // cell_ptr: pointer to the first element in queue + // n_cells: queue size + template<class R, class T> + R DistanceCalculator<R, T>::get_max_possible_value(const CellWithValue<R>* cell_ptr, int n_cells) + { + R result = (n_cells > 0) ? cell_ptr->stored_upper_bound() : 0; + for(int i = 0; i < n_cells; ++i, ++cell_ptr) { + result = std::max(result, cell_ptr->stored_upper_bound()); + } + return result; + } + + // helper function: + // return current error from lower and upper bounds + // and save it in params_ (hence not const) + template<class R, class T> + R DistanceCalculator<R, T>::current_error(R lower_bound, R upper_bound) + { + R current_error = (lower_bound > 0.0) ? (upper_bound - lower_bound) / lower_bound + : std::numeric_limits<R>::max(); + + params_.actual_error = current_error; + + if (current_error < params_.delta) { + spd::debug( + "Threshold achieved! bound_strategy = {}, traverse_strategy = {}, upper_bound = {}, current_error = {}", + params_.bound_strategy, params_.traverse_strategy, upper_bound, current_error); + } + return current_error; + } + + // return matching distance + // use priority queue to store dual cells + // comparison function depends on the strategies in params_ + // ressets hera calls counter + template<class R, class T> + R DistanceCalculator<R, T>::get_distance_pq() + { + std::map<int, long> n_cells_considered; + std::map<int, long> n_cells_pushed_into_queue; + long int n_too_deep_cells = 0; + std::map<int, long> n_cells_discarded; + std::map<int, long> n_cells_pruned; + + spd::debug("Enter get_distance_pq, bound strategy = {}, traverse strategy = {}, stop_asap = {} ", + params_.bound_strategy, params_.traverse_strategy, params_.stop_asap); + + std::chrono::high_resolution_clock timer; + auto start_time = timer.now(); + + n_hera_calls_ = 0; + n_hera_calls_per_level_.clear(); + + + // if cell is too deep and is not pushed into queue, + // we still need to take its max value into account; + // the max over such cells is stored in max_result_on_too_fine_cells + R upper_bound_on_deep_cells = -1; + + spd::debug("Started iterations in dual space, delta = {}, bound_strategy = {}", params_.delta, + params_.bound_strategy); + // user-defined less lambda function + // to regulate priority queue depending on strategy + auto dual_cell_less = [this](const CellWithValue<R>& a, const CellWithValue<R>& b) { + + int a_level = a.level(); + int b_level = b.level(); + R a_value = a.max_corner_value(); + R b_value = b.max_corner_value(); + R a_ub = a.stored_upper_bound(); + R b_ub = b.stored_upper_bound(); + if (this->params_.traverse_strategy == TraverseStrategy::upper_bound and + (not a.has_max_possible_value() or not b.has_max_possible_value())) { + throw std::runtime_error("no upper bound on cell"); + } + DualPoint<R> a_lower_left = a.dual_box().lower_left(); + DualPoint<R> b_lower_left = b.dual_box().lower_left(); + + switch(this->params_.traverse_strategy) { + // in both breadth_first searches we want coarser cells + // to be processed first. Cells with smaller level must be larger, + // hence the minus in front of level + case TraverseStrategy::breadth_first: + return std::make_tuple(-a_level, a_lower_left) + < std::make_tuple(-b_level, b_lower_left); + case TraverseStrategy::breadth_first_value: + return std::make_tuple(-a_level, a_value, a_lower_left) + < std::make_tuple(-b_level, b_value, b_lower_left); + case TraverseStrategy::depth_first: + return std::make_tuple(a_value, a_level, a_lower_left) + < std::make_tuple(b_value, b_level, b_lower_left); + case TraverseStrategy::upper_bound: + return std::make_tuple(a_ub, a_level, a_lower_left) + < std::make_tuple(b_ub, b_level, b_lower_left); + default: + throw std::runtime_error("Forgotten case"); + } + }; + + std::priority_queue<CellWithValue<R>, CellValueVector, decltype(dual_cell_less)> dual_cells_queue( + dual_cell_less); + + // weighted bt distance on the center of current cell + R lower_bound = std::numeric_limits<R>::min(); + + // init pq and lower bound + for(auto& init_cell : get_initial_dual_grid(lower_bound)) { + dual_cells_queue.push(init_cell); + } + + R upper_bound = get_max_possible_value(&dual_cells_queue.top(), dual_cells_queue.size()); + + std::vector<UbExperimentRecord> ub_experiment_results; + + while(not dual_cells_queue.empty()) { + + CellWithValue<R> dual_cell = dual_cells_queue.top(); + dual_cells_queue.pop(); + assert(dual_cell.has_corner_value() + and dual_cell.has_max_possible_value() + and dual_cell.max_corner_value() <= upper_bound); + + n_cells_considered[dual_cell.level()]++; + + bool discard_cell = false; + + if (not params_.stop_asap) { + // if stop_asap is on, it is safer to never discard a cell + if (params_.bound_strategy == BoundStrategy::bruteforce) { + discard_cell = false; + } else if (params_.traverse_strategy == TraverseStrategy::upper_bound) { + discard_cell = (dual_cell.stored_upper_bound() <= lower_bound); + } else { + discard_cell = (dual_cell.stored_upper_bound() <= (1.0 + params_.delta) * lower_bound); + } + } + + spd::debug( + "CURRENT CELL bound_strategy = {}, traverse_strategy = {}, dual cell: {}, upper_bound = {}, lower_bound = {}, current_error = {}, discard_cell = {}", + params_.bound_strategy, params_.traverse_strategy, dual_cell, upper_bound, lower_bound, + current_error(lower_bound, upper_bound), discard_cell); + + if (discard_cell) { + n_cells_discarded[dual_cell.level()]++; + continue; + } + + // until now, dual_cell knows its value in one of its corners + // new_value will be the weighted distance at its center + set_cell_central_value(dual_cell); + R new_value = dual_cell.value_at(ValuePoint::center); + lower_bound = std::max(new_value, lower_bound); + + spd::debug("Processed cell = {}, weighted value = {}, lower_bound = {}", dual_cell, new_value, lower_bound); + + assert(upper_bound >= lower_bound); + + if (current_error(lower_bound, upper_bound) < params_.delta) { + break; + } + + // refine cell and push 4 smaller cells into queue + for(auto refined_cell : dual_cell.get_refined_cells()) { + + if (refined_cell.num_values() == 0) + throw std::runtime_error("no value on cell"); + + // if delta is smaller than good_enough_value, it allows to prune cell + R good_enough_ub = get_good_enough_upper_bound(lower_bound); + + // upper bound of the parent holds for refined_cell + // and can sometimes be smaller! + R upper_bound_on_refined_cell = std::min(dual_cell.stored_upper_bound(), + get_upper_bound(refined_cell, good_enough_ub)); + + spd::debug("upper_bound_on_refined_cell = {}, dual_cell.stored_upper_bound = {}, get_upper_bound = {}", + upper_bound_on_refined_cell, dual_cell.stored_upper_bound(), + get_upper_bound(refined_cell, good_enough_ub)); + + refined_cell.set_max_possible_value(upper_bound_on_refined_cell); + +#ifdef MD_DO_FULL_CHECK + check_upper_bound(refined_cell); +#endif + + bool prune_cell = false; + + if (refined_cell.level() <= params_.max_depth) { + // cell might be added to queue; if it is not added, its maximal value can be safely ignored + if (params_.traverse_strategy == TraverseStrategy::upper_bound) { + prune_cell = (refined_cell.stored_upper_bound() <= lower_bound); + } else if (params_.bound_strategy != BoundStrategy::bruteforce) { + prune_cell = (refined_cell.stored_upper_bound() <= (1.0 + params_.delta) * lower_bound); + } + if (prune_cell) + n_cells_pruned[refined_cell.level()]++; +// prune_cell = (max_result_on_refined_cell <= lower_bound); + } else { + // cell is too deep, it won't be added to queue + // we must memorize maximal value on this cell, because we won't see it anymore + prune_cell = true; + if (refined_cell.stored_upper_bound() > (1 + params_.delta) * lower_bound) { + n_too_deep_cells++; + } + upper_bound_on_deep_cells = std::max(upper_bound_on_deep_cells, refined_cell.stored_upper_bound()); + } + + spd::debug( + "In get_distance_pq, loop over refined cells, bound_strategy = {}, traverse_strategy = {}, refined cell: {}, max_value_on_cell = {}, upper_bound = {}, current_error = {}, prune_cell = {}", + params_.bound_strategy, params_.traverse_strategy, refined_cell, + refined_cell.stored_upper_bound(), upper_bound, current_error(lower_bound, upper_bound), + prune_cell); + + if (not prune_cell) { + n_cells_pushed_into_queue[refined_cell.level()]++; + dual_cells_queue.push(refined_cell); + } + } // end loop over refined cells + + if (dual_cells_queue.empty()) + upper_bound = std::max(upper_bound, upper_bound_on_deep_cells); + else + upper_bound = std::max(upper_bound_on_deep_cells, + get_max_possible_value(&dual_cells_queue.top(), dual_cells_queue.size())); + + if (params_.traverse_strategy == TraverseStrategy::upper_bound) { + upper_bound = dual_cells_queue.top().stored_upper_bound(); + + if (get_hera_calls_number() < 20 || get_hera_calls_number() % 20 == 0) { + auto elapsed = timer.now() - start_time; + UbExperimentRecord ub_exp_record; + + ub_exp_record.error = current_error(lower_bound, upper_bound); + ub_exp_record.lower_bound = lower_bound; + ub_exp_record.upper_bound = upper_bound; + ub_exp_record.cell = dual_cells_queue.top(); + ub_exp_record.n_hera_calls = n_hera_calls_; + ub_exp_record.time = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count(); + +#ifdef MD_DO_CHECKS + if (ub_experiment_results.size() > 0) { + auto prev = ub_experiment_results.back(); + if (upper_bound > prev.upper_bound) { + spd::error("ALARM 1, upper_bound = {}, top = {}, prev.ub = {}, prev cell = {}, lower_bound = {}, prev.lower_bound = {}", + upper_bound, ub_exp_record.cell, prev.upper_bound, prev.cell, lower_bound, prev.lower_bound); + throw std::runtime_error("die"); + } + + if (lower_bound < prev.lower_bound) { + spd::error("ALARM 2, lower_bound = {}, prev.lower_bound = {}, top = {}, prev.ub = {}, prev cell = {}", lower_bound, prev.lower_bound, ub_exp_record.cell, prev.upper_bound, prev.cell); + throw std::runtime_error("die"); + } + } +#endif + + ub_experiment_results.emplace_back(ub_exp_record); + + fmt::print(std::cerr, "[UB_EXPERIMENT]\t{}\n", ub_exp_record); + } + } + + assert(upper_bound >= lower_bound); + + if (current_error(lower_bound, upper_bound) < params_.delta) { + break; + } + } + + params_.actual_error = current_error(lower_bound, upper_bound); + + if (n_too_deep_cells > 0) { + spd::warn( + "Error not guaranteed, there were {} too deep cells. Actual error = {}. Increase max_depth or delta", + n_too_deep_cells, params_.actual_error); + } + // otherwise actual_error in params can be larger than delta, + // but this is OK + + spd::debug("#############################################################"); + spd::debug( + "Exiting get_distance_pq, bound_strategy = {}, traverse_strategy = {}, lower_bound = {}, upper_bound = {}, current_error = {}, actual_max_level = {}", + params_.bound_strategy, params_.traverse_strategy, lower_bound, + upper_bound, params_.actual_error, params_.actual_max_depth); + + spd::debug("#############################################################"); + + if (params_.print_stats) { + fmt::print("EXIT STATS, cells considered:\n"); + print_map(n_cells_considered); + fmt::print("EXIT STATS, cells discarded:\n"); + print_map(n_cells_discarded); + fmt::print("EXIT STATS, cells pruned:\n"); + print_map(n_cells_pruned); + fmt::print("EXIT STATS, cells pushed:\n"); + print_map(n_cells_pushed_into_queue); + fmt::print("EXIT STATS, hera calls:\n"); + print_map(n_hera_calls_per_level_); + + fmt::print("EXIT STATS, too deep cells with high value: {}\n", n_too_deep_cells); + } + + return lower_bound; + } + + template<class R, class T> + int DistanceCalculator<R, T>::get_hera_calls_number() const + { + return n_hera_calls_; + } + + template<class R> + R matching_distance(const Bifiltration<R>& bif_a, const Bifiltration<R>& bif_b, + CalculationParams<R>& params) + { + R result; + // compute distance only in one dimension + if (params.dim != CalculationParams<R>::ALL_DIMENSIONS) { + BifiltrationProxy<R> bifp_a(bif_a, params.dim); + BifiltrationProxy<R> bifp_b(bif_b, params.dim); + DistanceCalculator<R, BifiltrationProxy<R>> runner(bifp_a, bifp_b, params); + result = runner.distance(); + params.n_hera_calls = runner.get_hera_calls_number(); + } else { + // compute distance in all dimensions, return maximal + result = -1; + for(int dim = 0; dim < std::max(bif_a.maximal_dim(), bif_b.maximal_dim()); ++dim) { + BifiltrationProxy<R> bifp_a(bif_a, params.dim); + BifiltrationProxy<R> bifp_b(bif_a, params.dim); + DistanceCalculator<R, BifiltrationProxy<R>> runner(bifp_a, bifp_b, params); + result = std::max(result, runner.distance()); + params.n_hera_calls += runner.get_hera_calls_number(); + } + } + return result; + } + + + template<class R> + R matching_distance(const ModulePresentation<R>& mod_a, const ModulePresentation<R>& mod_b, + CalculationParams<R>& params) + { + DistanceCalculator<R, ModulePresentation<R>> runner(mod_a, mod_b, params); + R result = runner.distance(); + params.n_hera_calls = runner.get_hera_calls_number(); + return result; + } +} // namespace md diff --git a/matching/include/opts/opts.h b/matching/include/opts/opts.h new file mode 100644 index 0000000..1a9bbf7 --- /dev/null +++ b/matching/include/opts/opts.h @@ -0,0 +1,499 @@ +/** + * Author: Dmitriy Morozov <dmitriy@mrzv.org> + * The interface is heavily influenced by GetOptPP (https://code.google.com/p/getoptpp/). + * The parsing logic is from ProgramOptions.hxx (https://github.com/Fytch/ProgramOptions.hxx). + * + * History: + * - 2015-06-01: added Traits<...>::type_string() for long, unsigned long + * - ... + * - 2018-04-27: replace parsing logic with the one from ProgramOptions.hxx to + * make the parser compliant with [GNU Program Argument Syntax + * Conventions](https://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html) + * - 2018-05-11: add dashed_non_option(), to accept arguments that are negative numbers + */ + +#ifndef OPTS_OPTS_H +#define OPTS_OPTS_H + +#include <iostream> +#include <sstream> +#include <string> +#include <list> +#include <vector> +#include <map> +#include <memory> +#include <cctype> +#include <functional> + +namespace opts { + +// Converters +template<class T> +struct Converter +{ + Converter() {} + static + bool convert(const std::string& val, T& res) + { + std::istringstream iss(val); + iss >> res; + return !iss.fail() && iss.eof(); + } +}; + +// Type +template<class T> +struct Traits +{ + static std::string type_string() { return "UNKNOWN TYPE"; } +}; + +template<> +struct Traits<int> +{ + static std::string type_string() { return "INT"; } +}; + +template<> +struct Traits<short int> +{ + static std::string type_string() { return "SHORT INT"; } +}; + +template<> +struct Traits<long> +{ + static std::string type_string() { return "LONG"; } +}; + +template<> +struct Traits<unsigned> +{ + static std::string type_string() { return "UNSIGNED INT"; } +}; + +template<> +struct Traits<short unsigned> +{ + static std::string type_string() { return "SHORT UNSIGNED INT"; } +}; + +template<> +struct Traits<unsigned long> +{ + static std::string type_string() { return "UNSIGNED LONG"; } +}; + +template<> +struct Traits<float> +{ + static std::string type_string() { return "FLOAT"; } +}; + +template<> +struct Traits<double> +{ + static std::string type_string() { return "DOUBLE"; } +}; + +template<> +struct Traits<std::string> +{ + static std::string type_string() { return "STRING"; } +}; + + +struct BasicOption +{ + using IsShort = std::function<bool(char)>; + + BasicOption(char s_, + std::string l_, + std::string default_, + std::string type_, + std::string help_): + s(s_), l(l_), d(default_), t(type_), help(help_) {} + virtual ~BasicOption() {} + + int long_size() const { return l.size() + 1 + t.size(); } + + void output(std::ostream& out, int max_long) const + { + out << " "; + if (s) + out << '-' << s << ", "; + else + out << " "; + + out << "--" << l << ' '; + + if (!t.empty()) + out << t; + + for (int i = long_size(); i < max_long; ++i) + out << ' '; + + out << " " << help; + + if (!d.empty()) + { + out << " [default: " << d << "]"; + } + out << '\n'; + } + + virtual bool flag() const { return false; } + virtual bool parse(int argc, char** argv, int& i, int j, IsShort is_short); + virtual bool set(std::string arg) =0; + + char s; + std::string l; + std::string d; + std::string t; + std::string help; +}; + +// Option +template<class T> +struct OptionContainer: public BasicOption +{ + OptionContainer(char s_, + const std::string& l_, + T& var_, + const std::string& help_, + const std::string& type_ = Traits<T>::type_string()): + BasicOption(s_, l_, default_value(var_), type_, help_), + var(&var_) {} + + static + std::string default_value(const T& def) + { + std::ostringstream oss; + oss << def; + return oss.str(); + } + + bool set(std::string s) override { return Converter<T>::convert(s, *var); } + + T* var; +}; + +template<> +struct OptionContainer<bool>: public BasicOption +{ + OptionContainer(char s_, + const std::string& l_, + bool& var_, + const std::string& help_): + BasicOption(s_, l_, "", "", help_), + var(&var_) { *var = false; } + + bool parse(int, char**, int&, int, IsShort) override { *var = true; return true; } + bool set(std::string) override { return true; } + bool flag() const override { return true; } + + bool* var; +}; + +template<class T> +struct OptionContainer< std::vector<T> >: public BasicOption +{ + OptionContainer(char s_, + const std::string& l_, + std::vector<T>& var_, + const std::string& help_, + const std::string& type_ = "SEQUENCE"): + BasicOption(s_, l_, default_value(var_), type_, help_), + var(&var_), first(true) { } + + static + std::string default_value(const std::vector<T>& def) + { + std::ostringstream oss; + oss << "("; + if (def.size()) + oss << def[0]; + for (size_t i = 1; i < def.size(); ++i) + oss << ", " << def[i]; + oss << ")"; + return oss.str(); + } + + bool set(std::string s) override + { + if (first) + { + var->clear(); + first = false; + } + + T x; + bool result = Converter<T>::convert(s,x); + var->emplace_back(std::move(x)); + return result; + } + + std::vector<T>* var; + mutable bool first; +}; + + +template<class T> +std::unique_ptr<BasicOption> +Option(char s, const std::string& l, T& var, const std::string& help) { return std::unique_ptr<BasicOption>{new OptionContainer<T>(s, l, var, help)}; } + +template<class T> +std::unique_ptr<BasicOption> +Option(char s, const std::string& l, T& var, + const std::string& type, const std::string& help) { return std::unique_ptr<BasicOption>{new OptionContainer<T>(s, l, var, help, type)}; } + +template<class T> +std::unique_ptr<BasicOption> +Option(const std::string& l, T& var, const std::string& help) { return std::unique_ptr<BasicOption>{new OptionContainer<T>(0, l, var, help)}; } + +template<class T> +std::unique_ptr<BasicOption> +Option(const std::string& l, T& var, + const std::string& type, const std::string& help) { return std::unique_ptr<BasicOption>{new OptionContainer<T>(0, l, var, help, type)}; } + +// PosOption +template<class T> +struct PosOptionContainer +{ + PosOptionContainer(T& var_): + var(&var_) {} + + bool parse(std::list<std::string>& args) const + { + if (args.empty()) + return false; + + bool result = Converter<T>::convert(args.front(), *var); + if (!result) + std::cerr << "error: failed to parse " << args.front() << '\n'; + args.pop_front(); + return result; + } + + T* var; +}; + +template<class T> +PosOptionContainer<T> +PosOption(T& var) { return PosOptionContainer<T>(var); } + + +// Options +struct Options +{ + Options(): + failed(false) {} + + inline + Options& operator>>(std::unique_ptr<BasicOption> opt); + template<class T> + Options& operator>>(const PosOptionContainer<T>& poc); + + operator bool() { return !failed; } + + + friend + std::ostream& + operator<<(std::ostream& out, const Options& ops) + { + int max_long = 0; + for (auto& cur : ops.options) + { + int cur_long = cur->long_size(); + if (cur_long > max_long) + max_long = cur_long; + } + + out << "Options:\n"; + for (auto& cur : ops.options) + cur->output(out, max_long); + + return out; + } + + bool parse(int argc, char** argv); + + void unrecognized_option(std::string arg) const + { + std::cerr << "error: unrecognized option " << arg << '\n'; + } + + static bool dashed_non_option(char* arg, BasicOption::IsShort is_short) + { + return arg[ 0 ] == '-' + && (std::isdigit(arg[ 1 ]) || arg[ 1 ] == '.') + && !is_short(arg[ 1 ]); + } + + private: + std::list<std::string> args; + std::list<std::unique_ptr<BasicOption>> options; + bool failed; +}; + +bool +BasicOption::parse(int argc, char** argv, int& i, int j, IsShort is_short) +{ + char* argument; + char* cur_arg = argv[i]; + // -v... + if (argv[i][j] == '\0') + { + // -v data + if (i + 1 < argc && (argv[i+1][0] != '-' || Options::dashed_non_option(argv[i+1], is_short))) + { + ++i; + argument = argv[i]; + } else + { + std::cerr << "error: cannot find the argument; ignoring " << argv[i] << '\n'; + return false; + } + } else if (argv[i][j] == '=') + { + // -v=data + argument = &argv[i][j+1]; + } else if( j == 2 ) { // only for short options + // -vdata + argument = &argv[i][j]; + } else + { + std::cerr << "error: unexpected character \'" << argv[i][j] << "\' ignoring " << argv[i] << '\n'; + return false; + } + bool result = set(argument); + if (!result) + std::cerr << "error: failed to parse " << argument << " in " << cur_arg << '\n'; + return result; +} + +bool +Options::parse(int argc, char** argv) +{ + std::map<char, BasicOption*> short_opts; + std::map<std::string, BasicOption*> long_opts; + + for (auto& opt : options) + { + if (opt->s) + short_opts[opt->s] = opt.get(); + + long_opts[opt->l] = opt.get(); + } + + auto is_short = [&short_opts](char c) -> bool { return short_opts.find(c) != short_opts.end(); }; + + for (int i = 1; i < argc; ++i) + { + if( argv[ i ][ 0 ] == '\0' ) + continue; + if( argv[ i ][ 0 ] != '-' || dashed_non_option(argv[i], is_short)) + args.push_back(argv[i]); + else + { + // -... + if( argv[ i ][ 1 ] == '\0' ) + { + // - + args.push_back(argv[i]); + } else if( argv[ i ][ 1 ] == '-' ) + { + if( argv[ i ][ 2 ] == '\0' ) + { + // -- + while( ++i < argc ) + args.push_back(argv[i]); + } else { + // --... + char* first = &argv[ i ][ 2 ]; + char* last = first; + for(; *last != '=' && *last != '\0'; ++last); + if (first == last) + { + failed = true; + unrecognized_option(argv[i]); + } else + { + auto opt_it = long_opts.find(std::string{first,last}); + if (opt_it == long_opts.end()) + { + failed = true; + unrecognized_option(argv[i]); + } else + { + failed |= !opt_it->second->parse(argc, argv, i, last - argv[i], is_short); + } + } + } + } else + { + // -f... + auto opt_it = short_opts.find(argv[i][1]); + if (opt_it == short_opts.end()) + { + failed = true; + unrecognized_option(argv[i]); + } else if (opt_it->second->flag()) + { + opt_it->second->parse(argc, argv, i, 0, is_short); // arguments are meaningless; just sets the flag + + // -fgh + char c; + for(int j = 1; (c = argv[i][j]) != '\0'; ++j) + { + if (!std::isprint(c) || c == '-') + { + failed = true; + std::cerr << "error: invalid character\'" << c << " ignoring " << &argv[i][j] << '\n'; + break; + } + opt_it = short_opts.find(c); + if (opt_it == short_opts.end()) + { + failed = true; + unrecognized_option("-" + std::string(1, c)); + continue; + } + if (!opt_it->second->flag()) + { + failed = true; + std::cerr << "error: non-void options not allowed in option packs; ignoring " << c << '\n'; + continue; + } + opt_it->second->parse(argc, argv, i, 0, is_short); // arguments are meaningless; just sets the flag + } + } else + { + failed |= !opt_it->second->parse(argc, argv, i, 2, is_short); + } + } + } + } + + return !failed; +} + +Options& +Options::operator>>(std::unique_ptr<BasicOption> opt) +{ + options.emplace_back(std::move(opt)); + return *this; +} + +template<class T> +Options& +Options::operator>>(const PosOptionContainer<T>& poc) +{ + if (!failed) + failed = !poc.parse(args); + return *this; +} + +} + +#endif diff --git a/matching/include/persistence_module.h b/matching/include/persistence_module.h new file mode 100644 index 0000000..b68c21e --- /dev/null +++ b/matching/include/persistence_module.h @@ -0,0 +1,111 @@ +#ifndef MATCHING_DISTANCE_PERSISTENCE_MODULE_H +#define MATCHING_DISTANCE_PERSISTENCE_MODULE_H + +#include <cassert> +#include <vector> +#include <utility> +#include <string> +#include <numeric> +#include <algorithm> +#include <unordered_set> + +#include "phat/boundary_matrix.h" +#include "phat/compute_persistence_pairs.h" + +#include "common_util.h" +#include "dual_point.h" +#include "box.h" + +namespace md { + + /* ModulePresentation contains only information needed for matching + * distance computation over Z/2. + * Generators are represented as points (critical values), + * id i of generator g_i = its index in * vector generators_. + * + * Relations are represented by struct Relation, which has two members: + * position_ is a point at which relation appears, + * components_ contains indices of generators that sum to zero: + * if components_ = [i, ..., j], then the relation is g_i +...+ g_j = 0. + * + * ModulePresentation has member positions_ that contains all + * distinct positions of generators and relations; + * this member simplifies computing local linear bound. + */ + + + template<class Real> + class ModulePresentation { + public: + + using RealVec = std::vector<Real>; + + enum Format { rivet_firep }; + + struct Relation { + Point<Real> position_; + IndexVec components_; + + Relation() {} + Relation(const Point<Real>& _pos, const IndexVec& _components) : position_(_pos), components_(_components) {} + + Real get_x() const { return position_.x; } + Real get_y() const { return position_.y; } + }; + + using RelVec = std::vector<Relation>; + + ModulePresentation() {} + + ModulePresentation(const PointVec<Real>& _generators, const RelVec& _relations); + + Diagram<Real> weighted_slice_diagram(const DualPoint<Real>& line) const; + + // translate all points by vector (a,a) + void translate(Real a); + + // return minimal value of x- and y-coordinates + Real minimal_coordinate() const { return std::min(min_x(), min_y()); } + + // return box that contains all positions of all simplices + Box<Real> bounding_box() const; + + Real max_x() const { return max_x_; } + + Real max_y() const { return max_y_; } + + Real min_x() const { return min_x_; } + + Real min_y() const { return min_y_; } + + PointVec<Real> positions() const; + +#ifndef MD_TEST_CODE + private: +#endif + + PointVec<Real> generators_; + std::vector<Relation> relations_; + PointVec<Real> positions_; + + + Real max_x_ { std::numeric_limits<Real>::max() }; + Real max_y_ { std::numeric_limits<Real>::max() }; + Real min_x_ { -std::numeric_limits<Real>::max() }; + Real min_y_ { -std::numeric_limits<Real>::max() }; + Box<Real> bounding_box_; + + void init_boundaries(); + + void project_generators(const DualPoint<Real>& slice, IndexVec& sorted_indices, RealVec& projections) const; + void project_relations(const DualPoint<Real>& slice, IndexVec& sorted_indices, RealVec& projections) const; + + void get_slice_projection_matrix(const DualPoint<Real>& slice, phat::boundary_matrix<>& phat_matrix, + RealVec& gen_projections, RealVec& rel_projections) const; + + }; +} // namespace md + +#include "persistence_module.hpp" + +#endif //MATCHING_DISTANCE_PERSISTENCE_MODULE_H diff --git a/matching/include/persistence_module.hpp b/matching/include/persistence_module.hpp new file mode 100644 index 0000000..233a70d --- /dev/null +++ b/matching/include/persistence_module.hpp @@ -0,0 +1,202 @@ +namespace md { + + /** + * + * @param values vector of length n + * @return [a_1,...,a_n] such that + * 1) values[a_1] <= values[a_2] <= ... <= values[a_n] + * 2) a_1,...,a_n is a permutation of 1,..,n + */ + + template<class T> + IndexVec get_sorted_indices(const std::vector<T>& values) + { + IndexVec result(values.size()); + std::iota(result.begin(), result.end(), 0); + std::sort(result.begin(), result.end(), + [&values](size_t a, size_t b) { return values[a] < values[b]; }); + return result; + } + + // helper function to initialize const member positions_ in ModulePresentation + template<class Real> + PointVec<Real> concat_gen_and_rel_positions(const PointVec<Real>& generators, + const typename ModulePresentation<Real>::RelVec& relations) + { + std::unordered_set<Point<Real>> ps(generators.begin(), generators.end()); + for(const auto& rel : relations) { + ps.insert(rel.position_); + } + return PointVec<Real>(ps.begin(), ps.end()); + } + + + template<class Real> + void ModulePresentation<Real>::init_boundaries() + { + max_x_ = -std::numeric_limits<Real>::max(); + max_y_ = -std::numeric_limits<Real>::max(); + min_x_ = std::numeric_limits<Real>::max(); + min_y_ = std::numeric_limits<Real>::max(); + + for(const auto& gen : positions_) { + min_x_ = std::min(gen.x, min_x_); + min_y_ = std::min(gen.y, min_y_); + max_x_ = std::max(gen.x, max_x_); + max_y_ = std::max(gen.y, max_y_); + } + + bounding_box_ = Box<Real>(Point<Real>(min_x_, min_y_), Point<Real>(max_x_, max_y_)); + } + + + template<class Real> + ModulePresentation<Real>::ModulePresentation(const PointVec<Real>& _generators, const RelVec& _relations) : + generators_(_generators), + relations_(_relations) + { + positions_ = concat_gen_and_rel_positions(generators_, relations_); + init_boundaries(); + } + + template<class Real> + void ModulePresentation<Real>::translate(Real a) + { + for(auto& g : generators_) { + g.translate(a); + } + + for(auto& r : relations_) { + r.position_.translate(a); + } + + positions_ = concat_gen_and_rel_positions(generators_, relations_); + init_boundaries(); + } + + + /** + * + * @param slice line on which generators are projected + * @param sorted_indices [a_1,...,a_n] s.t. wpush(generator[a_1]) <= wpush(generator[a_2]) <= .. + * @param projections sorted weighted pushes of generators + */ + + template<class Real> + void ModulePresentation<Real>::project_generators(const DualPoint<Real>& slice, + IndexVec& sorted_indices, RealVec& projections) const + { + spd::debug("Enter project_generators, slice = {}", slice); + size_t num_gens = generators_.size(); + + RealVec gen_values; + gen_values.reserve(num_gens); + for(const auto& pos : generators_) { + gen_values.push_back(slice.weighted_push(pos)); + } + sorted_indices = get_sorted_indices(gen_values); + projections.clear(); + projections.reserve(num_gens); + for(auto i : sorted_indices) { + projections.push_back(gen_values[i]); + spd::debug("added push = {}", gen_values[i]); + } + } + + template<class Real> + void ModulePresentation<Real>::project_relations(const DualPoint<Real>& slice, IndexVec& sorted_rel_indices, + RealVec& projections) const + { + + spd::debug("Enter project_relations, slice = {}", slice); + size_t num_rels = relations_.size(); + + RealVec rel_values; + rel_values.reserve(num_rels); + for(const auto& rel : relations_) { + rel_values.push_back(slice.weighted_push(rel.position_)); + } + + sorted_rel_indices = get_sorted_indices(rel_values); + + spd::debug("rel_values = {}, sorted_rel_indices = {}", container_to_string(rel_values), container_to_string(sorted_rel_indices)); + + projections.clear(); + projections.reserve(num_rels); + for(auto i : sorted_rel_indices) { + projections.push_back(rel_values[i]); + spd::debug("added push = {}", rel_values[i]); + } + } + + + template<class Real> + void ModulePresentation<Real>::get_slice_projection_matrix(const DualPoint<Real>& slice, + phat::boundary_matrix<>& phat_matrix, + RealVec& gen_projections, RealVec& rel_projections) const + { + spd::debug("Enter weighted_slice_diagram, slice = {}", slice); + IndexVec sorted_gen_indices, sorted_rel_indices; + + project_generators(slice, sorted_gen_indices, gen_projections); + project_relations(slice, sorted_rel_indices, rel_projections); + + phat_matrix.set_num_cols(relations_.size()); + + for(Index i = 0; i < (Index) relations_.size(); i++) { + IndexVec current_relation = relations_[sorted_rel_indices[i]].components_; + for(auto& j : current_relation) { + j = sorted_gen_indices[j]; + } + std::sort(current_relation.begin(), current_relation.end()); + // modules do not have dimension, set all to 0 + phat_matrix.set_dim(i, 0); + phat_matrix.set_col(i, current_relation); + } + } + + + template<class Real> + Diagram<Real> ModulePresentation<Real>::weighted_slice_diagram(const DualPoint<Real>& slice) const + { + spd::debug("Enter weighted_slice_diagram, slice = {}", slice); + + RealVec gen_projections, rel_projections; + phat::boundary_matrix<> phat_matrix; + + get_slice_projection_matrix(slice, phat_matrix, gen_projections, rel_projections); + + phat::persistence_pairs phat_persistence_pairs; + phat::compute_persistence_pairs<phat::twist_reduction>(phat_persistence_pairs, phat_matrix); + + Diagram<Real> dgm; + + constexpr Real real_inf = std::numeric_limits<Real>::infinity(); + + for(Index i = 0; i < (Index) phat_persistence_pairs.get_num_pairs(); i++) { + std::pair<phat::index, phat::index> new_pair = phat_persistence_pairs.get_pair(i); + bool is_finite_pair = new_pair.second != phat::k_infinity_index; + Real birth = gen_projections.at(new_pair.first); + Real death = is_finite_pair ? rel_projections.at(new_pair.second) : real_inf; + spd::debug("i = {}, birth = {}, death = {}", i, new_pair.first, new_pair.second); + if (birth != death) { + dgm.emplace_back(birth, death); + } + } + + return dgm; + } + + template<class Real> + PointVec<Real> ModulePresentation<Real>::positions() const + { + return positions_; + } + + template<class Real> + Box<Real> ModulePresentation<Real>::bounding_box() const + { + return bounding_box_; + } + +} // namespace md diff --git a/matching/include/phat/algorithms/chunk_reduction.h b/matching/include/phat/algorithms/chunk_reduction.h new file mode 100644 index 0000000..1797023 --- /dev/null +++ b/matching/include/phat/algorithms/chunk_reduction.h @@ -0,0 +1,223 @@ +/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/boundary_matrix.h>
+
+namespace phat {
+ class chunk_reduction {
+ public:
+ enum column_type { GLOBAL
+ , LOCAL_POSITIVE
+ , LOCAL_NEGATIVE };
+
+ public:
+ template< typename Representation >
+ void operator() ( boundary_matrix< Representation >& boundary_matrix ) {
+
+
+ const index nr_columns = boundary_matrix.get_num_cols();
+ if( omp_get_max_threads( ) > nr_columns )
+ omp_set_num_threads( 1 );
+
+ const dimension max_dim = boundary_matrix.get_max_dim();
+
+ std::vector< index > lowest_one_lookup( nr_columns, -1 );
+ std::vector < column_type > column_type( nr_columns, GLOBAL );
+ std::vector< char > is_active( nr_columns, false );
+
+ const index chunk_size = omp_get_max_threads() == 1 ? (index)sqrt( (double)nr_columns ) : nr_columns / omp_get_max_threads();
+
+ std::vector< index > chunk_boundaries;
+ for( index cur_boundary = 0; cur_boundary < nr_columns; cur_boundary += chunk_size )
+ chunk_boundaries.push_back( cur_boundary );
+ chunk_boundaries.push_back( nr_columns );
+
+ for( dimension cur_dim = max_dim; cur_dim >= 1; cur_dim-- ) {
+ // Phase 1: Reduce chunks locally -- 1st pass
+ #pragma omp parallel for schedule( guided, 1 )
+ for( index chunk_id = 0; chunk_id < (index)chunk_boundaries.size() - 1; chunk_id++ )
+ _local_chunk_reduction( boundary_matrix, lowest_one_lookup, column_type, cur_dim,
+ chunk_boundaries[ chunk_id ], chunk_boundaries[ chunk_id + 1 ], chunk_boundaries[ chunk_id ] );
+ boundary_matrix.sync();
+
+ // Phase 1: Reduce chunks locally -- 2nd pass
+ #pragma omp parallel for schedule( guided, 1 )
+ for( index chunk_id = 1; chunk_id < (index)chunk_boundaries.size( ) - 1; chunk_id++ )
+ _local_chunk_reduction( boundary_matrix, lowest_one_lookup, column_type, cur_dim,
+ chunk_boundaries[ chunk_id ], chunk_boundaries[ chunk_id + 1 ], chunk_boundaries[ chunk_id - 1 ] );
+ boundary_matrix.sync( );
+ }
+
+ // get global columns
+ std::vector< index > global_columns;
+ for( index cur_col_idx = 0; cur_col_idx < nr_columns; cur_col_idx++ )
+ if( column_type[ cur_col_idx ] == GLOBAL )
+ global_columns.push_back( cur_col_idx );
+
+ // get active columns
+ #pragma omp parallel for
+ for( index idx = 0; idx < (index)global_columns.size(); idx++ )
+ is_active[ global_columns[ idx ] ] = true;
+ _get_active_columns( boundary_matrix, lowest_one_lookup, column_type, global_columns, is_active );
+
+ // Phase 2+3: Simplify columns and reduce them
+ for( dimension cur_dim = max_dim; cur_dim >= 1; cur_dim-- ) {
+ // Phase 2: Simplify columns
+ std::vector< index > temp_col;
+ #pragma omp parallel for schedule( guided, 1 ), private( temp_col )
+ for( index idx = 0; idx < (index)global_columns.size(); idx++ )
+ if( boundary_matrix.get_dim( global_columns[ idx ] ) == cur_dim )
+ _global_column_simplification( global_columns[ idx ], boundary_matrix, lowest_one_lookup, column_type, is_active, temp_col );
+ boundary_matrix.sync();
+
+ // Phase 3: Reduce columns
+ for( index idx = 0; idx < (index)global_columns.size(); idx++ ) {
+ index cur_col = global_columns[ idx ];
+ if( boundary_matrix.get_dim( cur_col ) == cur_dim && column_type[ cur_col ] == GLOBAL ) {
+ index lowest_one = boundary_matrix.get_max_index( cur_col );
+ while( lowest_one != -1 && lowest_one_lookup[ lowest_one ] != -1 ) {
+ boundary_matrix.add_to( lowest_one_lookup[ lowest_one ], cur_col );
+ lowest_one = boundary_matrix.get_max_index( cur_col );
+ }
+ if( lowest_one != -1 ) {
+ lowest_one_lookup[ lowest_one ] = cur_col;
+ boundary_matrix.clear( lowest_one );
+ }
+ boundary_matrix.finalize( cur_col );
+ }
+ }
+ }
+
+ boundary_matrix.sync();
+ }
+
+ protected:
+ template< typename Representation >
+ void _local_chunk_reduction( boundary_matrix< Representation >& boundary_matrix
+ , std::vector<index>& lowest_one_lookup
+ , std::vector< column_type >& column_type
+ , const dimension cur_dim
+ , const index chunk_begin
+ , const index chunk_end
+ , const index row_begin ) {
+
+ for( index cur_col = chunk_begin; cur_col < chunk_end; cur_col++ ) {
+ if( column_type[ cur_col ] == GLOBAL && boundary_matrix.get_dim( cur_col ) == cur_dim ) {
+ index lowest_one = boundary_matrix.get_max_index( cur_col );
+ while( lowest_one != -1 && lowest_one >= row_begin && lowest_one_lookup[ lowest_one ] != -1 ) {
+ boundary_matrix.add_to( lowest_one_lookup[ lowest_one ], cur_col );
+ lowest_one = boundary_matrix.get_max_index( cur_col );
+ }
+ if( lowest_one >= row_begin ) {
+ lowest_one_lookup[ lowest_one ] = cur_col;
+ column_type[ cur_col ] = LOCAL_NEGATIVE;
+ column_type[ lowest_one ] = LOCAL_POSITIVE;
+ boundary_matrix.clear( lowest_one );
+ boundary_matrix.finalize( cur_col );
+ }
+ }
+ }
+ }
+
+ template< typename Representation >
+ void _get_active_columns( const boundary_matrix< Representation >& boundary_matrix
+ , const std::vector< index >& lowest_one_lookup
+ , const std::vector< column_type >& column_type
+ , const std::vector< index >& global_columns
+ , std::vector< char >& is_active ) {
+
+ const index nr_columns = boundary_matrix.get_num_cols();
+ std::vector< char > finished( nr_columns, false );
+
+ std::vector< std::pair < index, index > > stack;
+ std::vector< index > cur_col_values;
+ #pragma omp parallel for schedule( guided, 1 ), private( stack, cur_col_values )
+ for( index idx = 0; idx < (index)global_columns.size(); idx++ ) {
+ bool pop_next = false;
+ index start_col = global_columns[ idx ];
+ stack.push_back( std::pair< index, index >( start_col, -1 ) );
+ while( !stack.empty() ) {
+ index cur_col = stack.back().first;
+ index prev_col = stack.back().second;
+ if( pop_next ) {
+ stack.pop_back();
+ pop_next = false;
+ if( prev_col != -1 ) {
+ if( is_active[ cur_col ] ) {
+ is_active[ prev_col ] = true;
+ }
+ if( prev_col == stack.back().first ) {
+ finished[ prev_col ] = true;
+ pop_next = true;
+ }
+ }
+ } else {
+ pop_next = true;
+ boundary_matrix.get_col( cur_col, cur_col_values );
+ for( index idx = 0; idx < (index) cur_col_values.size(); idx++ ) {
+ index cur_row = cur_col_values[ idx ];
+ if( ( column_type[ cur_row ] == GLOBAL ) ) {
+ is_active[ cur_col ] = true;
+ } else if( column_type[ cur_row ] == LOCAL_POSITIVE ) {
+ index next_col = lowest_one_lookup[ cur_row ];
+ if( next_col != cur_col && !finished[ cur_col ] ) {
+ stack.push_back( std::make_pair( next_col, cur_col ) );
+ pop_next = false;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ template< typename Representation >
+ void _global_column_simplification( const index col_idx
+ , boundary_matrix< Representation >& boundary_matrix
+ , const std::vector< index >& lowest_one_lookup
+ , const std::vector< column_type >& column_type
+ , const std::vector< char >& is_active
+ , std::vector< index >& temp_col )
+ {
+ temp_col.clear();
+ while( !boundary_matrix.is_empty( col_idx ) ) {
+ index cur_row = boundary_matrix.get_max_index( col_idx );
+ switch( column_type[ cur_row ] ) {
+ case GLOBAL:
+ temp_col.push_back( cur_row );
+ boundary_matrix.remove_max( col_idx );
+ break;
+ case LOCAL_NEGATIVE:
+ boundary_matrix.remove_max( col_idx );
+ break;
+ case LOCAL_POSITIVE:
+ if( is_active[ lowest_one_lookup[ cur_row ] ] )
+ boundary_matrix.add_to( lowest_one_lookup[ cur_row ], col_idx );
+ else
+ boundary_matrix.remove_max( col_idx );
+ break;
+ }
+ }
+ std::reverse( temp_col.begin(), temp_col.end() );
+ boundary_matrix.set_col( col_idx, temp_col );
+ }
+ };
+}
diff --git a/matching/include/phat/algorithms/row_reduction.h b/matching/include/phat/algorithms/row_reduction.h new file mode 100644 index 0000000..cdd1a8f --- /dev/null +++ b/matching/include/phat/algorithms/row_reduction.h @@ -0,0 +1,56 @@ +/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/boundary_matrix.h>
+
+namespace phat {
+ class row_reduction {
+ public:
+ template< typename Representation >
+ void operator() ( boundary_matrix< Representation >& boundary_matrix ) {
+
+ const index nr_columns = boundary_matrix.get_num_cols();
+ std::vector< std::vector< index > > lowest_one_lookup( nr_columns );
+
+ for( index cur_col = nr_columns - 1; cur_col >= 0; cur_col-- ) {
+ if( !boundary_matrix.is_empty( cur_col ) )
+ lowest_one_lookup[ boundary_matrix.get_max_index( cur_col ) ].push_back( cur_col );
+
+ if( !lowest_one_lookup[ cur_col ].empty() ) {
+ boundary_matrix.clear( cur_col );
+ boundary_matrix.finalize( cur_col );
+ std::vector< index >& cols_with_cur_lowest = lowest_one_lookup[ cur_col ];
+ index source = *min_element( cols_with_cur_lowest.begin(), cols_with_cur_lowest.end() );
+ for( index idx = 0; idx < (index)cols_with_cur_lowest.size(); idx++ ) {
+ index target = cols_with_cur_lowest[ idx ];
+ if( target != source && !boundary_matrix.is_empty( target ) ) {
+ boundary_matrix.add_to( source, target );
+ if( !boundary_matrix.is_empty( target ) ) {
+ index lowest_one_of_target = boundary_matrix.get_max_index( target );
+ lowest_one_lookup[ lowest_one_of_target ].push_back( target );
+ }
+ }
+ }
+ }
+ }
+ }
+ };
+}
\ No newline at end of file diff --git a/matching/include/phat/algorithms/spectral_sequence_reduction.h b/matching/include/phat/algorithms/spectral_sequence_reduction.h new file mode 100644 index 0000000..bf442e6 --- /dev/null +++ b/matching/include/phat/algorithms/spectral_sequence_reduction.h @@ -0,0 +1,80 @@ +/* Copyright 2013 IST Austria
+ Contributed by: Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/boundary_matrix.h>
+
+namespace phat {
+ class spectral_sequence_reduction {
+ public:
+ template< typename Representation >
+ void operator () ( boundary_matrix< Representation >& boundary_matrix ) {
+
+ const index nr_columns = boundary_matrix.get_num_cols();
+ std::vector< index > lowest_one_lookup( nr_columns, -1 );
+
+ //const index num_stripes = (index) sqrt( (double)nr_columns );
+ const index num_stripes = omp_get_max_threads();
+
+ index block_size = ( nr_columns % num_stripes == 0 ) ? nr_columns / num_stripes : block_size = nr_columns / num_stripes + 1;
+
+ std::vector< std::vector< index > > unreduced_cols_cur_pass( num_stripes );
+ std::vector< std::vector< index > > unreduced_cols_next_pass( num_stripes );
+
+ for( index cur_dim = boundary_matrix.get_max_dim(); cur_dim >= 1 ; cur_dim-- ) {
+ #pragma omp parallel for schedule( guided, 1 )
+ for( index cur_stripe = 0; cur_stripe < num_stripes; cur_stripe++ ) {
+ index col_begin = cur_stripe * block_size;
+ index col_end = std::min( (cur_stripe+1) * block_size, nr_columns );
+ for( index cur_col = col_begin; cur_col < col_end; cur_col++ )
+ if( boundary_matrix.get_dim( cur_col ) == cur_dim && boundary_matrix.get_max_index( cur_col ) != -1 )
+ unreduced_cols_cur_pass[ cur_stripe ].push_back( cur_col );
+ }
+ for( index cur_pass = 0; cur_pass < num_stripes; cur_pass++ ) {
+ boundary_matrix.sync();
+ #pragma omp parallel for schedule( guided, 1 )
+ for( int cur_stripe = 0; cur_stripe < num_stripes; cur_stripe++ ) {
+ index row_begin = (cur_stripe - cur_pass) * block_size;
+ index row_end = row_begin + block_size;
+ unreduced_cols_next_pass[ cur_stripe ].clear();
+ for( index idx = 0; idx < (index)unreduced_cols_cur_pass[ cur_stripe ].size(); idx++ ) {
+ index cur_col = unreduced_cols_cur_pass[ cur_stripe ][ idx ];
+ index lowest_one = boundary_matrix.get_max_index( cur_col );
+ while( lowest_one != -1 && lowest_one >= row_begin && lowest_one < row_end && lowest_one_lookup[ lowest_one ] != -1 ) {
+ boundary_matrix.add_to( lowest_one_lookup[ lowest_one ], cur_col );
+ lowest_one = boundary_matrix.get_max_index( cur_col );
+ }
+ if( lowest_one != -1 ) {
+ if( lowest_one >= row_begin && lowest_one < row_end ) {
+ lowest_one_lookup[ lowest_one ] = cur_col;
+ boundary_matrix.clear( lowest_one );
+ boundary_matrix.finalize( cur_col );
+ } else {
+ unreduced_cols_next_pass[ cur_stripe ].push_back( cur_col );
+ }
+ }
+ }
+ unreduced_cols_next_pass[ cur_stripe ].swap( unreduced_cols_cur_pass[ cur_stripe ] );
+ }
+ }
+ }
+ }
+ };
+}
diff --git a/matching/include/phat/algorithms/standard_reduction.h b/matching/include/phat/algorithms/standard_reduction.h new file mode 100644 index 0000000..e490a5e --- /dev/null +++ b/matching/include/phat/algorithms/standard_reduction.h @@ -0,0 +1,47 @@ +/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/boundary_matrix.h>
+
+namespace phat {
+ class standard_reduction {
+ public:
+ template< typename Representation >
+ void operator() ( boundary_matrix< Representation >& boundary_matrix ) {
+
+ const index nr_columns = boundary_matrix.get_num_cols();
+ std::vector< index > lowest_one_lookup( nr_columns, -1 );
+
+ for( index cur_col = 0; cur_col < nr_columns; cur_col++ ) {
+ index lowest_one = boundary_matrix.get_max_index( cur_col );
+ while( lowest_one != -1 && lowest_one_lookup[ lowest_one ] != -1 ) {
+ boundary_matrix.add_to( lowest_one_lookup[ lowest_one ], cur_col );
+ lowest_one = boundary_matrix.get_max_index( cur_col );
+ }
+ if( lowest_one != -1 ) {
+ lowest_one_lookup[ lowest_one ] = cur_col;
+ }
+ boundary_matrix.finalize( cur_col );
+ }
+ }
+ };
+}
+
diff --git a/matching/include/phat/algorithms/twist_reduction.h b/matching/include/phat/algorithms/twist_reduction.h new file mode 100644 index 0000000..2357df0 --- /dev/null +++ b/matching/include/phat/algorithms/twist_reduction.h @@ -0,0 +1,51 @@ +/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/boundary_matrix.h>
+
+namespace phat {
+ class twist_reduction {
+ public:
+ template< typename Representation >
+ void operator () ( boundary_matrix< Representation >& boundary_matrix ) {
+
+ const index nr_columns = boundary_matrix.get_num_cols();
+ std::vector< index > lowest_one_lookup( nr_columns, -1 );
+
+ for( index cur_dim = boundary_matrix.get_max_dim(); cur_dim >= 1 ; cur_dim-- ) {
+ for( index cur_col = 0; cur_col < nr_columns; cur_col++ ) {
+ if( boundary_matrix.get_dim( cur_col ) == cur_dim ) {
+ index lowest_one = boundary_matrix.get_max_index( cur_col );
+ while( lowest_one != -1 && lowest_one_lookup[ lowest_one ] != -1 ) {
+ boundary_matrix.add_to( lowest_one_lookup[ lowest_one ], cur_col );
+ lowest_one = boundary_matrix.get_max_index( cur_col );
+ }
+ if( lowest_one != -1 ) {
+ lowest_one_lookup[ lowest_one ] = cur_col;
+ boundary_matrix.clear( lowest_one );
+ }
+ boundary_matrix.finalize( cur_col );
+ }
+ }
+ }
+ }
+ };
+}
diff --git a/matching/include/phat/boundary_matrix.h b/matching/include/phat/boundary_matrix.h new file mode 100644 index 0000000..10c66cc --- /dev/null +++ b/matching/include/phat/boundary_matrix.h @@ -0,0 +1,343 @@ +/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/representations/bit_tree_pivot_column.h>
+
+// interface class for the main data structure -- implementations of the interface can be found in ./representations
+namespace phat {
+ template< class Representation = bit_tree_pivot_column >
+ class boundary_matrix
+ {
+
+ protected:
+ Representation rep;
+
+ // interface functions -- actual implementation and complexity depends on chosen @Representation template
+ public:
+ // get overall number of columns in boundary_matrix
+ index get_num_cols() const { return rep._get_num_cols(); }
+
+ // set overall number of columns in boundary_matrix
+ void set_num_cols( index nr_of_columns ) { rep._set_num_cols( nr_of_columns ); }
+
+ // get dimension of given index
+ dimension get_dim( index idx ) const { return rep._get_dim( idx ); }
+
+ // set dimension of given index
+ void set_dim( index idx, dimension dim ) { rep._set_dim( idx, dim ); }
+
+ // replaces content of @col with boundary of given index
+ void get_col( index idx, column& col ) const { col.clear(); rep._get_col( idx, col ); }
+
+ // set column @idx to the values contained in @col
+ void set_col( index idx, const column& col ) { rep._set_col( idx, col ); }
+
+ // true iff boundary of given column is empty
+ bool is_empty( index idx ) const { return rep._is_empty( idx ); }
+
+ // largest index of given column (new name for lowestOne()) -- NOT thread-safe
+ index get_max_index( index idx ) const { return rep._get_max_index( idx ); }
+
+ // removes maximal index from given column
+ void remove_max( index idx ) { rep._remove_max( idx ); }
+
+ // adds column @source to column @target'
+ void add_to( index source, index target ) { rep._add_to( source, target ); }
+
+ // clears given column
+ void clear( index idx ) { rep._clear( idx ); }
+
+ // finalizes given column
+ void finalize( index idx ) { rep._finalize( idx ); }
+
+ // syncronizes all internal data structures -- has to be called before and after any multithreaded access!
+ void sync() { rep._sync(); }
+
+ // info functions -- independent of chosen 'Representation'
+ public:
+ // maximal dimension
+ dimension get_max_dim() const {
+ dimension cur_max_dim = 0;
+ for( index idx = 0; idx < get_num_cols(); idx++ )
+ cur_max_dim = get_dim( idx ) > cur_max_dim ? get_dim( idx ) : cur_max_dim;
+ return cur_max_dim;
+ }
+
+ // number of nonzero rows for given column @idx
+ index get_num_rows( index idx ) const {
+ column cur_col;
+ get_col( idx, cur_col );
+ return cur_col.size();
+ }
+
+ // maximal number of nonzero rows of all columns
+ index get_max_col_entries() const {
+ index max_col_entries = -1;
+ const index nr_of_columns = get_num_cols();
+ for( index idx = 0; idx < nr_of_columns; idx++ )
+ max_col_entries = get_num_rows( idx ) > max_col_entries ? get_num_rows( idx ) : max_col_entries;
+ return max_col_entries;
+ }
+
+ // maximal number of nonzero cols of all rows
+ index get_max_row_entries() const {
+ size_t max_row_entries = 0;
+ const index nr_of_columns = get_num_cols();
+ std::vector< std::vector< index > > transposed_matrix( nr_of_columns );
+ column temp_col;
+ for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) {
+ get_col( cur_col, temp_col );
+ for( index idx = 0; idx < (index)temp_col.size(); idx++)
+ transposed_matrix[ temp_col[ idx ] ].push_back( cur_col );
+ }
+ for( index idx = 0; idx < nr_of_columns; idx++ )
+ max_row_entries = transposed_matrix[ idx ].size() > max_row_entries ? transposed_matrix[ idx ].size() : max_row_entries;
+ return max_row_entries;
+ }
+
+ // overall number of entries in the matrix
+ index get_num_entries() const {
+ index number_of_nonzero_entries = 0;
+ const index nr_of_columns = get_num_cols();
+ for( index idx = 0; idx < nr_of_columns; idx++ )
+ number_of_nonzero_entries += get_num_rows( idx );
+ return number_of_nonzero_entries;
+ }
+
+ // operators / constructors
+ public:
+ boundary_matrix() {};
+
+ template< class OtherRepresentation >
+ boundary_matrix( const boundary_matrix< OtherRepresentation >& other ) {
+ *this = other;
+ }
+
+ template< typename OtherRepresentation >
+ bool operator==( const boundary_matrix< OtherRepresentation >& other_boundary_matrix ) const {
+ const index number_of_columns = this->get_num_cols();
+
+ if( number_of_columns != other_boundary_matrix.get_num_cols() )
+ return false;
+
+ column temp_col;
+ column other_temp_col;
+ for( index idx = 0; idx < number_of_columns; idx++ ) {
+ this->get_col( idx, temp_col );
+ other_boundary_matrix.get_col( idx, other_temp_col );
+ if( temp_col != other_temp_col || this->get_dim( idx ) != other_boundary_matrix.get_dim( idx ) )
+ return false;
+ }
+ return true;
+ }
+
+ template< typename OtherRepresentation >
+ bool operator!=( const boundary_matrix< OtherRepresentation >& other_boundary_matrix ) const {
+ return !( *this == other_boundary_matrix );
+ }
+
+ template< typename OtherRepresentation >
+ boundary_matrix< Representation >& operator=( const boundary_matrix< OtherRepresentation >& other )
+ {
+ const index nr_of_columns = other.get_num_cols();
+ this->set_num_cols( nr_of_columns );
+ column temp_col;
+ for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) {
+ this->set_dim( cur_col, other.get_dim( cur_col ) );
+ other.get_col( cur_col, temp_col );
+ this->set_col( cur_col, temp_col );
+ }
+
+ // by convention, always return *this
+ return *this;
+ }
+
+ // I/O -- independent of chosen 'Representation'
+ public:
+
+ // initializes boundary_matrix from (vector<vector>, vector) pair -- untested
+ template< typename index_type, typename dimemsion_type >
+ void load_vector_vector( const std::vector< std::vector< index_type > >& input_matrix, const std::vector< dimemsion_type >& input_dims ) {
+ const index nr_of_columns = (index)input_matrix.size();
+ this->set_num_cols( nr_of_columns );
+ column temp_col;
+ #pragma omp parallel for private( temp_col )
+ for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) {
+ this->set_dim( cur_col, (dimension)input_dims[ cur_col ] );
+
+ index num_rows = input_matrix[ cur_col ].size();
+ temp_col.resize( num_rows );
+ for( index cur_row = 0; cur_row < num_rows; cur_row++ )
+ temp_col[ cur_row ] = (index)input_matrix[ cur_col ][ cur_row ];
+ this->set_col( cur_col, temp_col );
+ }
+ }
+
+ template< typename index_type, typename dimemsion_type >
+ void save_vector_vector( std::vector< std::vector< index_type > >& output_matrix, std::vector< dimemsion_type >& output_dims ) {
+ const index nr_of_columns = get_num_cols();
+ output_matrix.resize( nr_of_columns );
+ output_dims.resize( nr_of_columns );
+ column temp_col;
+ for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) {
+ output_dims[ cur_col ] = (dimemsion_type)get_dim( cur_col );
+ get_col( cur_col, temp_col );
+ index num_rows = temp_col.size();
+ output_matrix[ cur_col ].clear();
+ output_matrix[ cur_col ].resize( num_rows );
+ for( index cur_row = 0; cur_row < num_rows; cur_row++ )
+ output_matrix[ cur_col ][ cur_row ] = (index_type)temp_col[ cur_row ];
+ }
+ }
+
+
+ // Loads the boundary_matrix from given file in ascii format
+ // Format: each line represents a column, first number is dimension, other numbers are the content of the column.
+ // Ignores empty lines and lines starting with a '#'.
+ bool load_ascii( std::string filename ) {
+ // first count number of columns:
+ std::string cur_line;
+ std::ifstream dummy( filename .c_str() );
+ if( dummy.fail() )
+ return false;
+
+ index number_of_columns = 0;
+ while( getline( dummy, cur_line ) ) {
+ cur_line.erase(cur_line.find_last_not_of(" \t\n\r\f\v") + 1);
+ if( cur_line != "" && cur_line[ 0 ] != '#' )
+ number_of_columns++;
+
+ }
+ this->set_num_cols( number_of_columns );
+ dummy.close();
+
+ std::ifstream input_stream( filename.c_str() );
+ if( input_stream.fail() )
+ return false;
+
+ column temp_col;
+ index cur_col = -1;
+ while( getline( input_stream, cur_line ) ) {
+ cur_line.erase(cur_line.find_last_not_of(" \t\n\r\f\v") + 1);
+ if( cur_line != "" && cur_line[ 0 ] != '#' ) {
+ cur_col++;
+ std::stringstream ss( cur_line );
+
+ int64_t temp_dim;
+ ss >> temp_dim;
+ this->set_dim( cur_col, (dimension) temp_dim );
+
+ int64_t temp_index;
+ temp_col.clear();
+ while( ss.good() ) {
+ ss >> temp_index;
+ temp_col.push_back( (index)temp_index );
+ }
+ std::sort( temp_col.begin(), temp_col.end() );
+ this->set_col( cur_col, temp_col );
+ }
+ }
+
+ input_stream.close();
+ return true;
+ }
+
+ // Saves the boundary_matrix to given file in ascii format
+ // Format: each line represents a column, first number is dimension, other numbers are the content of the column
+ bool save_ascii( std::string filename ) {
+ std::ofstream output_stream( filename.c_str() );
+ if( output_stream.fail() )
+ return false;
+
+ const index nr_columns = this->get_num_cols();
+ column tempCol;
+ for( index cur_col = 0; cur_col < nr_columns; cur_col++ ) {
+ output_stream << (int64_t)this->get_dim( cur_col );
+ this->get_col( cur_col, tempCol );
+ for( index cur_row_idx = 0; cur_row_idx < (index)tempCol.size(); cur_row_idx++ )
+ output_stream << " " << tempCol[ cur_row_idx ];
+ output_stream << std::endl;
+ }
+
+ output_stream.close();
+ return true;
+ }
+
+ // Loads boundary_matrix from given file
+ // Format: nr_columns % dim1 % N1 % row1 row2 % ...% rowN1 % dim2 % N2 % ...
+ bool load_binary( std::string filename )
+ {
+ std::ifstream input_stream( filename.c_str( ), std::ios_base::binary | std::ios_base::in );
+ if( input_stream.fail( ) )
+ return false;
+
+ int64_t nr_columns;
+ input_stream.read( (char*)&nr_columns, sizeof( int64_t ) );
+ this->set_num_cols( (index)nr_columns );
+
+ column temp_col;
+ for( index cur_col = 0; cur_col < nr_columns; cur_col++ ) {
+ int64_t cur_dim;
+ input_stream.read( (char*)&cur_dim, sizeof( int64_t ) );
+ this->set_dim( cur_col, (dimension)cur_dim );
+ int64_t nr_rows;
+ input_stream.read( (char*)&nr_rows, sizeof( int64_t ) );
+ temp_col.resize( ( std::size_t )nr_rows );
+ for( index idx = 0; idx < nr_rows; idx++ ) {
+ int64_t cur_row;
+ input_stream.read( (char*)&cur_row, sizeof( int64_t ) );
+ temp_col[ idx ] = (index)cur_row;
+ }
+ this->set_col( cur_col, temp_col );
+ }
+
+ input_stream.close( );
+ return true;
+ }
+
+ // Saves the boundary_matrix to given file in binary format
+ // Format: nr_columns % dim1 % N1 % row1 row2 % ...% rowN1 % dim2 % N2 % ...
+ bool save_binary( std::string filename )
+ {
+ std::ofstream output_stream( filename.c_str( ), std::ios_base::binary | std::ios_base::out );
+ if( output_stream.fail( ) )
+ return false;
+
+ const int64_t nr_columns = this->get_num_cols( );
+ output_stream.write( (char*)&nr_columns, sizeof( int64_t ) );
+ column tempCol;
+ for( index cur_col = 0; cur_col < nr_columns; cur_col++ ) {
+ int64_t cur_dim = this->get_dim( cur_col );
+ output_stream.write( (char*)&cur_dim, sizeof( int64_t ) );
+ this->get_col( cur_col, tempCol );
+ int64_t cur_nr_rows = tempCol.size( );
+ output_stream.write( (char*)&cur_nr_rows, sizeof( int64_t ) );
+ for( index cur_row_idx = 0; cur_row_idx < (index)tempCol.size( ); cur_row_idx++ ) {
+ int64_t cur_row = tempCol[ cur_row_idx ];
+ output_stream.write( (char*)&cur_row, sizeof( int64_t ) );
+ }
+ }
+
+ output_stream.close( );
+ return true;
+ }
+ };
+}
diff --git a/matching/include/phat/compute_persistence_pairs.h b/matching/include/phat/compute_persistence_pairs.h new file mode 100644 index 0000000..06f5372 --- /dev/null +++ b/matching/include/phat/compute_persistence_pairs.h @@ -0,0 +1,137 @@ +/* Copyright 2013 IST Austria + Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus + + This file is part of PHAT. + + PHAT is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + PHAT 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PHAT. If not, see <http://www.gnu.org/licenses/>. */ + +#pragma once + +#include <phat/persistence_pairs.h> +#include <phat/boundary_matrix.h> +#include <phat/helpers/dualize.h> +#include <phat/algorithms/twist_reduction.h> + +namespace phat { + // Extracts persistence pairs in separate dimensions from a reduced + // boundary matrix representing ``double`` filtration. The pairs + // give persistent relative homology of the pair of filtrations. + // TODO: Use it with standard reduction algorithm (no template option). + template< typename ReductionAlgorithm, typename Representation > + void compute_relative_persistence_pairs(std::vector<persistence_pairs>& pairs, boundary_matrix<Representation>& boundary_matrix, const std::map<int, int>& L) { + ReductionAlgorithm reduce; + reduce(boundary_matrix); + std::map<int, bool> free; + std::map<int, int> invL; + for (std::map<int, int>::const_iterator it = L.begin(); it != L.end(); ++it) { invL[it->second] = it->first; } + for (std::vector<persistence_pairs>::iterator it = pairs.begin(); it != pairs.end(); ++it) { it->clear(); } + for (index idx = 0; idx < boundary_matrix.get_num_cols(); ++idx) { + int dimension = boundary_matrix.get_dim(idx); + if (L.find(idx) != L.end()) { ++dimension; } + free[idx] = true; + if (!boundary_matrix.is_empty(idx)) { + index birth = boundary_matrix.get_max_index(idx); + index death = idx; + pairs[dimension-1].append_pair(birth, death); + free[birth] = false; + free[death] = false; + } else { + // This is an L-simplex and a (dimension+1)-dimensional cycle + if (L.find(idx) != L.end()) { + assert(dimension < pairs.size()); + pairs[dimension].append_pair(idx, -1); + } + } + } + for (std::map<int, bool>::iterator it = free.begin(); it != free.end(); ++it) { + if (it->second) { + int dimension = boundary_matrix.get_dim(it->first); + if (invL.find(it->first) == invL.end() && L.find(it->first) == L.end()) { + assert(dimension < pairs.size()); + pairs[dimension].append_pair(it->first, -1); + } + } + } + } + + // Extracts persistence pairs in separate dimensions; expects a d-dimensional vector of persistent_pairs + template< typename ReductionAlgorithm, typename Representation > + void compute_persistence_pairs(std::vector<persistence_pairs>& pairs, boundary_matrix<Representation>& boundary_matrix) { + ReductionAlgorithm reduce; + reduce(boundary_matrix); + std::map<int, bool> free; + for (std::vector<persistence_pairs>::iterator it = pairs.begin(); it != pairs.end(); ++it) { it->clear(); } + for (index idx = 0; idx < boundary_matrix.get_num_cols(); ++idx) { + int dimension = boundary_matrix.get_dim(idx); + free[idx] = true; + if (!boundary_matrix.is_empty(idx)) { + index birth = boundary_matrix.get_max_index(idx); + index death = idx; + pairs[dimension-1].append_pair(birth, death); + // Cannot be of the form (a, infinity) + free[birth] = false; + free[death] = false; + } + } + for (std::map<int, bool>::iterator it = free.begin(); it != free.end(); ++it) { + if (it->second) { + int dimension = boundary_matrix.get_dim(it->first); + pairs[dimension].append_pair(it->first, -1); + } + } + } + + template< typename ReductionAlgorithm, typename Representation > + void compute_persistence_pairs( persistence_pairs& pairs, boundary_matrix< Representation >& boundary_matrix ) { + ReductionAlgorithm reduce; + reduce( boundary_matrix ); + pairs.clear(); + std::set<index> max_indices; + // finite pairs + for( index idx = 0; idx < boundary_matrix.get_num_cols(); idx++ ) { + if( !boundary_matrix.is_empty( idx ) ) { + index birth = boundary_matrix.get_max_index( idx ); + max_indices.insert(birth); + index death = idx; + pairs.append_pair( birth, death ); + } + } + // infinite pairs: column idx is 0, and row idx does not contain a lowest one + for( index idx = 0; idx < boundary_matrix.get_num_cols(); idx++ ) { + if(boundary_matrix.is_empty(idx) && max_indices.count(idx) == 0 ) { + pairs.append_pair( idx, k_infinity_index); + } + } + } + + template< typename ReductionAlgorithm, typename Representation > + void compute_persistence_pairs_dualized( persistence_pairs& pairs, boundary_matrix< Representation >& boundary_matrix ) { + + dualize( boundary_matrix ); + compute_persistence_pairs< ReductionAlgorithm >( pairs, boundary_matrix ); + dualize_persistence_pairs( pairs, boundary_matrix.get_num_cols() ); + } + + template< typename Representation > + void compute_persistence_pairs( persistence_pairs& pairs, boundary_matrix< Representation >& boundary_matrix ) { + phat::compute_persistence_pairs< twist_reduction >( pairs, boundary_matrix ); + } + + + template< typename Representation > + void compute_persistence_pairs_dualized( persistence_pairs& pairs, boundary_matrix< Representation >& boundary_matrix ) { + compute_persistence_pairs_dualized< twist_reduction >( pairs, boundary_matrix ); + } + +} diff --git a/matching/include/phat/helpers/dualize.h b/matching/include/phat/helpers/dualize.h new file mode 100644 index 0000000..5731408 --- /dev/null +++ b/matching/include/phat/helpers/dualize.h @@ -0,0 +1,74 @@ +/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/boundary_matrix.h>
+#include <phat/persistence_pairs.h>
+
+
+namespace phat {
+ template< typename Representation >
+ void dualize( boundary_matrix< Representation >& boundary_matrix ) {
+
+ std::vector< dimension > dual_dims;
+ std::vector< std::vector< index > > dual_matrix;
+
+ index nr_of_columns = boundary_matrix.get_num_cols();
+ dual_matrix.resize( nr_of_columns );
+ dual_dims.resize( nr_of_columns );
+
+ std::vector< index > dual_sizes( nr_of_columns, 0 );
+
+ column temp_col;
+ for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) {
+ boundary_matrix.get_col( cur_col, temp_col );
+ for( index idx = 0; idx < (index)temp_col.size(); idx++)
+ dual_sizes[ nr_of_columns - 1 - temp_col[ idx ] ]++;
+ }
+
+ #pragma omp parallel for
+ for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ )
+ dual_matrix[cur_col].reserve(dual_sizes[cur_col]);
+
+ for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ ) {
+ boundary_matrix.get_col( cur_col, temp_col );
+ for( index idx = 0; idx < (index)temp_col.size(); idx++)
+ dual_matrix[ nr_of_columns - 1 - temp_col[ idx ] ].push_back( nr_of_columns - 1 - cur_col );
+ }
+
+ const dimension max_dim = boundary_matrix.get_max_dim();
+ #pragma omp parallel for
+ for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ )
+ dual_dims[ nr_of_columns - 1 - cur_col ] = max_dim - boundary_matrix.get_dim( cur_col );
+
+ #pragma omp parallel for
+ for( index cur_col = 0; cur_col < nr_of_columns; cur_col++ )
+ std::reverse( dual_matrix[ cur_col ].begin(), dual_matrix[ cur_col ].end() );
+
+ boundary_matrix.load_vector_vector( dual_matrix, dual_dims );
+ }
+
+ inline void dualize_persistence_pairs( persistence_pairs& pairs, const index n ) {
+ for (index i = 0; i < pairs.get_num_pairs(); ++i) {
+ std::pair< index, index > pair = pairs.get_pair( i );
+ pairs.set_pair( i , n - 1 - pair.second, n - 1 - pair.first);
+ }
+ }
+}
diff --git a/matching/include/phat/helpers/misc.h b/matching/include/phat/helpers/misc.h new file mode 100644 index 0000000..5a5c682 --- /dev/null +++ b/matching/include/phat/helpers/misc.h @@ -0,0 +1,78 @@ +/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+// STL includes
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+#include <set>
+#include <list>
+#include <map>
+#include <algorithm>
+#include <queue>
+#include <cassert>
+#include <sstream>
+#include <algorithm>
+#include <iomanip>
+#include <cmath>
+#include <cstdlib>
+#include <iterator>
+#include <limits>
+
+// VS2008 and below unfortunately do not support stdint.h
+#if defined(_MSC_VER)&& _MSC_VER < 1600
+ typedef __int8 int8_t;
+ typedef unsigned __int8 uint8_t;
+ typedef __int16 int16_t;
+ typedef unsigned __int16 uint16_t;
+ typedef __int32 int32_t;
+ typedef unsigned __int32 uint32_t;
+ typedef __int64 int64_t;
+ typedef unsigned __int64 uint64_t;
+#else
+ #include <stdint.h>
+#endif
+
+// basic types. index can be changed to int32_t to save memory on small instances
+namespace phat {
+ typedef int64_t index;
+ typedef int8_t dimension;
+ typedef std::vector< index > column;
+
+ constexpr index k_infinity_index = std::numeric_limits<index>::max();
+}
+
+// OpenMP (proxy) functions
+#if defined _OPENMP
+ #include <omp.h>
+#else
+ #define omp_get_thread_num() 0
+ #define omp_get_max_threads() 1
+ #define omp_get_num_threads() 1
+ inline void omp_set_num_threads( int ) {};
+ #include <time.h>
+ #define omp_get_wtime() (float)clock() / (float)CLOCKS_PER_SEC
+#endif
+
+#include <phat/helpers/thread_local_storage.h>
+
+
+
diff --git a/matching/include/phat/helpers/thread_local_storage.h b/matching/include/phat/helpers/thread_local_storage.h new file mode 100644 index 0000000..d0b5332 --- /dev/null +++ b/matching/include/phat/helpers/thread_local_storage.h @@ -0,0 +1,52 @@ +/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+
+// should ideally be equal to the cache line size of the CPU
+#define PHAT_TLS_SPACING_FACTOR 64
+
+// ThreadLocalStorage with some spacing to avoid "false sharing" (see wikipedia)
+template< typename T >
+class thread_local_storage
+{
+public:
+
+ thread_local_storage() : per_thread_storage( omp_get_max_threads() * PHAT_TLS_SPACING_FACTOR ) {};
+
+ T& operator()() {
+ return per_thread_storage[ omp_get_thread_num() * PHAT_TLS_SPACING_FACTOR ];
+ }
+
+ const T& operator()() const {
+ return per_thread_storage[ omp_get_thread_num() * PHAT_TLS_SPACING_FACTOR ];
+ }
+
+ T& operator[]( int tid ) {
+ return per_thread_storage[ tid * PHAT_TLS_SPACING_FACTOR ];
+ }
+
+ const T& operator[]( int tid ) const {
+ return per_thread_storage[ tid * PHAT_TLS_SPACING_FACTOR ];
+ }
+
+protected:
+ std::vector< T > per_thread_storage;
+};
diff --git a/matching/include/phat/persistence_pairs.h b/matching/include/phat/persistence_pairs.h new file mode 100644 index 0000000..eafc638 --- /dev/null +++ b/matching/include/phat/persistence_pairs.h @@ -0,0 +1,155 @@ +/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+
+namespace phat {
+ class persistence_pairs {
+
+ protected:
+ std::vector< std::pair< index, index > > pairs;
+
+ public:
+ index get_num_pairs() const {
+ return (index)pairs.size();
+ }
+
+ void append_pair( index birth, index death ) {
+ pairs.push_back( std::make_pair( birth, death ) );
+ }
+
+ std::pair< index, index > get_pair( index idx ) const {
+ return pairs[ idx ];
+ }
+
+ void set_pair( index idx, index birth, index death ) {
+ pairs[ idx ] = std::make_pair( birth, death );
+ }
+
+ void clear() {
+ pairs.clear();
+ }
+
+ void sort() {
+ std::sort( pairs.begin(), pairs.end() );
+ }
+
+ // Loads the persistence pairs from given file in asci format
+ // Format: nr_pairs % newline % birth1 % death1 % newline % birth2 % death2 % newline ...
+ bool load_ascii( std::string filename ) {
+ std::ifstream input_stream( filename.c_str() );
+ if( input_stream.fail() )
+ return false;
+
+ int64_t nr_pairs;
+ input_stream >> nr_pairs;
+ pairs.clear();
+ for( index idx = 0; idx < nr_pairs; idx++ ) {
+ int64_t birth;
+ input_stream >> birth;
+ int64_t death;
+ input_stream >> death;
+ append_pair( (index)birth, (index)death );
+ }
+
+ input_stream.close();
+ return true;
+ }
+
+ // Saves the persistence pairs to given file in binary format
+ // Format: nr_pairs % newline % birth1 % death1 % newline % birth2 % death2 % newline ...
+ bool save_ascii( std::string filename ) {
+ std::ofstream output_stream( filename.c_str() );
+ if( output_stream.fail() )
+ return false;
+
+ this->sort();
+ output_stream << get_num_pairs() << std::endl;
+ for( std::size_t idx = 0; idx < pairs.size(); idx++ ) {
+ output_stream << pairs[idx].first << " " << pairs[idx].second << std::endl;
+ }
+
+ output_stream.close();
+ return true;
+ }
+
+ // Loads the persistence pairs from given file in binary format
+ // Format: nr_pairs % birth1 % death1 % birth2 % death2 ...
+ bool load_binary( std::string filename ) {
+ std::ifstream input_stream( filename.c_str(), std::ios_base::binary | std::ios_base::in );
+ if( input_stream.fail() )
+ return false;
+
+ int64_t nr_pairs;
+ input_stream.read( (char*)&nr_pairs, sizeof( int64_t ) );
+ for( index idx = 0; idx < nr_pairs; idx++ ) {
+ int64_t birth;
+ input_stream.read( (char*)&birth, sizeof( int64_t ) );
+ int64_t death;
+ input_stream.read( (char*)&death, sizeof( int64_t ) );
+ append_pair( (index)birth, (index)death );
+ }
+
+ input_stream.close();
+ return true;
+ }
+
+ // Saves the persistence pairs to given file in binary format
+ // Format: nr_pairs % birth1 % death1 % birth2 % death2 ...
+ bool save_binary( std::string filename ) {
+ std::ofstream output_stream( filename.c_str(), std::ios_base::binary | std::ios_base::out );
+ if( output_stream.fail() )
+ return false;
+
+ this->sort();
+ int64_t nr_pairs = get_num_pairs();
+ output_stream.write( (char*)&nr_pairs, sizeof( int64_t ) );
+ for( std::size_t idx = 0; idx < pairs.size(); idx++ ) {
+ int64_t birth = pairs[ idx ].first;
+ output_stream.write( (char*)&birth, sizeof( int64_t ) );
+ int64_t death = pairs[ idx ].second;
+ output_stream.write( (char*)&death, sizeof( int64_t ) );
+ }
+
+ output_stream.close();
+ return true;
+ }
+
+ bool operator==( persistence_pairs& other_pairs ) {
+ this->sort();
+ other_pairs.sort();
+ if( pairs.size() != (std::size_t)other_pairs.get_num_pairs() )
+ return false;
+
+ for( index idx = 0; idx < (index)pairs.size(); idx++ )
+ if( get_pair( idx ) != other_pairs.get_pair( idx ) )
+ return false;
+
+ return true;
+ }
+
+ bool operator!=( persistence_pairs& other_pairs ) {
+ return !( *this == other_pairs );
+ }
+ };
+
+
+
+}
diff --git a/matching/include/phat/representations/abstract_pivot_column.h b/matching/include/phat/representations/abstract_pivot_column.h new file mode 100644 index 0000000..e16d7a5 --- /dev/null +++ b/matching/include/phat/representations/abstract_pivot_column.h @@ -0,0 +1,102 @@ +/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/representations/vector_vector.h>
+
+namespace phat {
+
+ // Note: We could even make the rep generic in the underlying Const representation
+ // But I cannot imagine that anything else than vector<vector<index>> would
+ // make sense
+ template< typename PivotColumn >
+ class abstract_pivot_column : public vector_vector {
+
+ protected:
+ typedef vector_vector Base;
+ typedef PivotColumn pivot_col;
+
+ // For parallization purposes, it could be more than one full column
+ mutable thread_local_storage< pivot_col > pivot_cols;
+ mutable thread_local_storage< index > idx_of_pivot_cols;
+
+ pivot_col& get_pivot_col() const {
+ return pivot_cols();
+ }
+
+ bool is_pivot_col( index idx ) const {
+ return idx_of_pivot_cols() == idx;
+ }
+
+ void release_pivot_col() {
+ index idx = idx_of_pivot_cols();
+ if( idx != -1 ) {
+ this->matrix[ idx ].clear();
+ pivot_cols().get_col_and_clear( this->matrix[ idx ] );
+ }
+ idx_of_pivot_cols() = -1;
+ }
+
+ void make_pivot_col( index idx ) {
+ release_pivot_col();
+ idx_of_pivot_cols() = idx;
+ get_pivot_col().add_col( matrix[ idx ] );
+ }
+
+ public:
+
+ void _set_num_cols( index nr_of_cols ) {
+ #pragma omp parallel for
+ for( int tid = 0; tid < omp_get_num_threads(); tid++ ) {
+ pivot_cols[ tid ].init( nr_of_cols );
+ idx_of_pivot_cols[ tid ] = -1;
+ }
+ Base::_set_num_cols( nr_of_cols );
+ }
+
+ void _add_to( index source, index target ) {
+ if( !is_pivot_col( target ) )
+ make_pivot_col( target );
+ get_pivot_col().add_col( matrix[source] );
+ }
+
+ void _sync() {
+ #pragma omp parallel for
+ for( int tid = 0; tid < omp_get_num_threads(); tid++ )
+ release_pivot_col();
+ }
+
+ void _get_col( index idx, column& col ) const { is_pivot_col( idx ) ? get_pivot_col().get_col( col ) : Base::_get_col( idx, col ); }
+
+ bool _is_empty( index idx ) const { return is_pivot_col( idx ) ? get_pivot_col().is_empty() : Base::_is_empty( idx ); }
+
+ index _get_max_index( index idx ) const { return is_pivot_col( idx ) ? get_pivot_col().get_max_index() : Base::_get_max_index( idx ); }
+
+ void _clear( index idx ) { is_pivot_col( idx ) ? get_pivot_col().clear() : Base::_clear( idx ); }
+
+ void _set_col( index idx, const column& col ) { is_pivot_col( idx ) ? get_pivot_col().set_col( col ) : Base::_set_col( idx, col ); }
+
+ void _remove_max( index idx ) { is_pivot_col( idx ) ? get_pivot_col().remove_max() : Base::_remove_max( idx ); }
+
+ void finalize( index idx ) { Base::_finalize( idx ); }
+ };
+}
+
+
diff --git a/matching/include/phat/representations/bit_tree_pivot_column.h b/matching/include/phat/representations/bit_tree_pivot_column.h new file mode 100644 index 0000000..4d48e88 --- /dev/null +++ b/matching/include/phat/representations/bit_tree_pivot_column.h @@ -0,0 +1,165 @@ +/* Copyright 2013 IST Austria
+ Contributed by: Hubert Wagner
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/representations/abstract_pivot_column.h>
+
+namespace phat {
+
+ // This is a bitset indexed with a 64-ary tree. Each node in the index
+ // has 64 bits; i-th bit says that the i-th subtree is non-empty.
+ // Supports practically O(1), inplace, zero-allocation: insert, remove, max_element
+ // and clear in O(number of ones in the bitset).
+ // 'add_index' is still the real bottleneck in practice.
+ class bit_tree_column
+ {
+ protected:
+
+ size_t offset; // data[i + offset] = ith block of the data-bitset
+ typedef uint64_t block_type;
+ std::vector< block_type > data;
+
+
+ size_t debrujin_magic_table[ 64 ];
+
+ enum { block_size_in_bits = 64 };
+ enum { block_shift = 6 };
+
+ // Some magic: http://graphics.stanford.edu/~seander/bithacks.html
+ // Gets the position of the rightmost bit of 'x'. 0 means the most significant bit.
+ // (-x)&x isolates the rightmost bit.
+ // The whole method is much faster than calling log2i, and very comparable to using ScanBitForward/Reverse intrinsic,
+ // which should be one CPU instruction, but is not portable.
+ size_t rightmost_pos( const block_type value ) const {
+ return 64 - 1 - debrujin_magic_table[ ( (value & (-(int64_t)value) ) * 0x07EDD5E59A4E28C2 ) >> 58 ];
+ }
+
+ public:
+
+ void init( index num_cols ) {
+ int64_t n = 1; // in case of overflow
+ int64_t bottom_blocks_needed = ( num_cols + block_size_in_bits - 1 ) / block_size_in_bits;
+ int64_t upper_blocks = 1;
+
+ // How many blocks/nodes of index needed to index the whole bitset?
+ while( n * block_size_in_bits < bottom_blocks_needed ) {
+ n *= block_size_in_bits;
+ upper_blocks += n;
+ }
+
+ offset = upper_blocks;
+ data.resize( upper_blocks + bottom_blocks_needed, 0 );
+
+ std::size_t temp_array[ 64 ] = {
+ 63, 0, 58, 1, 59, 47, 53, 2,
+ 60, 39, 48, 27, 54, 33, 42, 3,
+ 61, 51, 37, 40, 49, 18, 28, 20,
+ 55, 30, 34, 11, 43, 14, 22, 4,
+ 62, 57, 46, 52, 38, 26, 32, 41,
+ 50, 36, 17, 19, 29, 10, 13, 21,
+ 56, 45, 25, 31, 35, 16, 9, 12,
+ 44, 24, 15, 8, 23, 7, 6, 5 };
+
+ std::copy( &temp_array[ 0 ], &temp_array[ 64 ], &debrujin_magic_table[ 0 ] );
+ }
+
+ index get_max_index() const {
+ if( !data[ 0 ] )
+ return -1;
+
+ size_t n = 0;
+ size_t newn = 0;
+ size_t index = 0;
+ while( newn < data.size() ) {
+ n = newn;
+ index = rightmost_pos( data[ n ] );
+ newn = ( n << block_shift ) + index + 1;
+ }
+
+ return ( ( n - offset ) << block_shift ) + index;
+ }
+
+ bool is_empty() const {
+ return data[ 0 ] == 0;
+ }
+
+ void add_index( const size_t entry ) {
+ const block_type ONE = 1;
+ const block_type block_modulo_mask = ( ONE << block_shift ) - 1;
+ size_t index_in_level = entry >> block_shift;
+ size_t address = index_in_level + offset;
+ size_t index_in_block = entry & block_modulo_mask;
+
+ block_type mask = ( ONE << ( block_size_in_bits - index_in_block - 1 ) );
+
+ data[ address ] ^= mask;
+
+ // Check if we reached the root. Also, if anyone else was in this block, we don't need to update the path up.
+ while( address && !( data[ address ] & ~mask ) ) {
+ index_in_block = index_in_level & block_modulo_mask;
+ index_in_level >>= block_shift;
+ --address;
+ address >>= block_shift;
+ mask = ( ONE << ( block_size_in_bits - index_in_block - 1 ) );
+ data[ address ] ^= mask;
+ }
+ }
+
+ void get_col_and_clear( column &out ) {
+ index mx = this->get_max_index();
+ while( mx != -1 ) {
+ out.push_back( mx );
+ add_index( mx );
+ mx = this->get_max_index();
+ }
+
+ std::reverse( out.begin(), out.end() );
+ }
+
+ void add_col(const column &col) {
+ for( size_t i = 0; i < col.size(); ++i )
+ add_index(col[i]);
+ }
+
+ void clear() {
+ index mx = this->get_max_index();
+ while( mx != -1 ) {
+ add_index( mx );
+ mx = this->get_max_index();
+ }
+ }
+
+ void remove_max() {
+ add_index( get_max_index() );
+ }
+
+ void set_col( const column& col ) {
+ clear();
+ add_col( col );
+ }
+
+ void get_col( column& col ) {
+ get_col_and_clear( col );
+ add_col( col );
+ }
+ };
+
+ typedef abstract_pivot_column<bit_tree_column> bit_tree_pivot_column;
+}
diff --git a/matching/include/phat/representations/full_pivot_column.h b/matching/include/phat/representations/full_pivot_column.h new file mode 100644 index 0000000..c2e9e3c --- /dev/null +++ b/matching/include/phat/representations/full_pivot_column.h @@ -0,0 +1,100 @@ +/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/representations/abstract_pivot_column.h>
+
+namespace phat {
+ class full_column {
+
+ protected:
+ std::priority_queue< index > history;
+ std::vector< char > is_in_history;
+ std::vector< char > col_bit_field;
+
+ public:
+ void init( const index total_size ) {
+ col_bit_field.resize( total_size, false );
+ is_in_history.resize( total_size, false );
+ }
+
+ void add_col( const column& col ) {
+ for( index idx = 0; idx < (index) col.size(); idx++ ) {
+ add_index( col[ idx ] );
+ }
+ }
+
+ void add_index( const index idx ) {
+ if( !is_in_history[ idx ] ) {
+ history.push( idx );
+ is_in_history[ idx ] = true;
+ }
+
+ col_bit_field[ idx ] = !col_bit_field[ idx ];
+ }
+
+ index get_max_index() {
+ while( history.size() > 0 ) {
+ index topIndex = history.top();
+ if( col_bit_field[ topIndex ] ) {
+ return topIndex;
+ } else {
+ history.pop();
+ is_in_history[ topIndex ] = false;
+ }
+ }
+
+ return -1;
+ }
+
+ void get_col_and_clear( column& col ) {
+ while( !is_empty() ) {
+ col.push_back( get_max_index() );
+ add_index( get_max_index() );
+ }
+ std::reverse( col.begin(), col.end() );
+ }
+
+ bool is_empty() {
+ return (get_max_index() == -1);
+ }
+
+ void clear() {
+ while( !is_empty() )
+ add_index( get_max_index() );
+ }
+
+ void remove_max() {
+ add_index( get_max_index() );
+ }
+
+ void set_col( const column& col ) {
+ clear();
+ add_col( col );
+ }
+
+ void get_col( column& col ) {
+ get_col_and_clear( col );
+ add_col( col );
+ }
+ };
+
+ typedef abstract_pivot_column< full_column > full_pivot_column;
+}
diff --git a/matching/include/phat/representations/heap_pivot_column.h b/matching/include/phat/representations/heap_pivot_column.h new file mode 100644 index 0000000..33cd07b --- /dev/null +++ b/matching/include/phat/representations/heap_pivot_column.h @@ -0,0 +1,126 @@ +/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/representations/abstract_pivot_column.h>
+
+namespace phat {
+ class heap_column {
+
+ protected:
+ std::priority_queue< index > data;
+
+ column temp_col;
+ index inserts_since_last_prune;
+
+ void prune()
+ {
+ temp_col.clear( );
+ index max_index = pop_max_index( );
+ while( max_index != -1 ) {
+ temp_col.push_back( max_index );
+ max_index = pop_max_index( );
+ }
+
+ for( index idx = 0; idx < (index)temp_col.size( ); idx++ )
+ data.push( temp_col[ idx ] );
+
+ inserts_since_last_prune = 0;
+ }
+
+ index pop_max_index()
+ {
+ if( data.empty( ) )
+ return -1;
+ else {
+ index max_element = data.top( );
+ data.pop();
+ while( !data.empty( ) && data.top( ) == max_element ) {
+ data.pop( );
+ if( data.empty( ) )
+ return -1;
+ else {
+ max_element = data.top( );
+ data.pop( );
+ }
+ }
+ return max_element;
+ }
+ }
+
+ public:
+ void init( const index total_size ) {
+ inserts_since_last_prune = 0;
+ clear();
+ }
+
+ void add_col( const column& col ) {
+ for( index idx = 0; idx < (index) col.size(); idx++ )
+ data.push( col[ idx ] );
+ inserts_since_last_prune += col.size( );
+ if( 2 * inserts_since_last_prune >( index ) data.size( ) )
+ prune();
+ }
+
+ index get_max_index() {
+ index max_element = pop_max_index( );
+ if( max_element == -1 )
+ return -1;
+ else {
+ data.push( max_element );
+ return max_element;
+ }
+ }
+
+ void get_col_and_clear( column& col ) {
+ col.clear();
+ index max_index = pop_max_index( );
+ while( max_index != -1 ) {
+ col.push_back( max_index );
+ max_index = pop_max_index( );
+ }
+ std::reverse( col.begin(), col.end() );
+ }
+
+ bool is_empty() {
+ return get_max_index() == -1;
+ }
+
+ void clear() {
+ data = std::priority_queue< index >();
+ }
+
+ void remove_max() {
+ pop_max_index();
+ }
+
+ void set_col( const column& col ) {
+ clear();
+ add_col( col );
+ }
+
+ void get_col( column& col ) {
+ get_col_and_clear( col );
+ add_col( col );
+ }
+ };
+
+ typedef abstract_pivot_column< heap_column > heap_pivot_column;
+}
diff --git a/matching/include/phat/representations/sparse_pivot_column.h b/matching/include/phat/representations/sparse_pivot_column.h new file mode 100644 index 0000000..390fd91 --- /dev/null +++ b/matching/include/phat/representations/sparse_pivot_column.h @@ -0,0 +1,79 @@ +/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+#include <phat/representations/abstract_pivot_column.h>
+
+namespace phat {
+ class sparse_column {
+
+ protected:
+ std::set< index > data;
+
+ void add_index( const index idx ) {
+ std::pair< std::set< index >::iterator, bool > result = data.insert( idx );
+ if( result.second == false )
+ data.erase( result.first );
+ }
+
+ public:
+ void init( const index total_size ) {
+ data.clear();
+ }
+
+ void add_col( const column& col ) {
+ for( index idx = 0; idx < (index) col.size(); idx++ )
+ add_index( col[ idx ] );
+ }
+
+ index get_max_index() {
+ return data.empty() ? -1 : *data.rbegin();
+ }
+
+ void get_col_and_clear( column& col ) {
+ col.assign( data.begin(), data.end() );
+ data.clear();
+ }
+
+ bool is_empty() {
+ return data.empty();
+ }
+
+ void clear() {
+ data.clear();
+ }
+
+ void remove_max() {
+ add_index( get_max_index() );
+ }
+
+ void set_col( const column& col ) {
+ clear();
+ add_col( col );
+ }
+
+ void get_col( column& col ) {
+ get_col_and_clear( col );
+ add_col( col );
+ }
+ };
+
+ typedef abstract_pivot_column< sparse_column > sparse_pivot_column;
+}
diff --git a/matching/include/phat/representations/vector_heap.h b/matching/include/phat/representations/vector_heap.h new file mode 100644 index 0000000..db0420f --- /dev/null +++ b/matching/include/phat/representations/vector_heap.h @@ -0,0 +1,170 @@ +/* Copyright 2013 IST Austria
+Contributed by: Jan Reininghaus
+
+This file is part of PHAT.
+
+PHAT is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+PHAT 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+
+namespace phat {
+ class vector_heap {
+
+ protected:
+ std::vector< dimension > dims;
+ std::vector< column > matrix;
+
+ std::vector< index > inserts_since_last_prune;
+
+ mutable thread_local_storage< column > temp_column_buffer;
+
+ protected:
+ void _prune( index idx )
+ {
+ column& col = matrix[ idx ];
+ column& temp_col = temp_column_buffer();
+ temp_col.clear();
+ index max_index = _pop_max_index( col );
+ while( max_index != -1 ) {
+ temp_col.push_back( max_index );
+ max_index = _pop_max_index( col );
+ }
+ col = temp_col;
+ std::reverse( col.begin( ), col.end( ) );
+ std::make_heap( col.begin( ), col.end( ) );
+ inserts_since_last_prune[ idx ] = 0;
+ }
+
+ index _pop_max_index( index idx )
+ {
+ return _pop_max_index( matrix[ idx ] );
+ }
+
+ index _pop_max_index( column& col ) const
+ {
+ if( col.empty( ) )
+ return -1;
+ else {
+ index max_element = col.front( );
+ std::pop_heap( col.begin( ), col.end( ) );
+ col.pop_back( );
+ while( !col.empty( ) && col.front( ) == max_element ) {
+ std::pop_heap( col.begin( ), col.end( ) );
+ col.pop_back( );
+ if( col.empty( ) )
+ return -1;
+ else {
+ max_element = col.front( );
+ std::pop_heap( col.begin( ), col.end( ) );
+ col.pop_back( );
+ }
+ }
+ return max_element;
+ }
+ }
+
+ public:
+ // overall number of cells in boundary_matrix
+ index _get_num_cols( ) const
+ {
+ return (index)matrix.size( );
+ }
+ void _set_num_cols( index nr_of_columns )
+ {
+ dims.resize( nr_of_columns );
+ matrix.resize( nr_of_columns );
+ inserts_since_last_prune.assign( nr_of_columns, 0 );
+ }
+
+ // dimension of given index
+ dimension _get_dim( index idx ) const
+ {
+ return dims[ idx ];
+ }
+ void _set_dim( index idx, dimension dim )
+ {
+ dims[ idx ] = dim;
+ }
+
+ // replaces(!) content of 'col' with boundary of given index
+ void _get_col( index idx, column& col ) const
+ {
+ temp_column_buffer( ) = matrix[ idx ];
+
+ index max_index = _pop_max_index( temp_column_buffer() );
+ while( max_index != -1 ) {
+ col.push_back( max_index );
+ max_index = _pop_max_index( temp_column_buffer( ) );
+ }
+ std::reverse( col.begin( ), col.end( ) );
+ }
+ void _set_col( index idx, const column& col )
+ {
+ matrix[ idx ] = col;
+ std::make_heap( matrix[ idx ].begin( ), matrix[ idx ].end( ) );
+ }
+
+ // true iff boundary of given idx is empty
+ bool _is_empty( index idx ) const
+ {
+ return _get_max_index( idx ) == -1;
+ }
+
+ // largest row index of given column idx (new name for lowestOne())
+ index _get_max_index( index idx ) const
+ {
+ column& col = const_cast< column& >( matrix[ idx ] );
+ index max_element = _pop_max_index( col );
+ col.push_back( max_element );
+ std::push_heap( col.begin( ), col.end( ) );
+ return max_element;
+ }
+
+ // removes the maximal index of a column
+ void _remove_max( index idx )
+ {
+ _pop_max_index( idx );
+ }
+
+ // clears given column
+ void _clear( index idx )
+ {
+ matrix[ idx ].clear( );
+ }
+
+ // syncronizes all data structures (essential for openmp stuff)
+ void _sync( ) {}
+
+ // adds column 'source' to column 'target'
+ void _add_to( index source, index target )
+ {
+ for( index idx = 0; idx < (index)matrix[ source ].size( ); idx++ ) {
+ matrix[ target ].push_back( matrix[ source ][ idx ] );
+ std::push_heap( matrix[ target ].begin(), matrix[ target ].end() );
+ }
+ inserts_since_last_prune[ target ] += matrix[ source ].size();
+
+ if( 2 * inserts_since_last_prune[ target ] > ( index )matrix[ target ].size() )
+ _prune( target );
+ }
+
+ // finalizes given column
+ void _finalize( index idx ) {
+ _prune( idx );
+ }
+
+ };
+}
diff --git a/matching/include/phat/representations/vector_list.h b/matching/include/phat/representations/vector_list.h new file mode 100644 index 0000000..ca0b5b8 --- /dev/null +++ b/matching/include/phat/representations/vector_list.h @@ -0,0 +1,101 @@ +/* Copyright 2013 IST Austria
+ Contributed by: Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+
+namespace phat {
+ class vector_list {
+
+ protected:
+ std::vector< dimension > dims;
+ std::vector< std::list< index > > matrix;
+
+ public:
+ // overall number of cells in boundary_matrix
+ index _get_num_cols() const {
+ return (index)matrix.size();
+ }
+ void _set_num_cols( index nr_of_columns ) {
+ dims.resize( nr_of_columns );
+ matrix.resize( nr_of_columns );
+ }
+
+ // dimension of given index
+ dimension _get_dim( index idx ) const {
+ return dims[ idx ];
+ }
+ void _set_dim( index idx, dimension dim ) {
+ dims[ idx ] = dim;
+ }
+
+ // replaces(!) content of 'col' with boundary of given index
+ void _get_col( index idx, column& col ) const {
+ col.clear();
+ col.reserve( matrix[idx].size() );
+ std::copy (matrix[idx].begin(), matrix[idx].end(), std::back_inserter(col) );
+ }
+
+ void _set_col( index idx, const column& col ) {
+ matrix[ idx ].clear();
+ matrix[ idx ].resize( col.size() );
+ std::copy (col.begin(), col.end(), matrix[ idx ].begin() );
+ }
+
+ // true iff boundary of given idx is empty
+ bool _is_empty( index idx ) const {
+ return matrix[ idx ].empty();
+ }
+
+ // largest row index of given column idx (new name for lowestOne())
+ index _get_max_index( index idx ) const {
+ return matrix[ idx ].empty() ? -1 : *matrix[ idx ].rbegin();
+ }
+
+ // removes the maximal index of a column
+ void _remove_max( index idx ) {
+ std::list< index >::iterator it = matrix[ idx ].end();
+ it--;
+ matrix[ idx ].erase( it );
+ }
+
+ // clears given column
+ void _clear( index idx ) {
+ matrix[ idx ].clear();
+ }
+
+ // syncronizes all data structures (essential for openmp stuff)
+ void _sync() {}
+
+ // adds column 'source' to column 'target'
+ void _add_to( index source, index target ) {
+ std::list< index >& source_col = matrix[ source ];
+ std::list< index >& target_col = matrix[ target ];
+ std::list< index > temp_col;
+ target_col.swap( temp_col );
+ std::set_symmetric_difference( temp_col.begin(), temp_col.end(),
+ source_col.begin(), source_col.end(),
+ std::back_inserter( target_col ) );
+ }
+
+ // finalizes given column
+ void _finalize( index idx ) {
+ }
+ };
+}
diff --git a/matching/include/phat/representations/vector_set.h b/matching/include/phat/representations/vector_set.h new file mode 100644 index 0000000..6878a27 --- /dev/null +++ b/matching/include/phat/representations/vector_set.h @@ -0,0 +1,99 @@ +/* Copyright 2013 IST Austria + Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus + + This file is part of PHAT. + + PHAT is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + PHAT 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PHAT. If not, see <http://www.gnu.org/licenses/>. */ + +#pragma once + +#include <phat/helpers/misc.h> + +namespace phat { + class vector_set { + + protected: + std::vector< dimension > dims; + std::vector< std::set< index > > matrix; + + public: + // overall number of cells in boundary_matrix + index _get_num_cols() const { + return (index)matrix.size(); + } + void _set_num_cols( index nr_of_columns ) { + dims.resize( nr_of_columns ); + matrix.resize( nr_of_columns ); + } + + // dimension of given index + dimension _get_dim( index idx ) const { + return dims[ idx ]; + } + void _set_dim( index idx, dimension dim ) { + dims[ idx ] = dim; + } + + // replaces(!) content of 'col' with boundary of given index + void _get_col( index idx, column& col ) const { + col.clear(); + col.reserve( matrix[idx].size() ); + std::copy (matrix[idx].begin(), matrix[idx].end(), std::back_inserter(col) ); + } + void _set_col( index idx, const column& col ) { + matrix[ idx ].clear(); + matrix[ idx ].insert( col.begin(), col.end() ); + } + + // true iff boundary of given idx is empty + bool _is_empty( index idx ) const { + return matrix[ idx ].empty(); + } + + // largest row index of given column idx (new name for lowestOne()) + index _get_max_index( index idx ) const { + return matrix[ idx ].empty() ? -1 : *matrix[ idx ].rbegin(); + } + + // removes the maximal index of a column + void _remove_max( index idx ) { + std::set< index >::iterator it = matrix[ idx ].end(); + it--; + matrix[ idx ].erase( it ); + } + + // clears given column + void _clear( index idx ) { + matrix[ idx ].clear(); + } + + // syncronizes all data structures (essential for openmp stuff) + void _sync() {} + + // adds column 'source' to column 'target' + void _add_to( index source, index target ) { + for( std::set< index >::iterator it = matrix[ source ].begin(); it != matrix[ source ].end(); it++ ) { + std::set< index >& col = matrix[ target ]; + std::pair< std::set< index >::iterator, bool > result = col.insert( *it ); + if( !result.second ) + col.erase( result.first ); + } + } + + // finalizes given column + void _finalize( index idx ) { + } + + }; +} diff --git a/matching/include/phat/representations/vector_vector.h b/matching/include/phat/representations/vector_vector.h new file mode 100644 index 0000000..f111d6b --- /dev/null +++ b/matching/include/phat/representations/vector_vector.h @@ -0,0 +1,107 @@ +/* Copyright 2013 IST Austria
+ Contributed by: Ulrich Bauer, Michael Kerber, Jan Reininghaus
+
+ This file is part of PHAT.
+
+ PHAT is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ PHAT 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PHAT. If not, see <http://www.gnu.org/licenses/>. */
+
+#pragma once
+
+#include <phat/helpers/misc.h>
+
+namespace phat {
+ class vector_vector {
+
+ protected:
+ std::vector< dimension > dims;
+ std::vector< column > matrix;
+
+ thread_local_storage< column > temp_column_buffer;
+
+ public:
+ // overall number of cells in boundary_matrix
+ index _get_num_cols() const {
+ return (index)matrix.size();
+ }
+ void _set_num_cols( index nr_of_columns ) {
+ dims.resize( nr_of_columns );
+ matrix.resize( nr_of_columns );
+ }
+
+ // dimension of given index
+ dimension _get_dim( index idx ) const {
+ return dims[ idx ];
+ }
+ void _set_dim( index idx, dimension dim ) {
+ dims[ idx ] = dim;
+ }
+
+ // replaces(!) content of 'col' with boundary of given index
+ void _get_col( index idx, column& col ) const {
+ col = matrix[ idx ];
+ }
+ void _set_col( index idx, const column& col ) {
+ matrix[ idx ] = col;
+ }
+
+ // true iff boundary of given idx is empty
+ bool _is_empty( index idx ) const {
+ return matrix[ idx ].empty();
+ }
+
+ // largest row index of given column idx (new name for lowestOne())
+ index _get_max_index( index idx ) const {
+ return matrix[ idx ].empty() ? -1 : matrix[ idx ].back();
+ }
+
+ // removes the maximal index of a column
+ void _remove_max( index idx ) {
+ matrix[ idx ].pop_back();
+ }
+
+ // clears given column
+ void _clear( index idx ) {
+ matrix[ idx ].clear();
+ }
+
+ // syncronizes all data structures (essential for openmp stuff)
+ void _sync() {}
+
+ // adds column 'source' to column 'target'
+ void _add_to( index source, index target ) {
+ column& source_col = matrix[ source ];
+ column& target_col = matrix[ target ];
+ column& temp_col = temp_column_buffer();
+
+
+ size_t new_size = source_col.size() + target_col.size();
+
+ if (new_size > temp_col.size()) temp_col.resize(new_size);
+
+ std::vector<index>::iterator col_end = std::set_symmetric_difference( target_col.begin(), target_col.end(),
+ source_col.begin(), source_col.end(),
+ temp_col.begin() );
+ temp_col.erase(col_end, temp_col.end());
+
+
+ target_col.swap(temp_col);
+ }
+
+ // finalizes given column
+ void _finalize( index idx ) {
+ column& col = matrix[ idx ];
+ column(col.begin(), col.end()).swap(col);
+ }
+ };
+}
diff --git a/matching/include/simplex.h b/matching/include/simplex.h new file mode 100644 index 0000000..75bbcae --- /dev/null +++ b/matching/include/simplex.h @@ -0,0 +1,163 @@ +#ifndef MATCHING_DISTANCE_SIMPLEX_H +#define MATCHING_DISTANCE_SIMPLEX_H + +#include <algorithm> +#include <vector> +#include <ostream> + +#include "common_util.h" + +namespace md { + + template<class Real> + class Bifiltration; + + enum class BifiltrationFormat { + phat_like, rivet + }; + + class AbstractSimplex { + private: + std::vector<int> vertices_; + public: + + // this member is for convenience only; + // abstract simplices are identified by their set of vertices + mutable int id {-1}; + + decltype(auto) begin() { return vertices_.begin(); } + + decltype(auto) end() { return vertices_.end(); } + + decltype(auto) begin() const { return vertices_.begin(); } + + decltype(auto) end() const { return vertices_.end(); } + + decltype(auto) cbegin() const { return vertices_.cbegin(); } + + decltype(auto) cend() const { return vertices_.cend(); } + + int dim() const { return vertices_.size() - 1; } + + void push_back(int v) + { + vertices_.push_back(v); + std::sort(vertices_.begin(), vertices_.end()); + } + + AbstractSimplex() { } + + AbstractSimplex(std::vector<int> vertices, bool sort = true) + :vertices_(vertices) + { + if (sort) + std::sort(vertices_.begin(), vertices_.end()); + } + + + template<class Iter> + AbstractSimplex(Iter beg_iter, Iter end_iter, bool sort = true) + : + vertices_(beg_iter, end_iter) + { + if (sort) + std::sort(vertices_.begin(), end()); + } + + std::vector<AbstractSimplex> facets() const + { + std::vector<AbstractSimplex> result; + for (int i = 0; i < static_cast<int>(vertices_.size()); ++i) { + std::vector<int> facet_vertices; + facet_vertices.reserve(dim()); + for (int j = 0; j < static_cast<int>(vertices_.size()); ++j) { + if (j != i) + facet_vertices.push_back(vertices_[j]); + } + if (!facet_vertices.empty()) { + result.emplace_back(facet_vertices, false); + } + } + return result; + } + + friend std::ostream& operator<<(std::ostream& os, const AbstractSimplex& s); + // compare by vertices_ only + friend bool operator==(const AbstractSimplex& s1, const AbstractSimplex& s2); + + friend bool operator<(const AbstractSimplex&, const AbstractSimplex&); + }; + + inline std::ostream& operator<<(std::ostream& os, const AbstractSimplex& s) + { + os << "AbstractSimplex(id = " << s.id << ", vertices_ = " << container_to_string(s.vertices_) << ")"; + return os; + } + + inline bool operator<(const AbstractSimplex& a, const AbstractSimplex& b) + { + return a.vertices_ < b.vertices_; + } + + inline bool operator==(const AbstractSimplex& s1, const AbstractSimplex& s2) + { + return s1.vertices_ == s2.vertices_; + } + + template<class Real> + class Simplex { + private: + Index id_; + Point<Real> pos_; + int dim_; + // in our format we use facet indices, + // this is the fastest representation for homology + // Rivet format fills vertices_ vector + // Simplex alone cannot convert from one representation to the other, + // conversion routines are in Bifiltration + Column facet_indices_; + Column vertices_; + Real v {0}; // used when constructed a filtration for a slice + public: + Simplex(Index _id, std::string s, BifiltrationFormat input_format); + + Simplex(Index _id, Point<Real> birth, int _dim, const Column& _bdry); + + void init_rivet(std::string s); + + void init_phat_like(std::string s); + + Index id() const { return id_; } + + int dim() const { return dim_; } + + Column boundary() const { return facet_indices_; } + + Real value() const { return v; } + + // assumes 1-criticality + Point<Real> position() const { return pos_; } + + void set_position(const Point<Real>& new_pos) { pos_ = new_pos; } + + void scale(Real lambda) + { + pos_.x *= lambda; + pos_.y *= lambda; + } + + void translate(Real a); + + void set_value(Real new_val) { v = new_val; } + + friend Bifiltration<Real>; + }; + + template<class Real> + std::ostream& operator<<(std::ostream& os, const Simplex<Real>& s); + +} + +#include "simplex.hpp" + +#endif //MATCHING_DISTANCE_SIMPLEX_H diff --git a/matching/include/simplex.hpp b/matching/include/simplex.hpp new file mode 100644 index 0000000..ce0e30f --- /dev/null +++ b/matching/include/simplex.hpp @@ -0,0 +1,79 @@ +namespace md { + + template<class Real> + Simplex<Real>::Simplex(Index id, Point<Real> birth, int dim, const Column& bdry) + : + id_(id), + pos_(birth), + dim_(dim), + facet_indices_(bdry) { } + + template<class Real> + void Simplex<Real>::translate(Real a) + { + pos_.translate(a); + } + + template<class Real> + void Simplex<Real>::init_rivet(std::string s) + { + auto delim_pos = s.find_first_of(";"); + assert(delim_pos > 0); + std::string vertices_str = s.substr(0, delim_pos); + std::string pos_str = s.substr(delim_pos + 1); + assert(not vertices_str.empty() and not pos_str.empty()); + // get vertices + std::stringstream vertices_ss(vertices_str); + int dim = 0; + int vertex; + while (vertices_ss >> vertex) { + dim++; + vertices_.push_back(vertex); + } + // + std::sort(vertices_.begin(), vertices_.end()); + assert(dim > 0); + + std::stringstream pos_ss(pos_str); + // TODO: get rid of 1-criticaltiy assumption + pos_ss >> pos_.x >> pos_.y; + } + + template<class Real> + void Simplex<Real>::init_phat_like(std::string s) + { + facet_indices_.clear(); + std::stringstream ss(s); + ss >> dim_ >> pos_.x >> pos_.y; + if (dim_ > 0) { + facet_indices_.reserve(dim_ + 1); + for (int j = 0; j <= dim_; j++) { + Index k; + ss >> k; + facet_indices_.push_back(k); + } + } + } + + template<class Real> + Simplex<Real>::Simplex(Index _id, std::string s, BifiltrationFormat input_format) + :id_(_id) + { + switch (input_format) { + case BifiltrationFormat::phat_like : + init_phat_like(s); + break; + case BifiltrationFormat::rivet : + init_rivet(s); + break; + } + } + + template<class Real> + std::ostream& operator<<(std::ostream& os, const Simplex<Real>& x) + { + os << "Simplex<Real>(id = " << x.id() << ", dim = " << x.dim(); + os << ", boundary = " << container_to_string(x.boundary()) << ", pos = " << x.position() << ")"; + return os; + } +} diff --git a/matching/include/spdlog/async.h b/matching/include/spdlog/async.h new file mode 100644 index 0000000..971becd --- /dev/null +++ b/matching/include/spdlog/async.h @@ -0,0 +1,87 @@ + +// +// Copyright(c) 2018 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +// +// Async logging using global thread pool +// All loggers created here share same global thread pool. +// Each log message is pushed to a queue along withe a shared pointer to the +// logger. +// If a logger deleted while having pending messages in the queue, it's actual +// destruction will defer +// until all its messages are processed by the thread pool. +// This is because each message in the queue holds a shared_ptr to the +// originating logger. + +#include "spdlog/async_logger.h" +#include "spdlog/details/registry.h" +#include "spdlog/details/thread_pool.h" + +#include <memory> +#include <mutex> + +namespace spdlog { + +namespace details { +static const size_t default_async_q_size = 8192; +} + +// async logger factory - creates async loggers backed with thread pool. +// if a global thread pool doesn't already exist, create it with default queue +// size of 8192 items and single thread. +template<async_overflow_policy OverflowPolicy = async_overflow_policy::block> +struct async_factory_impl +{ + template<typename Sink, typename... SinkArgs> + static std::shared_ptr<async_logger> create(std::string logger_name, SinkArgs &&... args) + { + auto ®istry_inst = details::registry::instance(); + + // create global thread pool if not already exists.. + std::lock_guard<std::recursive_mutex> tp_lock(registry_inst.tp_mutex()); + auto tp = registry_inst.get_tp(); + if (tp == nullptr) + { + tp = std::make_shared<details::thread_pool>(details::default_async_q_size, 1); + registry_inst.set_tp(tp); + } + + auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...); + auto new_logger = std::make_shared<async_logger>(std::move(logger_name), std::move(sink), std::move(tp), OverflowPolicy); + registry_inst.initialize_logger(new_logger); + return new_logger; + } +}; + +using async_factory = async_factory_impl<async_overflow_policy::block>; +using async_factory_nonblock = async_factory_impl<async_overflow_policy::overrun_oldest>; + +template<typename Sink, typename... SinkArgs> +inline std::shared_ptr<spdlog::logger> create_async(std::string logger_name, SinkArgs &&... sink_args) +{ + return async_factory::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...); +} + +template<typename Sink, typename... SinkArgs> +inline std::shared_ptr<spdlog::logger> create_async_nb(std::string logger_name, SinkArgs &&... sink_args) +{ + return async_factory_nonblock::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...); +} + +// set global thread pool. +inline void init_thread_pool(size_t q_size, size_t thread_count) +{ + auto tp = std::make_shared<details::thread_pool>(q_size, thread_count); + details::registry::instance().set_tp(std::move(tp)); +} + +// get the global thread pool. +inline std::shared_ptr<spdlog::details::thread_pool> thread_pool() +{ + return details::registry::instance().get_tp(); +} +} // namespace spdlog diff --git a/matching/include/spdlog/async_logger.h b/matching/include/spdlog/async_logger.h new file mode 100644 index 0000000..a7ecb78 --- /dev/null +++ b/matching/include/spdlog/async_logger.h @@ -0,0 +1,73 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +// Very fast asynchronous logger (millions of logs per second on an average +// desktop) +// Uses pre allocated lockfree queue for maximum throughput even under large +// number of threads. +// Creates a single back thread to pop messages from the queue and log them. +// +// Upon each log write the logger: +// 1. Checks if its log level is enough to log the message +// 2. Push a new copy of the message to a queue (or block the caller until +// space is available in the queue) +// 3. will throw spdlog_ex upon log exceptions +// Upon destruction, logs all remaining messages in the queue before +// destructing.. + +#include "spdlog/common.h" +#include "spdlog/logger.h" + +#include <chrono> +#include <memory> +#include <string> + +namespace spdlog { + +// Async overflow policy - block by default. +enum class async_overflow_policy +{ + block, // Block until message can be enqueued + overrun_oldest // Discard oldest message in the queue if full when trying to + // add new item. +}; + +namespace details { +class thread_pool; +} + +class async_logger final : public std::enable_shared_from_this<async_logger>, public logger +{ + friend class details::thread_pool; + +public: + template<typename It> + async_logger(std::string logger_name, It begin, It end, std::weak_ptr<details::thread_pool> tp, + async_overflow_policy overflow_policy = async_overflow_policy::block); + + async_logger(std::string logger_name, sinks_init_list sinks_list, std::weak_ptr<details::thread_pool> tp, + async_overflow_policy overflow_policy = async_overflow_policy::block); + + async_logger(std::string logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp, + async_overflow_policy overflow_policy = async_overflow_policy::block); + + std::shared_ptr<logger> clone(std::string new_name) override; + +protected: + void sink_it_(details::log_msg &msg) override; + void flush_() override; + + void backend_log_(const details::log_msg &incoming_log_msg); + void backend_flush_(); + +private: + std::weak_ptr<details::thread_pool> thread_pool_; + async_overflow_policy overflow_policy_; +}; +} // namespace spdlog + +#include "details/async_logger_impl.h" diff --git a/matching/include/spdlog/common.h b/matching/include/spdlog/common.h new file mode 100644 index 0000000..d8c5811 --- /dev/null +++ b/matching/include/spdlog/common.h @@ -0,0 +1,243 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#include "spdlog/tweakme.h" + +#include <atomic> +#include <chrono> +#include <functional> +#include <initializer_list> +#include <memory> +#include <stdexcept> +#include <string> +#include <cstring> +#include <type_traits> +#include <unordered_map> + +#if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) +#include <codecvt> +#include <locale> +#endif + +#include "spdlog/details/null_mutex.h" + +#include "spdlog/fmt/fmt.h" + +// visual studio upto 2013 does not support noexcept nor constexpr +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#define SPDLOG_NOEXCEPT throw() +#define SPDLOG_CONSTEXPR +#else +#define SPDLOG_NOEXCEPT noexcept +#define SPDLOG_CONSTEXPR constexpr +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define SPDLOG_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) +#define SPDLOG_DEPRECATED __declspec(deprecated) +#else +#define SPDLOG_DEPRECATED +#endif + +// disable thread local on msvc 2013 +#ifndef SPDLOG_NO_TLS +#if (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__cplusplus_winrt) +#define SPDLOG_NO_TLS 1 +#endif +#endif + +// Get the basename of __FILE__ (at compile time if possible) +#if FMT_HAS_FEATURE(__builtin_strrchr) +#define SPDLOG_STRRCHR(str, sep) __builtin_strrchr(str, sep) +#else +#define SPDLOG_STRRCHR(str, sep) strrchr(str, sep) +#endif //__builtin_strrchr not defined + +#ifdef _WIN32 +#define SPDLOG_FILE_BASENAME(file) SPDLOG_STRRCHR("\\" file, '\\') + 1 +#else +#define SPDLOG_FILE_BASENAME(file) SPDLOG_STRRCHR("/" file, '/') + 1 +#endif + +#ifndef SPDLOG_FUNCTION +#define SPDLOG_FUNCTION __FUNCTION__ +#endif + +namespace spdlog { + +class formatter; + +namespace sinks { +class sink; +} + +using log_clock = std::chrono::system_clock; +using sink_ptr = std::shared_ptr<sinks::sink>; +using sinks_init_list = std::initializer_list<sink_ptr>; +using log_err_handler = std::function<void(const std::string &err_msg)>; + +// string_view type - either std::string_view or fmt::string_view (pre c++17) +#if defined(FMT_USE_STD_STRING_VIEW) +using string_view_t = std::string_view; +#else +using string_view_t = fmt::string_view; +#endif + +#if defined(SPDLOG_NO_ATOMIC_LEVELS) +using level_t = details::null_atomic_int; +#else +using level_t = std::atomic<int>; +#endif + +#define SPDLOG_LEVEL_TRACE 0 +#define SPDLOG_LEVEL_DEBUG 1 +#define SPDLOG_LEVEL_INFO 2 +#define SPDLOG_LEVEL_WARN 3 +#define SPDLOG_LEVEL_ERROR 4 +#define SPDLOG_LEVEL_CRITICAL 5 +#define SPDLOG_LEVEL_OFF 6 + +#if !defined(SPDLOG_ACTIVE_LEVEL) +#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO +#endif + +// Log level enum +namespace level { +enum level_enum +{ + trace = SPDLOG_LEVEL_TRACE, + debug = SPDLOG_LEVEL_DEBUG, + info = SPDLOG_LEVEL_INFO, + warn = SPDLOG_LEVEL_WARN, + err = SPDLOG_LEVEL_ERROR, + critical = SPDLOG_LEVEL_CRITICAL, + off = SPDLOG_LEVEL_OFF, +}; + +#if !defined(SPDLOG_LEVEL_NAMES) +#define SPDLOG_LEVEL_NAMES \ + { \ + "trace", "debug", "info", "warning", "error", "critical", "off" \ + } +#endif + +static string_view_t level_string_views[] SPDLOG_LEVEL_NAMES; +static const char *short_level_names[]{"T", "D", "I", "W", "E", "C", "O"}; + +inline string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT +{ + return level_string_views[l]; +} + +inline const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT +{ + return short_level_names[l]; +} + +inline spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT +{ + int level = 0; + for (const auto &level_str : level_string_views) + { + if (level_str == name) + { + return static_cast<level::level_enum>(level); + } + level++; + } + return level::off; +} + +using level_hasher = std::hash<int>; +} // namespace level + +// +// Pattern time - specific time getting to use for pattern_formatter. +// local time by default +// +enum class pattern_time_type +{ + local, // log localtime + utc // log utc +}; + +// +// Log exception +// +class spdlog_ex : public std::exception +{ +public: + explicit spdlog_ex(std::string msg) + : msg_(std::move(msg)) + { + } + + spdlog_ex(const std::string &msg, int last_errno) + { + fmt::memory_buffer outbuf; + fmt::format_system_error(outbuf, last_errno, msg); + msg_ = fmt::to_string(outbuf); + } + + const char *what() const SPDLOG_NOEXCEPT override + { + return msg_.c_str(); + } + +private: + std::string msg_; +}; + +// +// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined) +// +#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) +using filename_t = std::wstring; +#else +using filename_t = std::string; +#endif + +struct source_loc +{ + SPDLOG_CONSTEXPR source_loc() + : filename{""} + , line{0} + , funcname{""} + { + } + SPDLOG_CONSTEXPR source_loc(const char *filename_in, int line_in, const char *funcname_in) + : filename{filename_in} + , line{static_cast<uint32_t>(line_in)} + , funcname{funcname_in} + { + } + + SPDLOG_CONSTEXPR bool empty() const SPDLOG_NOEXCEPT + { + return line == 0; + } + const char *filename; + uint32_t line; + const char *funcname; +}; + +namespace details { +// make_unique support for pre c++14 + +#if __cplusplus >= 201402L // C++14 and beyond +using std::make_unique; +#else +template<typename T, typename... Args> +std::unique_ptr<T> make_unique(Args &&... args) +{ + static_assert(!std::is_array<T>::value, "arrays not supported"); + return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); +} +#endif +} // namespace details +} // namespace spdlog diff --git a/matching/include/spdlog/details/async_logger_impl.h b/matching/include/spdlog/details/async_logger_impl.h new file mode 100644 index 0000000..aafcae6 --- /dev/null +++ b/matching/include/spdlog/details/async_logger_impl.h @@ -0,0 +1,110 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +// async logger implementation +// uses a thread pool to perform the actual logging + +#include "spdlog/details/thread_pool.h" + +#include <chrono> +#include <memory> +#include <string> + +template<typename It> +inline spdlog::async_logger::async_logger( + std::string logger_name, It begin, It end, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy) + : logger(std::move(logger_name), begin, end) + , thread_pool_(std::move(tp)) + , overflow_policy_(overflow_policy) +{ +} + +inline spdlog::async_logger::async_logger( + std::string logger_name, sinks_init_list sinks_list, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy) + : async_logger(std::move(logger_name), sinks_list.begin(), sinks_list.end(), std::move(tp), overflow_policy) +{ +} + +inline spdlog::async_logger::async_logger( + std::string logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy) + : async_logger(std::move(logger_name), {std::move(single_sink)}, std::move(tp), overflow_policy) +{ +} + +// send the log message to the thread pool +inline void spdlog::async_logger::sink_it_(details::log_msg &msg) +{ +#if defined(SPDLOG_ENABLE_MESSAGE_COUNTER) + incr_msg_counter_(msg); +#endif + if (auto pool_ptr = thread_pool_.lock()) + { + pool_ptr->post_log(shared_from_this(), msg, overflow_policy_); + } + else + { + throw spdlog_ex("async log: thread pool doesn't exist anymore"); + } +} + +// send flush request to the thread pool +inline void spdlog::async_logger::flush_() +{ + if (auto pool_ptr = thread_pool_.lock()) + { + pool_ptr->post_flush(shared_from_this(), overflow_policy_); + } + else + { + throw spdlog_ex("async flush: thread pool doesn't exist anymore"); + } +} + +// +// backend functions - called from the thread pool to do the actual job +// +inline void spdlog::async_logger::backend_log_(const details::log_msg &incoming_log_msg) +{ + try + { + for (auto &s : sinks_) + { + if (s->should_log(incoming_log_msg.level)) + { + s->log(incoming_log_msg); + } + } + } + SPDLOG_CATCH_AND_HANDLE + + if (should_flush_(incoming_log_msg)) + { + backend_flush_(); + } +} + +inline void spdlog::async_logger::backend_flush_() +{ + try + { + for (auto &sink : sinks_) + { + sink->flush(); + } + } + SPDLOG_CATCH_AND_HANDLE +} + +inline std::shared_ptr<spdlog::logger> spdlog::async_logger::clone(std::string new_name) +{ + auto cloned = std::make_shared<spdlog::async_logger>(std::move(new_name), sinks_.begin(), sinks_.end(), thread_pool_, overflow_policy_); + + cloned->set_level(this->level()); + cloned->flush_on(this->flush_level()); + cloned->set_error_handler(this->error_handler()); + return std::move(cloned); +} diff --git a/matching/include/spdlog/details/circular_q.h b/matching/include/spdlog/details/circular_q.h new file mode 100644 index 0000000..b01325b --- /dev/null +++ b/matching/include/spdlog/details/circular_q.h @@ -0,0 +1,72 @@ +// +// Copyright(c) 2018 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +// cirucal q view of std::vector. +#pragma once + +#include <vector> + +namespace spdlog { +namespace details { +template<typename T> +class circular_q +{ +public: + using item_type = T; + + explicit circular_q(size_t max_items) + : max_items_(max_items + 1) // one item is reserved as marker for full q + , v_(max_items_) + { + } + + // push back, overrun (oldest) item if no room left + void push_back(T &&item) + { + v_[tail_] = std::move(item); + tail_ = (tail_ + 1) % max_items_; + + if (tail_ == head_) // overrun last item if full + { + head_ = (head_ + 1) % max_items_; + ++overrun_counter_; + } + } + + // Pop item from front. + // If there are no elements in the container, the behavior is undefined. + void pop_front(T &popped_item) + { + popped_item = std::move(v_[head_]); + head_ = (head_ + 1) % max_items_; + } + + bool empty() + { + return tail_ == head_; + } + + bool full() + { + // head is ahead of the tail by 1 + return ((tail_ + 1) % max_items_) == head_; + } + + size_t overrun_counter() const + { + return overrun_counter_; + } + +private: + size_t max_items_; + typename std::vector<T>::size_type head_ = 0; + typename std::vector<T>::size_type tail_ = 0; + + std::vector<T> v_; + + size_t overrun_counter_ = 0; +}; +} // namespace details +} // namespace spdlog diff --git a/matching/include/spdlog/details/console_globals.h b/matching/include/spdlog/details/console_globals.h new file mode 100644 index 0000000..e2afb6b --- /dev/null +++ b/matching/include/spdlog/details/console_globals.h @@ -0,0 +1,74 @@ +#pragma once +// +// Copyright(c) 2018 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#include "spdlog/details/null_mutex.h" +#include <cstdio> +#include <mutex> + +#ifdef _WIN32 + +#ifndef NOMINMAX +#define NOMINMAX // prevent windows redefining min/max +#endif + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#include <windows.h> +#endif + +namespace spdlog { +namespace details { +struct console_stdout +{ + static std::FILE *stream() + { + return stdout; + } +#ifdef _WIN32 + static HANDLE handle() + { + return ::GetStdHandle(STD_OUTPUT_HANDLE); + } +#endif +}; + +struct console_stderr +{ + static std::FILE *stream() + { + return stderr; + } +#ifdef _WIN32 + static HANDLE handle() + { + return ::GetStdHandle(STD_ERROR_HANDLE); + } +#endif +}; + +struct console_mutex +{ + using mutex_t = std::mutex; + static mutex_t &mutex() + { + static mutex_t s_mutex; + return s_mutex; + } +}; + +struct console_nullmutex +{ + using mutex_t = null_mutex; + static mutex_t &mutex() + { + static mutex_t s_mutex; + return s_mutex; + } +}; +} // namespace details +} // namespace spdlog diff --git a/matching/include/spdlog/details/file_helper.h b/matching/include/spdlog/details/file_helper.h new file mode 100644 index 0000000..8c1132d --- /dev/null +++ b/matching/include/spdlog/details/file_helper.h @@ -0,0 +1,152 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +// Helper class for file sinks. +// When failing to open a file, retry several times(5) with a delay interval(10 ms). +// Throw spdlog_ex exception on errors. + +#include "spdlog/details/log_msg.h" +#include "spdlog/details/os.h" + +#include <cerrno> +#include <chrono> +#include <cstdio> +#include <string> +#include <thread> +#include <tuple> + +namespace spdlog { +namespace details { + +class file_helper +{ + +public: + const int open_tries = 5; + const int open_interval = 10; + + explicit file_helper() = default; + + file_helper(const file_helper &) = delete; + file_helper &operator=(const file_helper &) = delete; + + ~file_helper() + { + close(); + } + + void open(const filename_t &fname, bool truncate = false) + { + close(); + auto *mode = truncate ? SPDLOG_FILENAME_T("wb") : SPDLOG_FILENAME_T("ab"); + _filename = fname; + for (int tries = 0; tries < open_tries; ++tries) + { + if (!os::fopen_s(&fd_, fname, mode)) + { + return; + } + + details::os::sleep_for_millis(open_interval); + } + + throw spdlog_ex("Failed opening file " + os::filename_to_str(_filename) + " for writing", errno); + } + + void reopen(bool truncate) + { + if (_filename.empty()) + { + throw spdlog_ex("Failed re opening file - was not opened before"); + } + open(_filename, truncate); + } + + void flush() + { + std::fflush(fd_); + } + + void close() + { + if (fd_ != nullptr) + { + std::fclose(fd_); + fd_ = nullptr; + } + } + + void write(const fmt::memory_buffer &buf) + { + size_t msg_size = buf.size(); + auto data = buf.data(); + if (std::fwrite(data, 1, msg_size, fd_) != msg_size) + { + throw spdlog_ex("Failed writing to file " + os::filename_to_str(_filename), errno); + } + } + + size_t size() const + { + if (fd_ == nullptr) + { + throw spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(_filename)); + } + return os::filesize(fd_); + } + + const filename_t &filename() const + { + return _filename; + } + + static bool file_exists(const filename_t &fname) + { + return os::file_exists(fname); + } + + // + // return file path and its extension: + // + // "mylog.txt" => ("mylog", ".txt") + // "mylog" => ("mylog", "") + // "mylog." => ("mylog.", "") + // "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt") + // + // the starting dot in filenames is ignored (hidden files): + // + // ".mylog" => (".mylog". "") + // "my_folder/.mylog" => ("my_folder/.mylog", "") + // "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt") + static std::tuple<filename_t, filename_t> split_by_extension(const spdlog::filename_t &fname) + { + auto ext_index = fname.rfind('.'); + + // no valid extension found - return whole path and empty string as + // extension + if (ext_index == filename_t::npos || ext_index == 0 || ext_index == fname.size() - 1) + { + return std::make_tuple(fname, spdlog::filename_t()); + } + + // treat casese like "/etc/rc.d/somelogfile or "/abc/.hiddenfile" + auto folder_index = fname.rfind(details::os::folder_sep); + if (folder_index != filename_t::npos && folder_index >= ext_index - 1) + { + return std::make_tuple(fname, spdlog::filename_t()); + } + + // finally - return a valid base and extension tuple + return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index)); + } + +private: + std::FILE *fd_{nullptr}; + filename_t _filename; +}; +} // namespace details +} // namespace spdlog diff --git a/matching/include/spdlog/details/fmt_helper.h b/matching/include/spdlog/details/fmt_helper.h new file mode 100644 index 0000000..d76aac4 --- /dev/null +++ b/matching/include/spdlog/details/fmt_helper.h @@ -0,0 +1,122 @@ +// +// Created by gabi on 6/15/18. +// + +#pragma once + +#include <chrono> +#include <type_traits> +#include "spdlog/fmt/fmt.h" + +// Some fmt helpers to efficiently format and pad ints and strings +namespace spdlog { +namespace details { +namespace fmt_helper { + +template<size_t Buffer_Size> +inline spdlog::string_view_t to_string_view(const fmt::basic_memory_buffer<char, Buffer_Size> &buf) SPDLOG_NOEXCEPT +{ + return spdlog::string_view_t(buf.data(), buf.size()); +} + +template<size_t Buffer_Size1, size_t Buffer_Size2> +inline void append_buf(const fmt::basic_memory_buffer<char, Buffer_Size1> &buf, fmt::basic_memory_buffer<char, Buffer_Size2> &dest) +{ + auto *buf_ptr = buf.data(); + dest.append(buf_ptr, buf_ptr + buf.size()); +} + +template<size_t Buffer_Size> +inline void append_string_view(spdlog::string_view_t view, fmt::basic_memory_buffer<char, Buffer_Size> &dest) +{ + auto *buf_ptr = view.data(); + if (buf_ptr != nullptr) + { + dest.append(buf_ptr, buf_ptr + view.size()); + } +} + +template<typename T, size_t Buffer_Size> +inline void append_int(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest) +{ + fmt::format_int i(n); + dest.append(i.data(), i.data() + i.size()); +} + +template<typename T> +inline unsigned count_digits(T n) +{ + using count_type = typename std::conditional<(sizeof(T) > sizeof(uint32_t)), uint64_t, uint32_t>::type; + return static_cast<unsigned>(fmt::internal::count_digits(static_cast<count_type>(n))); +} + +template<size_t Buffer_Size> +inline void pad2(int n, fmt::basic_memory_buffer<char, Buffer_Size> &dest) +{ + if (n > 99) + { + append_int(n, dest); + } + else if (n > 9) // 10-99 + { + dest.push_back(static_cast<char>('0' + n / 10)); + dest.push_back(static_cast<char>('0' + n % 10)); + } + else if (n >= 0) // 0-9 + { + dest.push_back('0'); + dest.push_back(static_cast<char>('0' + n)); + } + else // negatives (unlikely, but just in case, let fmt deal with it) + { + fmt::format_to(dest, "{:02}", n); + } +} + +template<typename T, size_t Buffer_Size> +inline void pad_uint(T n, unsigned int width, fmt::basic_memory_buffer<char, Buffer_Size> &dest) +{ + static_assert(std::is_unsigned<T>::value, "pad_uint must get unsigned T"); + auto digits = count_digits(n); + if (width > digits) + { + const char *zeroes = "0000000000000000000"; + dest.append(zeroes, zeroes + width - digits); + } + append_int(n, dest); +} + +template<typename T, size_t Buffer_Size> +inline void pad3(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest) +{ + pad_uint(n, 3, dest); +} + +template<typename T, size_t Buffer_Size> +inline void pad6(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest) +{ + pad_uint(n, 6, dest); +} + +template<typename T, size_t Buffer_Size> +inline void pad9(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest) +{ + pad_uint(n, 9, dest); +} + +// return fraction of a second of the given time_point. +// e.g. +// fraction<std::milliseconds>(tp) -> will return the millis part of the second +template<typename ToDuration> +inline ToDuration time_fraction(const log_clock::time_point &tp) +{ + using std::chrono::duration_cast; + using std::chrono::seconds; + auto duration = tp.time_since_epoch(); + auto secs = duration_cast<seconds>(duration); + return duration_cast<ToDuration>(duration) - duration_cast<ToDuration>(secs); +} + +} // namespace fmt_helper +} // namespace details +} // namespace spdlog diff --git a/matching/include/spdlog/details/log_msg.h b/matching/include/spdlog/details/log_msg.h new file mode 100644 index 0000000..69422ba --- /dev/null +++ b/matching/include/spdlog/details/log_msg.h @@ -0,0 +1,55 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#include "spdlog/common.h" +#include "spdlog/details/os.h" + +#include <string> +#include <utility> + +namespace spdlog { +namespace details { +struct log_msg +{ + + log_msg(source_loc loc, const std::string *loggers_name, level::level_enum lvl, string_view_t view) + : logger_name(loggers_name) + , level(lvl) +#ifndef SPDLOG_NO_DATETIME + , time(os::now()) +#endif + +#ifndef SPDLOG_NO_THREAD_ID + , thread_id(os::thread_id()) +#endif + , source(loc) + , payload(view) + { + } + + log_msg(const std::string *loggers_name, level::level_enum lvl, string_view_t view) + : log_msg(source_loc{}, loggers_name, lvl, view) + { + } + + log_msg(const log_msg &other) = default; + + const std::string *logger_name{nullptr}; + level::level_enum level{level::off}; + log_clock::time_point time; + size_t thread_id{0}; + size_t msg_id{0}; + + // wrapping the formatted text with color (updated by pattern_formatter). + mutable size_t color_range_start{0}; + mutable size_t color_range_end{0}; + + source_loc source; + const string_view_t payload; +}; +} // namespace details +} // namespace spdlog diff --git a/matching/include/spdlog/details/logger_impl.h b/matching/include/spdlog/details/logger_impl.h new file mode 100644 index 0000000..0212ede --- /dev/null +++ b/matching/include/spdlog/details/logger_impl.h @@ -0,0 +1,441 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#include "spdlog/details/fmt_helper.h" + +#include <memory> +#include <string> + +#define SPDLOG_CATCH_AND_HANDLE \ + catch (const std::exception &ex) \ + { \ + err_handler_(ex.what()); \ + } \ + catch (...) \ + { \ + err_handler_("Unknown exception in logger"); \ + } + +// create logger with given name, sinks and the default pattern formatter +// all other ctors will call this one +template<typename It> +inline spdlog::logger::logger(std::string logger_name, It begin, It end) + : name_(std::move(logger_name)) + , sinks_(begin, end) +{ +} + +// ctor with sinks as init list +inline spdlog::logger::logger(std::string logger_name, sinks_init_list sinks_list) + : logger(std::move(logger_name), sinks_list.begin(), sinks_list.end()) +{ +} + +// ctor with single sink +inline spdlog::logger::logger(std::string logger_name, spdlog::sink_ptr single_sink) + : logger(std::move(logger_name), {std::move(single_sink)}) +{ +} + +inline spdlog::logger::~logger() = default; + +inline void spdlog::logger::set_formatter(std::unique_ptr<spdlog::formatter> f) +{ + for (auto &sink : sinks_) + { + sink->set_formatter(f->clone()); + } +} + +inline void spdlog::logger::set_pattern(std::string pattern, pattern_time_type time_type) +{ + auto new_formatter = details::make_unique<spdlog::pattern_formatter>(std::move(pattern), time_type); + set_formatter(std::move(new_formatter)); +} + +template<typename... Args> +inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const char *fmt, const Args &... args) +{ + if (!should_log(lvl)) + { + return; + } + + try + { + using details::fmt_helper::to_string_view; + fmt::memory_buffer buf; + fmt::format_to(buf, fmt, args...); + details::log_msg log_msg(source, &name_, lvl, to_string_view(buf)); + sink_it_(log_msg); + } + SPDLOG_CATCH_AND_HANDLE +} + +template<typename... Args> +inline void spdlog::logger::log(level::level_enum lvl, const char *fmt, const Args &... args) +{ + log(source_loc{}, lvl, fmt, args...); +} + +inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const char *msg) +{ + if (!should_log(lvl)) + { + return; + } + + try + { + details::log_msg log_msg(source, &name_, lvl, spdlog::string_view_t(msg)); + sink_it_(log_msg); + } + SPDLOG_CATCH_AND_HANDLE +} + +inline void spdlog::logger::log(level::level_enum lvl, const char *msg) +{ + log(source_loc{}, lvl, msg); +} + +template<class T, typename std::enable_if<std::is_convertible<T, spdlog::string_view_t>::value, T>::type *> +inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const T &msg) +{ + if (!should_log(lvl)) + { + return; + } + try + { + details::log_msg log_msg(source, &name_, lvl, msg); + sink_it_(log_msg); + } + SPDLOG_CATCH_AND_HANDLE +} + +template<class T, typename std::enable_if<std::is_convertible<T, spdlog::string_view_t>::value, T>::type *> +inline void spdlog::logger::log(level::level_enum lvl, const T &msg) +{ + log(source_loc{}, lvl, msg); +} + +template<class T, typename std::enable_if<!std::is_convertible<T, spdlog::string_view_t>::value, T>::type *> +inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const T &msg) +{ + if (!should_log(lvl)) + { + return; + } + try + { + using details::fmt_helper::to_string_view; + fmt::memory_buffer buf; + fmt::format_to(buf, "{}", msg); + details::log_msg log_msg(source, &name_, lvl, to_string_view(buf)); + sink_it_(log_msg); + } + SPDLOG_CATCH_AND_HANDLE +} + +template<class T, typename std::enable_if<!std::is_convertible<T, spdlog::string_view_t>::value, T>::type *> +inline void spdlog::logger::log(level::level_enum lvl, const T &msg) +{ + log(source_loc{}, lvl, msg); +} + +template<typename... Args> +inline void spdlog::logger::trace(const char *fmt, const Args &... args) +{ + log(level::trace, fmt, args...); +} + +template<typename... Args> +inline void spdlog::logger::debug(const char *fmt, const Args &... args) +{ + log(level::debug, fmt, args...); +} + +template<typename... Args> +inline void spdlog::logger::info(const char *fmt, const Args &... args) +{ + log(level::info, fmt, args...); +} + +template<typename... Args> +inline void spdlog::logger::warn(const char *fmt, const Args &... args) +{ + log(level::warn, fmt, args...); +} + +template<typename... Args> +inline void spdlog::logger::error(const char *fmt, const Args &... args) +{ + log(level::err, fmt, args...); +} + +template<typename... Args> +inline void spdlog::logger::critical(const char *fmt, const Args &... args) +{ + log(level::critical, fmt, args...); +} + +template<typename T> +inline void spdlog::logger::trace(const T &msg) +{ + log(level::trace, msg); +} + +template<typename T> +inline void spdlog::logger::debug(const T &msg) +{ + log(level::debug, msg); +} + +template<typename T> +inline void spdlog::logger::info(const T &msg) +{ + log(level::info, msg); +} + +template<typename T> +inline void spdlog::logger::warn(const T &msg) +{ + log(level::warn, msg); +} + +template<typename T> +inline void spdlog::logger::error(const T &msg) +{ + log(level::err, msg); +} + +template<typename T> +inline void spdlog::logger::critical(const T &msg) +{ + log(level::critical, msg); +} + +#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT + +inline void wbuf_to_utf8buf(const fmt::wmemory_buffer &wbuf, fmt::memory_buffer &target) +{ + int wbuf_size = static_cast<int>(wbuf.size()); + if (wbuf_size == 0) + { + return; + } + + auto result_size = ::WideCharToMultiByte(CP_UTF8, 0, wbuf.data(), wbuf_size, NULL, 0, NULL, NULL); + + if (result_size > 0) + { + target.resize(result_size); + ::WideCharToMultiByte(CP_UTF8, 0, wbuf.data(), wbuf_size, &target.data()[0], result_size, NULL, NULL); + } + else + { + throw spdlog::spdlog_ex(fmt::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError())); + } +} + +template<typename... Args> +inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const wchar_t *fmt, const Args &... args) +{ + if (!should_log(lvl)) + { + return; + } + + try + { + // format to wmemory_buffer and convert to utf8 + using details::fmt_helper::to_string_view; + fmt::wmemory_buffer wbuf; + fmt::format_to(wbuf, fmt, args...); + fmt::memory_buffer buf; + wbuf_to_utf8buf(wbuf, buf); + details::log_msg log_msg(source, &name_, lvl, to_string_view(buf)); + sink_it_(log_msg); + } + SPDLOG_CATCH_AND_HANDLE +} + +template<typename... Args> +inline void spdlog::logger::log(level::level_enum lvl, const wchar_t *fmt, const Args &... args) +{ + log(source_loc{}, lvl, fmt, args...); +} + +template<typename... Args> +inline void spdlog::logger::trace(const wchar_t *fmt, const Args &... args) +{ + log(level::trace, fmt, args...); +} + +template<typename... Args> +inline void spdlog::logger::debug(const wchar_t *fmt, const Args &... args) +{ + log(level::debug, fmt, args...); +} + +template<typename... Args> +inline void spdlog::logger::info(const wchar_t *fmt, const Args &... args) +{ + log(level::info, fmt, args...); +} + +template<typename... Args> +inline void spdlog::logger::warn(const wchar_t *fmt, const Args &... args) +{ + log(level::warn, fmt, args...); +} + +template<typename... Args> +inline void spdlog::logger::error(const wchar_t *fmt, const Args &... args) +{ + log(level::err, fmt, args...); +} + +template<typename... Args> +inline void spdlog::logger::critical(const wchar_t *fmt, const Args &... args) +{ + log(level::critical, fmt, args...); +} + +#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT + +// +// name and level +// +inline const std::string &spdlog::logger::name() const +{ + return name_; +} + +inline void spdlog::logger::set_level(spdlog::level::level_enum log_level) +{ + level_.store(log_level); +} + +inline void spdlog::logger::set_error_handler(spdlog::log_err_handler err_handler) +{ + err_handler_ = std::move(err_handler); +} + +inline spdlog::log_err_handler spdlog::logger::error_handler() const +{ + return err_handler_; +} + +inline void spdlog::logger::flush() +{ + try + { + flush_(); + } + SPDLOG_CATCH_AND_HANDLE +} + +inline void spdlog::logger::flush_on(level::level_enum log_level) +{ + flush_level_.store(log_level); +} + +inline spdlog::level::level_enum spdlog::logger::flush_level() const +{ + return static_cast<spdlog::level::level_enum>(flush_level_.load(std::memory_order_relaxed)); +} + +inline bool spdlog::logger::should_flush_(const details::log_msg &msg) +{ + auto flush_level = flush_level_.load(std::memory_order_relaxed); + return (msg.level >= flush_level) && (msg.level != level::off); +} + +inline spdlog::level::level_enum spdlog::logger::default_level() +{ + return static_cast<spdlog::level::level_enum>(SPDLOG_ACTIVE_LEVEL); +} + +inline spdlog::level::level_enum spdlog::logger::level() const +{ + return static_cast<spdlog::level::level_enum>(level_.load(std::memory_order_relaxed)); +} + +inline bool spdlog::logger::should_log(spdlog::level::level_enum msg_level) const +{ + return msg_level >= level_.load(std::memory_order_relaxed); +} + +// +// protected virtual called at end of each user log call (if enabled) by the +// line_logger +// +inline void spdlog::logger::sink_it_(details::log_msg &msg) +{ +#if defined(SPDLOG_ENABLE_MESSAGE_COUNTER) + incr_msg_counter_(msg); +#endif + for (auto &sink : sinks_) + { + if (sink->should_log(msg.level)) + { + sink->log(msg); + } + } + + if (should_flush_(msg)) + { + flush_(); + } +} + +inline void spdlog::logger::flush_() +{ + for (auto &sink : sinks_) + { + sink->flush(); + } +} + +inline void spdlog::logger::default_err_handler_(const std::string &msg) +{ + auto now = time(nullptr); + if (now - last_err_time_ < 60) + { + return; + } + last_err_time_ = now; + auto tm_time = details::os::localtime(now); + char date_buf[100]; + std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time); + fmt::print(stderr, "[*** LOG ERROR ***] [{}] [{}] {}\n", date_buf, name(), msg); +} + +inline void spdlog::logger::incr_msg_counter_(details::log_msg &msg) +{ + msg.msg_id = msg_counter_.fetch_add(1, std::memory_order_relaxed); +} + +inline const std::vector<spdlog::sink_ptr> &spdlog::logger::sinks() const +{ + return sinks_; +} + +inline std::vector<spdlog::sink_ptr> &spdlog::logger::sinks() +{ + return sinks_; +} + +inline std::shared_ptr<spdlog::logger> spdlog::logger::clone(std::string logger_name) +{ + auto cloned = std::make_shared<spdlog::logger>(std::move(logger_name), sinks_.begin(), sinks_.end()); + cloned->set_level(this->level()); + cloned->flush_on(this->flush_level()); + cloned->set_error_handler(this->error_handler()); + return cloned; +} diff --git a/matching/include/spdlog/details/mpmc_blocking_q.h b/matching/include/spdlog/details/mpmc_blocking_q.h new file mode 100644 index 0000000..ca789fc --- /dev/null +++ b/matching/include/spdlog/details/mpmc_blocking_q.h @@ -0,0 +1,121 @@ +#pragma once + +// +// Copyright(c) 2018 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +// multi producer-multi consumer blocking queue. +// enqueue(..) - will block until room found to put the new message. +// enqueue_nowait(..) - will return immediately with false if no room left in +// the queue. +// dequeue_for(..) - will block until the queue is not empty or timeout have +// passed. + +#include "spdlog/details/circular_q.h" + +#include <condition_variable> +#include <mutex> + +namespace spdlog { +namespace details { + +template<typename T> +class mpmc_blocking_queue +{ +public: + using item_type = T; + explicit mpmc_blocking_queue(size_t max_items) + : q_(max_items) + { + } + +#ifndef __MINGW32__ + // try to enqueue and block if no room left + void enqueue(T &&item) + { + { + std::unique_lock<std::mutex> lock(queue_mutex_); + pop_cv_.wait(lock, [this] { return !this->q_.full(); }); + q_.push_back(std::move(item)); + } + push_cv_.notify_one(); + } + + // enqueue immediately. overrun oldest message in the queue if no room left. + void enqueue_nowait(T &&item) + { + { + std::unique_lock<std::mutex> lock(queue_mutex_); + q_.push_back(std::move(item)); + } + push_cv_.notify_one(); + } + + // try to dequeue item. if no item found. wait upto timeout and try again + // Return true, if succeeded dequeue item, false otherwise + bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration) + { + { + std::unique_lock<std::mutex> lock(queue_mutex_); + if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); })) + { + return false; + } + q_.pop_front(popped_item); + } + pop_cv_.notify_one(); + return true; + } + +#else + // apparently mingw deadlocks if the mutex is released before cv.notify_one(), + // so release the mutex at the very end each function. + + // try to enqueue and block if no room left + void enqueue(T &&item) + { + std::unique_lock<std::mutex> lock(queue_mutex_); + pop_cv_.wait(lock, [this] { return !this->q_.full(); }); + q_.push_back(std::move(item)); + push_cv_.notify_one(); + } + + // enqueue immediately. overrun oldest message in the queue if no room left. + void enqueue_nowait(T &&item) + { + std::unique_lock<std::mutex> lock(queue_mutex_); + q_.push_back(std::move(item)); + push_cv_.notify_one(); + } + + // try to dequeue item. if no item found. wait upto timeout and try again + // Return true, if succeeded dequeue item, false otherwise + bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration) + { + std::unique_lock<std::mutex> lock(queue_mutex_); + if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); })) + { + return false; + } + q_.pop_front(popped_item); + pop_cv_.notify_one(); + return true; + } + +#endif + + size_t overrun_counter() + { + std::unique_lock<std::mutex> lock(queue_mutex_); + return q_.overrun_counter(); + } + +private: + std::mutex queue_mutex_; + std::condition_variable push_cv_; + std::condition_variable pop_cv_; + spdlog::details::circular_q<T> q_; +}; +} // namespace details +} // namespace spdlog diff --git a/matching/include/spdlog/details/null_mutex.h b/matching/include/spdlog/details/null_mutex.h new file mode 100644 index 0000000..3f495bd --- /dev/null +++ b/matching/include/spdlog/details/null_mutex.h @@ -0,0 +1,45 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#include <atomic> +// null, no cost dummy "mutex" and dummy "atomic" int + +namespace spdlog { +namespace details { +struct null_mutex +{ + void lock() {} + void unlock() {} + bool try_lock() + { + return true; + } +}; + +struct null_atomic_int +{ + int value; + null_atomic_int() = default; + + explicit null_atomic_int(int val) + : value(val) + { + } + + int load(std::memory_order) const + { + return value; + } + + void store(int val) + { + value = val; + } +}; + +} // namespace details +} // namespace spdlog diff --git a/matching/include/spdlog/details/os.h b/matching/include/spdlog/details/os.h new file mode 100644 index 0000000..646805e --- /dev/null +++ b/matching/include/spdlog/details/os.h @@ -0,0 +1,421 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// +#pragma once + +#include "../common.h" + +#include <algorithm> +#include <chrono> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <ctime> +#include <functional> +#include <string> +#include <sys/stat.h> +#include <sys/types.h> +#include <thread> + +#ifdef _WIN32 + +#ifndef NOMINMAX +#define NOMINMAX // prevent windows redefining min/max +#endif + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include <io.h> // _get_osfhandle and _isatty support +#include <process.h> // _get_pid support +#include <windows.h> + +#ifdef __MINGW32__ +#include <share.h> +#endif + +#else // unix + +#include <fcntl.h> +#include <unistd.h> + +#ifdef __linux__ +#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id + +#elif __FreeBSD__ +#include <sys/thr.h> //Use thr_self() syscall under FreeBSD to get thread id +#endif + +#endif // unix + +#ifndef __has_feature // Clang - feature checking macros. +#define __has_feature(x) 0 // Compatibility with non-clang compilers. +#endif + +namespace spdlog { +namespace details { +namespace os { + +inline spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT +{ + +#if defined __linux__ && defined SPDLOG_CLOCK_COARSE + timespec ts; + ::clock_gettime(CLOCK_REALTIME_COARSE, &ts); + return std::chrono::time_point<log_clock, typename log_clock::duration>( + std::chrono::duration_cast<typename log_clock::duration>(std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec))); + +#else + return log_clock::now(); +#endif +} +inline std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT +{ + +#ifdef _WIN32 + std::tm tm; + localtime_s(&tm, &time_tt); +#else + std::tm tm; + localtime_r(&time_tt, &tm); +#endif + return tm; +} + +inline std::tm localtime() SPDLOG_NOEXCEPT +{ + std::time_t now_t = time(nullptr); + return localtime(now_t); +} + +inline std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT +{ + +#ifdef _WIN32 + std::tm tm; + gmtime_s(&tm, &time_tt); +#else + std::tm tm; + gmtime_r(&time_tt, &tm); +#endif + return tm; +} + +inline std::tm gmtime() SPDLOG_NOEXCEPT +{ + std::time_t now_t = time(nullptr); + return gmtime(now_t); +} + +// eol definition +#if !defined(SPDLOG_EOL) +#ifdef _WIN32 +#define SPDLOG_EOL "\r\n" +#else +#define SPDLOG_EOL "\n" +#endif +#endif + +SPDLOG_CONSTEXPR static const char *default_eol = SPDLOG_EOL; + +// folder separator +#ifdef _WIN32 +SPDLOG_CONSTEXPR static const char folder_sep = '\\'; +#else +SPDLOG_CONSTEXPR static const char folder_sep = '/'; +#endif + +inline void prevent_child_fd(FILE *f) +{ + +#ifdef _WIN32 +#if !defined(__cplusplus_winrt) + auto file_handle = (HANDLE)_get_osfhandle(_fileno(f)); + if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0)) + throw spdlog_ex("SetHandleInformation failed", errno); +#endif +#else + auto fd = fileno(f); + if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) + { + throw spdlog_ex("fcntl with FD_CLOEXEC failed", errno); + } +#endif +} + +// fopen_s on non windows for writing +inline bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode) +{ +#ifdef _WIN32 +#ifdef SPDLOG_WCHAR_FILENAMES + *fp = _wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO); +#else + *fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO); +#endif +#else // unix + *fp = fopen((filename.c_str()), mode.c_str()); +#endif + +#ifdef SPDLOG_PREVENT_CHILD_FD + if (*fp != nullptr) + { + prevent_child_fd(*fp); + } +#endif + return *fp == nullptr; +} + +inline int remove(const filename_t &filename) SPDLOG_NOEXCEPT +{ +#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) + return _wremove(filename.c_str()); +#else + return std::remove(filename.c_str()); +#endif +} + +inline int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT +{ +#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) + return _wrename(filename1.c_str(), filename2.c_str()); +#else + return std::rename(filename1.c_str(), filename2.c_str()); +#endif +} + +// Return if file exists +inline bool file_exists(const filename_t &filename) SPDLOG_NOEXCEPT +{ +#ifdef _WIN32 +#ifdef SPDLOG_WCHAR_FILENAMES + auto attribs = GetFileAttributesW(filename.c_str()); +#else + auto attribs = GetFileAttributesA(filename.c_str()); +#endif + return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY)); +#else // common linux/unix all have the stat system call + struct stat buffer; + return (stat(filename.c_str(), &buffer) == 0); +#endif +} + +// Return file size according to open FILE* object +inline size_t filesize(FILE *f) +{ + if (f == nullptr) + { + throw spdlog_ex("Failed getting file size. fd is null"); + } +#if defined(_WIN32) && !defined(__CYGWIN__) + int fd = _fileno(f); +#if _WIN64 // 64 bits + __int64 ret = _filelengthi64(fd); + if (ret >= 0) + { + return static_cast<size_t>(ret); + } + +#else // windows 32 bits + long ret = _filelength(fd); + if (ret >= 0) + { + return static_cast<size_t>(ret); + } +#endif + +#else // unix + int fd = fileno(f); +// 64 bits(but not in osx or cygwin, where fstat64 is deprecated) +#if !defined(__FreeBSD__) && !defined(__APPLE__) && (defined(__x86_64__) || defined(__ppc64__)) && !defined(__CYGWIN__) + struct stat64 st; + if (fstat64(fd, &st) == 0) + { + return static_cast<size_t>(st.st_size); + } +#else // unix 32 bits or cygwin + struct stat st; + + if (fstat(fd, &st) == 0) + { + return static_cast<size_t>(st.st_size); + } +#endif +#endif + throw spdlog_ex("Failed getting file size from fd", errno); +} + +// Return utc offset in minutes or throw spdlog_ex on failure +inline int utc_minutes_offset(const std::tm &tm = details::os::localtime()) +{ + +#ifdef _WIN32 +#if _WIN32_WINNT < _WIN32_WINNT_WS08 + TIME_ZONE_INFORMATION tzinfo; + auto rv = GetTimeZoneInformation(&tzinfo); +#else + DYNAMIC_TIME_ZONE_INFORMATION tzinfo; + auto rv = GetDynamicTimeZoneInformation(&tzinfo); +#endif + if (rv == TIME_ZONE_ID_INVALID) + throw spdlog::spdlog_ex("Failed getting timezone info. ", errno); + + int offset = -tzinfo.Bias; + if (tm.tm_isdst) + { + offset -= tzinfo.DaylightBias; + } + else + { + offset -= tzinfo.StandardBias; + } + return offset; +#else + +#if defined(sun) || defined(__sun) || defined(_AIX) + // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris + struct helper + { + static long int calculate_gmt_offset(const std::tm &localtm = details::os::localtime(), const std::tm &gmtm = details::os::gmtime()) + { + int local_year = localtm.tm_year + (1900 - 1); + int gmt_year = gmtm.tm_year + (1900 - 1); + + long int days = ( + // difference in day of year + localtm.tm_yday - + gmtm.tm_yday + + // + intervening leap days + + ((local_year >> 2) - (gmt_year >> 2)) - (local_year / 100 - gmt_year / 100) + + ((local_year / 100 >> 2) - (gmt_year / 100 >> 2)) + + // + difference in years * 365 */ + + (long int)(local_year - gmt_year) * 365); + + long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour); + long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min); + long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec); + + return secs; + } + }; + + auto offset_seconds = helper::calculate_gmt_offset(tm); +#else + auto offset_seconds = tm.tm_gmtoff; +#endif + + return static_cast<int>(offset_seconds / 60); +#endif +} + +// Return current thread id as size_t +// It exists because the std::this_thread::get_id() is much slower(especially +// under VS 2013) +inline size_t _thread_id() SPDLOG_NOEXCEPT +{ +#ifdef _WIN32 + return static_cast<size_t>(::GetCurrentThreadId()); +#elif __linux__ +#if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21) +#define SYS_gettid __NR_gettid +#endif + return static_cast<size_t>(syscall(SYS_gettid)); +#elif __FreeBSD__ + long tid; + thr_self(&tid); + return static_cast<size_t>(tid); +#elif __APPLE__ + uint64_t tid; + pthread_threadid_np(nullptr, &tid); + return static_cast<size_t>(tid); +#else // Default to standard C++11 (other Unix) + return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id())); +#endif +} + +// Return current thread id as size_t (from thread local storage) +inline size_t thread_id() SPDLOG_NOEXCEPT +{ +#if defined(SPDLOG_NO_TLS) + return _thread_id(); +#else // cache thread id in tls + static thread_local const size_t tid = _thread_id(); + return tid; +#endif +} + +// This is avoid msvc issue in sleep_for that happens if the clock changes. +// See https://github.com/gabime/spdlog/issues/609 +inline void sleep_for_millis(int milliseconds) SPDLOG_NOEXCEPT +{ +#if defined(_WIN32) + ::Sleep(milliseconds); +#else + std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); +#endif +} + +// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined) +#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) +#define SPDLOG_FILENAME_T(s) L##s +inline std::string filename_to_str(const filename_t &filename) +{ + std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> c; + return c.to_bytes(filename); +} +#else +#define SPDLOG_FILENAME_T(s) s +inline std::string filename_to_str(const filename_t &filename) +{ + return filename; +} +#endif + +inline int pid() +{ + +#ifdef _WIN32 + return static_cast<int>(::GetCurrentProcessId()); +#else + return static_cast<int>(::getpid()); +#endif +} + +// Determine if the terminal supports colors +// Source: https://github.com/agauniyal/rang/ +inline bool is_color_terminal() SPDLOG_NOEXCEPT +{ +#ifdef _WIN32 + return true; +#else + static constexpr const char *Terms[] = { + "ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"}; + + const char *env_p = std::getenv("TERM"); + if (env_p == nullptr) + { + return false; + } + + static const bool result = + std::any_of(std::begin(Terms), std::end(Terms), [&](const char *term) { return std::strstr(env_p, term) != nullptr; }); + return result; +#endif +} + +// Detrmine if the terminal attached +// Source: https://github.com/agauniyal/rang/ +inline bool in_terminal(FILE *file) SPDLOG_NOEXCEPT +{ + +#ifdef _WIN32 + return _isatty(_fileno(file)) != 0; +#else + return isatty(fileno(file)) != 0; +#endif +} +} // namespace os +} // namespace details +} // namespace spdlog diff --git a/matching/include/spdlog/details/pattern_formatter.h b/matching/include/spdlog/details/pattern_formatter.h new file mode 100644 index 0000000..c0ad86e --- /dev/null +++ b/matching/include/spdlog/details/pattern_formatter.h @@ -0,0 +1,1336 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#include "spdlog/details/fmt_helper.h" +#include "spdlog/details/log_msg.h" +#include "spdlog/details/os.h" +#include "spdlog/fmt/fmt.h" +#include "spdlog/formatter.h" + +#include <array> +#include <chrono> +#include <ctime> +#include <cctype> +#include <memory> +#include <mutex> +#include <string> +#include <thread> +#include <utility> +#include <vector> + +namespace spdlog { +namespace details { + +// padding information. +struct padding_info +{ + enum pad_side + { + left, + right, + center + }; + + padding_info() = default; + padding_info(size_t width, padding_info::pad_side side) + : width_(width) + , side_(side) + { + } + + bool enabled() const + { + return width_ != 0; + } + const size_t width_ = 0; + const pad_side side_ = left; +}; + +class scoped_pad +{ +public: + scoped_pad(size_t wrapped_size, padding_info &padinfo, fmt::memory_buffer &dest) + : padinfo_(padinfo) + , dest_(dest) + { + + if (padinfo_.width_ <= wrapped_size) + { + total_pad_ = 0; + return; + } + + total_pad_ = padinfo.width_ - wrapped_size; + if (padinfo_.side_ == padding_info::left) + { + pad_it(total_pad_); + total_pad_ = 0; + } + else if (padinfo_.side_ == padding_info::center) + { + auto half_pad = total_pad_ / 2; + auto reminder = total_pad_ & 1; + pad_it(half_pad); + total_pad_ = half_pad + reminder; // for the right side + } + } + + scoped_pad(spdlog::string_view_t txt, padding_info &padinfo, fmt::memory_buffer &dest) + : scoped_pad(txt.size(), padinfo, dest) + { + } + + ~scoped_pad() + { + if (total_pad_) + { + pad_it(total_pad_); + } + } + +private: + void pad_it(size_t count) + { + // count = std::min(count, spaces_.size()); + assert(count <= spaces_.size()); + fmt_helper::append_string_view(string_view_t(spaces_.data(), count), dest_); + } + + const padding_info &padinfo_; + fmt::memory_buffer &dest_; + size_t total_pad_; + string_view_t spaces_{" " + " ", + 128}; +}; + +class flag_formatter +{ +public: + explicit flag_formatter(padding_info padinfo) + : padinfo_(padinfo) + { + } + flag_formatter() = default; + virtual ~flag_formatter() = default; + virtual void format(const details::log_msg &msg, const std::tm &tm_time, fmt::memory_buffer &dest) = 0; + +protected: + padding_info padinfo_; +}; + +/////////////////////////////////////////////////////////////////////// +// name & level pattern appender +/////////////////////////////////////////////////////////////////////// +class name_formatter : public flag_formatter +{ +public: + explicit name_formatter(padding_info padinfo) + : flag_formatter(padinfo) + { + } + + void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override + { + if (padinfo_.enabled()) + { + scoped_pad p(*msg.logger_name, padinfo_, dest); + fmt_helper::append_string_view(*msg.logger_name, dest); + } + else + { + fmt_helper::append_string_view(*msg.logger_name, dest); + } + } +}; + +// log level appender +class level_formatter : public flag_formatter +{ +public: + explicit level_formatter(padding_info padinfo) + : flag_formatter(padinfo) + { + } + + void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override + { + string_view_t &level_name = level::to_string_view(msg.level); + if (padinfo_.enabled()) + { + scoped_pad p(level_name, padinfo_, dest); + fmt_helper::append_string_view(level_name, dest); + } + else + { + fmt_helper::append_string_view(level_name, dest); + } + } +}; + +// short log level appender +class short_level_formatter : public flag_formatter +{ +public: + explicit short_level_formatter(padding_info padinfo) + : flag_formatter(padinfo) + { + } + + void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override + { + string_view_t level_name{level::to_short_c_str(msg.level)}; + scoped_pad p(level_name, padinfo_, dest); + fmt_helper::append_string_view(level_name, dest); + } +}; + +/////////////////////////////////////////////////////////////////////// +// Date time pattern appenders +/////////////////////////////////////////////////////////////////////// + +static const char *ampm(const tm &t) +{ + return t.tm_hour >= 12 ? "PM" : "AM"; +} + +static int to12h(const tm &t) +{ + return t.tm_hour > 12 ? t.tm_hour - 12 : t.tm_hour; +} + +// Abbreviated weekday name +static const char *days[]{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; +class a_formatter : public flag_formatter +{ +public: + explicit a_formatter(padding_info padinfo) + : flag_formatter(padinfo) + { + } + + void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override + { + string_view_t field_value{days[tm_time.tm_wday]}; + scoped_pad p(field_value, padinfo_, dest); + fmt_helper::append_string_view(field_value, dest); + } +}; + +// Full weekday name +static const char *full_days[]{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; +class A_formatter : public flag_formatter +{ +public: + explicit A_formatter(padding_info padinfo) + : flag_formatter(padinfo) + { + } + + void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override + { + string_view_t field_value{full_days[tm_time.tm_wday]}; + scoped_pad p(field_value, padinfo_, dest); + fmt_helper::append_string_view(field_value, dest); + } +}; + +// Abbreviated month +static const char *months[]{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"}; +class b_formatter : public flag_formatter +{ +public: + explicit b_formatter(padding_info padinfo) + : flag_formatter(padinfo) + { + } + + void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override + { + string_view_t field_value{months[tm_time.tm_mon]}; + scoped_pad p(field_value, padinfo_, dest); + fmt_helper::append_string_view(field_value, dest); + } +}; + +// Full month name +static const char *full_months[]{ + "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; +class B_formatter : public flag_formatter +{ +public: + explicit B_formatter(padding_info padinfo) + : flag_formatter(padinfo) + { + } + + void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override + { + string_view_t field_value{full_months[tm_time.tm_mon]}; + scoped_pad p(field_value, padinfo_, dest); + fmt_helper::append_string_view(field_value, dest); + } +}; + +// Date and time representation (Thu Aug 23 15:35:46 2014) +class c_formatter final : public flag_formatter +{ +public: + explicit c_formatter(padding_info padinfo) + : flag_formatter(padinfo) + { + } + + void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override + { + const size_t field_size = 24; + scoped_pad p(field_size, padinfo_, dest); + + fmt_helper::append_string_view(days[tm_time.tm_wday], dest); + dest.push_back(' '); + fmt_helper::append_string_view(months[tm_time.tm_mon], dest); + dest.push_back(' '); + fmt_helper::append_int(tm_time.tm_mday, dest); + dest.push_back(' '); + // time + + fmt_helper::pad2(tm_time.tm_hour, dest); + dest.push_back(':'); + fmt_helper::pad2(tm_time.tm_min, dest); + dest.push_back(':'); + fmt_helper::pad2(tm_time.tm_sec, dest); + dest.push_back(' '); + fmt_helper::append_int(tm_time.tm_year + 1900, dest); + } +}; + +// year - 2 digit +class C_formatter final : public flag_formatter +{ +public: + explicit C_formatter(padding_info padinfo) + : flag_formatter(padinfo) + { + } + + void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override + { + const size_t field_size = 2; + scoped_pad p(field_size, padinfo_, dest); + fmt_helper::pad2(tm_time.tm_year % 100, dest); + } +}; + +// Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01 +class D_formatter final : public flag_formatter +{ +public: + explicit D_formatter(padding_info padinfo) + : flag_formatter(padinfo) + { + } + + void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override + { + const size_t field_size = 10; + scoped_pad p(field_size, padinfo_, dest); + + fmt_helper::pad2(tm_time.tm_mon + 1, dest); + dest.push_back('/'); + fmt_helper::pad2(tm_time.tm_mday, dest); + dest.push_back('/'); + fmt_helper::pad2(tm_time.tm_year % 100, dest); + } +}; + +// year - 4 digit +class Y_formatter final : public flag_formatter +{ +public: + explicit Y_formatter(padding_info padinfo) + : flag_formatter(padinfo){}; + + void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override + { + const size_t field_size = 4; + scoped_pad p(field_size, padinfo_, dest); + fmt_helper::append_int(tm_time.tm_year + 1900, dest); + } +}; + +// month 1-12 +class m_formatter final : public flag_formatter +{ +public: + explicit m_formatter(padding_info padinfo) + : flag_formatter(padinfo) + { + } + + void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override + { + const size_t field_size = 2; + scoped_pad p(field_size, padinfo_, dest); + fmt_helper::pad2(tm_time.tm_mon + 1, dest); + } +}; + +// day of month 1-31 +class d_formatter final : public flag_formatter +{ +public: + explicit d_formatter(padding_info padinfo) + : flag_formatter(padinfo) + { + } + + void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override + { + const size_t field_size = 2; + scoped_pad p(field_size, padinfo_, dest); + fmt_helper::pad2(tm_time.tm_mday, dest); + } +}; + +// hours in 24 format 0-23 +class H_formatter final : public flag_formatter +{ +public: + explicit H_formatter(padding_info padinfo) + : flag_formatter(padinfo) + { + } + + void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override + { + const size_t field_size = 2; + scoped_pad p(field_size, padinfo_, dest); + fmt_helper::pad2(tm_time.tm_hour, dest); + } +}; + +// hours in 12 format 1-12 +class I_formatter final : public flag_formatter +{ +public: + explicit I_formatter(padding_info padinfo) + : flag_formatter(padinfo){}; + + void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override + { + const size_t field_size = 2; + scoped_pad p(field_size, padinfo_, dest); + fmt_helper::pad2(to12h(tm_time), dest); + } +}; + +// minutes 0-59 +class M_formatter final : public flag_formatter +{ +public: + explicit M_formatter(padding_info padinfo) + : flag_formatter(padinfo){}; + + void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override + { + const size_t field_size = 2; + scoped_pad p(field_size, padinfo_, dest); + fmt_helper::pad2(tm_time.tm_min, dest); + } +}; + +// seconds 0-59 +class S_formatter final : public flag_formatter +{ +public: + explicit S_formatter(padding_info padinfo) + : flag_formatter(padinfo){}; + + void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override + { + const size_t field_size = 2; + scoped_pad p(field_size, padinfo_, dest); + fmt_helper::pad2(tm_time.tm_sec, dest); + } +}; + +// milliseconds +class e_formatter final : public flag_formatter +{ +public: + explicit e_formatter(padding_info padinfo) + : flag_formatter(padinfo){}; + + void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override + { + auto millis = fmt_helper::time_fraction<std::chrono::milliseconds>(msg.time); + if (padinfo_.enabled()) + { + const size_t field_size = 3; + scoped_pad p(field_size, padinfo_, dest); + fmt_helper::pad3(static_cast<uint32_t>(millis.count()), dest); + } + else + { + fmt_helper::pad3(static_cast<uint32_t>(millis.count()), dest); + } + } +}; + +// microseconds +class f_formatter final : public flag_formatter +{ +public: + explicit f_formatter(padding_info padinfo) + : flag_formatter(padinfo){}; + + void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override + { + auto micros = fmt_helper::time_fraction<std::chrono::microseconds>(msg.time); + if (padinfo_.enabled()) + { + const size_t field_size = 6; + scoped_pad p(field_size, padinfo_, dest); + fmt_helper::pad6(static_cast<size_t>(micros.count()), dest); + } + else + { + fmt_helper::pad6(static_cast<size_t>(micros.count()), dest); + } + } +}; + +// nanoseconds +class F_formatter final : public flag_formatter +{ +public: + explicit F_formatter(padding_info padinfo) + : flag_formatter(padinfo){}; + + void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override + { + auto ns = fmt_helper::time_fraction<std::chrono::nanoseconds>(msg.time); + if (padinfo_.enabled()) + { + const size_t field_size = 9; + scoped_pad p(field_size, padinfo_, dest); + fmt_helper::pad9(static_cast<size_t>(ns.count()), dest); + } + else + { + fmt_helper::pad9(static_cast<size_t>(ns.count()), dest); + } + } +}; + +// seconds since epoch +class E_formatter final : public flag_formatter +{ +public: + explicit E_formatter(padding_info padinfo) + : flag_formatter(padinfo){}; + + void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override + { + const size_t field_size = 10; + scoped_pad p(field_size, padinfo_, dest); + auto duration = msg.time.time_since_epoch(); + auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration).count(); + fmt_helper::append_int(seconds, dest); + } +}; + +// AM/PM +class p_formatter final : public flag_formatter +{ +public: + explicit p_formatter(padding_info padinfo) + : flag_formatter(padinfo){}; + + void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override + { + const size_t field_size = 2; + scoped_pad p(field_size, padinfo_, dest); + fmt_helper::append_string_view(ampm(tm_time), dest); + } +}; + +// 12 hour clock 02:55:02 pm +class r_formatter final : public flag_formatter +{ +public: + explicit r_formatter(padding_info padinfo) + : flag_formatter(padinfo){}; + + void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override + { + const size_t field_size = 11; + scoped_pad p(field_size, padinfo_, dest); + + fmt_helper::pad2(to12h(tm_time), dest); + dest.push_back(':'); + fmt_helper::pad2(tm_time.tm_min, dest); + dest.push_back(':'); + fmt_helper::pad2(tm_time.tm_sec, dest); + dest.push_back(' '); + fmt_helper::append_string_view(ampm(tm_time), dest); + } +}; + +// 24-hour HH:MM time, equivalent to %H:%M +class R_formatter final : public flag_formatter +{ +public: + explicit R_formatter(padding_info padinfo) + : flag_formatter(padinfo){}; + + void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override + { + const size_t field_size = 5; + scoped_pad p(field_size, padinfo_, dest); + + fmt_helper::pad2(tm_time.tm_hour, dest); + dest.push_back(':'); + fmt_helper::pad2(tm_time.tm_min, dest); + } +}; + +// ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S +class T_formatter final : public flag_formatter +{ +public: + explicit T_formatter(padding_info padinfo) + : flag_formatter(padinfo){}; + + void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override + { + const size_t field_size = 8; + scoped_pad p(field_size, padinfo_, dest); + + fmt_helper::pad2(tm_time.tm_hour, dest); + dest.push_back(':'); + fmt_helper::pad2(tm_time.tm_min, dest); + dest.push_back(':'); + fmt_helper::pad2(tm_time.tm_sec, dest); + } +}; + +// ISO 8601 offset from UTC in timezone (+-HH:MM) +class z_formatter final : public flag_formatter +{ +public: + explicit z_formatter(padding_info padinfo) + : flag_formatter(padinfo){}; + + const std::chrono::seconds cache_refresh = std::chrono::seconds(5); + + z_formatter() = default; + z_formatter(const z_formatter &) = delete; + z_formatter &operator=(const z_formatter &) = delete; + + void format(const details::log_msg &msg, const std::tm &tm_time, fmt::memory_buffer &dest) override + { + const size_t field_size = 6; + scoped_pad p(field_size, padinfo_, dest); + +#ifdef _WIN32 + int total_minutes = get_cached_offset(msg, tm_time); +#else + // No need to chache under gcc, + // it is very fast (already stored in tm.tm_gmtoff) + (void)(msg); + int total_minutes = os::utc_minutes_offset(tm_time); +#endif + bool is_negative = total_minutes < 0; + if (is_negative) + { + total_minutes = -total_minutes; + dest.push_back('-'); + } + else + { + dest.push_back('+'); + } + + fmt_helper::pad2(total_minutes / 60, dest); // hours + dest.push_back(':'); + fmt_helper::pad2(total_minutes % 60, dest); // minutes + } + +private: + log_clock::time_point last_update_{std::chrono::seconds(0)}; +#ifdef _WIN32 + int offset_minutes_{0}; + + int get_cached_offset(const log_msg &msg, const std::tm &tm_time) + { + if (msg.time - last_update_ >= cache_refresh) + { + offset_minutes_ = os::utc_minutes_offset(tm_time); + last_update_ = msg.time; + } + return offset_minutes_; + } +#endif +}; + +// Thread id +class t_formatter final : public flag_formatter +{ +public: + explicit t_formatter(padding_info padinfo) + : flag_formatter(padinfo){}; + + void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override + { + if (padinfo_.enabled()) + { + const auto field_size = fmt_helper::count_digits(msg.thread_id); + scoped_pad p(field_size, padinfo_, dest); + fmt_helper::append_int(msg.thread_id, dest); + } + else + { + fmt_helper::append_int(msg.thread_id, dest); + } + } +}; + +// Current pid +class pid_formatter final : public flag_formatter +{ +public: + explicit pid_formatter(padding_info padinfo) + : flag_formatter(padinfo){}; + + void format(const details::log_msg &, const std::tm &, fmt::memory_buffer &dest) override + { + const auto pid = static_cast<uint32_t>(details::os::pid()); + if (padinfo_.enabled()) + { + auto field_size = fmt_helper::count_digits(pid); + scoped_pad p(field_size, padinfo_, dest); + fmt_helper::append_int(pid, dest); + } + else + { + fmt_helper::append_int(pid, dest); + } + } +}; + +// message counter formatter +class i_formatter final : public flag_formatter +{ +public: + explicit i_formatter(padding_info padinfo) + : flag_formatter(padinfo){}; + + void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override + { + const size_t field_size = 6; + scoped_pad p(field_size, padinfo_, dest); + fmt_helper::pad6(msg.msg_id, dest); + } +}; + +class v_formatter final : public flag_formatter +{ +public: + explicit v_formatter(padding_info padinfo) + : flag_formatter(padinfo){}; + + void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override + { + if (padinfo_.enabled()) + { + scoped_pad p(msg.payload, padinfo_, dest); + fmt_helper::append_string_view(msg.payload, dest); + } + else + { + fmt_helper::append_string_view(msg.payload, dest); + } + } +}; + +class ch_formatter final : public flag_formatter +{ +public: + explicit ch_formatter(char ch) + : ch_(ch) + { + } + + void format(const details::log_msg &, const std::tm &, fmt::memory_buffer &dest) override + { + const size_t field_size = 1; + scoped_pad p(field_size, padinfo_, dest); + dest.push_back(ch_); + } + +private: + char ch_; +}; + +// aggregate user chars to display as is +class aggregate_formatter final : public flag_formatter +{ +public: + aggregate_formatter() = default; + + void add_ch(char ch) + { + str_ += ch; + } + void format(const details::log_msg &, const std::tm &, fmt::memory_buffer &dest) override + { + fmt_helper::append_string_view(str_, dest); + } + +private: + std::string str_; +}; + +// mark the color range. expect it to be in the form of "%^colored text%$" +class color_start_formatter final : public flag_formatter +{ +public: + explicit color_start_formatter(padding_info padinfo) + : flag_formatter(padinfo) + { + } + + void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override + { + msg.color_range_start = dest.size(); + } +}; +class color_stop_formatter final : public flag_formatter +{ +public: + explicit color_stop_formatter(padding_info padinfo) + : flag_formatter(padinfo) + { + } + + void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override + { + msg.color_range_end = dest.size(); + } +}; + +// print source location +class source_location_formatter final : public flag_formatter +{ +public: + explicit source_location_formatter(padding_info padinfo) + : flag_formatter(padinfo){}; + + void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override + { + if (msg.source.empty()) + { + return; + } + if (padinfo_.enabled()) + { + const auto text_size = std::char_traits<char>::length(msg.source.filename) + fmt_helper::count_digits(msg.source.line) + 1; + scoped_pad p(text_size, padinfo_, dest); + fmt_helper::append_string_view(msg.source.filename, dest); + dest.push_back(':'); + fmt_helper::append_int(msg.source.line, dest); + } + else + { + fmt_helper::append_string_view(msg.source.filename, dest); + dest.push_back(':'); + fmt_helper::append_int(msg.source.line, dest); + } + } +}; +// print source filename +class source_filename_formatter final : public flag_formatter +{ +public: + explicit source_filename_formatter(padding_info padinfo) + : flag_formatter(padinfo){}; + + void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override + { + if (msg.source.empty()) + { + return; + } + scoped_pad p(msg.source.filename, padinfo_, dest); + fmt_helper::append_string_view(msg.source.filename, dest); + } +}; + +class source_linenum_formatter final : public flag_formatter +{ +public: + explicit source_linenum_formatter(padding_info padinfo) + : flag_formatter(padinfo){}; + + void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override + { + if (msg.source.empty()) + { + return; + } + if (padinfo_.enabled()) + { + auto field_size = fmt_helper::count_digits(msg.source.line); + scoped_pad p(field_size, padinfo_, dest); + fmt_helper::append_int(msg.source.line, dest); + } + else + { + fmt_helper::append_int(msg.source.line, dest); + } + } +}; +// print source funcname +class source_funcname_formatter final : public flag_formatter +{ +public: + explicit source_funcname_formatter(padding_info padinfo) + : flag_formatter(padinfo){}; + + void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override + { + if (msg.source.empty()) + { + return; + } + scoped_pad p(msg.source.funcname, padinfo_, dest); + fmt_helper::append_string_view(msg.source.funcname, dest); + } +}; + +// Full info formatter +// pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v +class full_formatter final : public flag_formatter +{ +public: + explicit full_formatter(padding_info padinfo) + : flag_formatter(padinfo) + { + } + + void format(const details::log_msg &msg, const std::tm &tm_time, fmt::memory_buffer &dest) override + { + using std::chrono::duration_cast; + using std::chrono::milliseconds; + using std::chrono::seconds; + +#ifndef SPDLOG_NO_DATETIME + + // cache the date/time part for the next second. + auto duration = msg.time.time_since_epoch(); + auto secs = duration_cast<seconds>(duration); + + if (cache_timestamp_ != secs || cached_datetime_.size() == 0) + { + cached_datetime_.clear(); + cached_datetime_.push_back('['); + fmt_helper::append_int(tm_time.tm_year + 1900, cached_datetime_); + cached_datetime_.push_back('-'); + + fmt_helper::pad2(tm_time.tm_mon + 1, cached_datetime_); + cached_datetime_.push_back('-'); + + fmt_helper::pad2(tm_time.tm_mday, cached_datetime_); + cached_datetime_.push_back(' '); + + fmt_helper::pad2(tm_time.tm_hour, cached_datetime_); + cached_datetime_.push_back(':'); + + fmt_helper::pad2(tm_time.tm_min, cached_datetime_); + cached_datetime_.push_back(':'); + + fmt_helper::pad2(tm_time.tm_sec, cached_datetime_); + cached_datetime_.push_back('.'); + + cache_timestamp_ = secs; + } + fmt_helper::append_buf(cached_datetime_, dest); + + auto millis = fmt_helper::time_fraction<milliseconds>(msg.time); + fmt_helper::pad3(static_cast<uint32_t>(millis.count()), dest); + dest.push_back(']'); + dest.push_back(' '); + +#else // no datetime needed + (void)tm_time; +#endif + +#ifndef SPDLOG_NO_NAME + if (!msg.logger_name->empty()) + { + dest.push_back('['); + // fmt_helper::append_str(*msg.logger_name, dest); + fmt_helper::append_string_view(*msg.logger_name, dest); + dest.push_back(']'); + dest.push_back(' '); + } +#endif + + dest.push_back('['); + // wrap the level name with color + msg.color_range_start = dest.size(); + // fmt_helper::append_string_view(level::to_c_str(msg.level), dest); + fmt_helper::append_string_view(level::to_string_view(msg.level), dest); + msg.color_range_end = dest.size(); + dest.push_back(']'); + dest.push_back(' '); + + // add source location if present + if (!msg.source.empty()) + { + dest.push_back('['); + fmt_helper::append_string_view(msg.source.filename, dest); + dest.push_back(':'); + fmt_helper::append_int(msg.source.line, dest); + dest.push_back(']'); + dest.push_back(' '); + } + // fmt_helper::append_string_view(msg.msg(), dest); + fmt_helper::append_string_view(msg.payload, dest); + } + +private: + std::chrono::seconds cache_timestamp_{0}; + fmt::basic_memory_buffer<char, 128> cached_datetime_; +}; + +} // namespace details + +class pattern_formatter final : public formatter +{ +public: + explicit pattern_formatter( + std::string pattern, pattern_time_type time_type = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol) + : pattern_(std::move(pattern)) + , eol_(std::move(eol)) + , pattern_time_type_(time_type) + , last_log_secs_(0) + { + std::memset(&cached_tm_, 0, sizeof(cached_tm_)); + compile_pattern_(pattern_); + } + + // use by default full formatter for if pattern is not given + explicit pattern_formatter(pattern_time_type time_type = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol) + : pattern_("%+") + , eol_(std::move(eol)) + , pattern_time_type_(time_type) + , last_log_secs_(0) + { + std::memset(&cached_tm_, 0, sizeof(cached_tm_)); + formatters_.push_back(details::make_unique<details::full_formatter>(details::padding_info{})); + } + + pattern_formatter(const pattern_formatter &other) = delete; + pattern_formatter &operator=(const pattern_formatter &other) = delete; + + std::unique_ptr<formatter> clone() const override + { + return details::make_unique<pattern_formatter>(pattern_, pattern_time_type_, eol_); + } + + void format(const details::log_msg &msg, fmt::memory_buffer &dest) override + { +#ifndef SPDLOG_NO_DATETIME + auto secs = std::chrono::duration_cast<std::chrono::seconds>(msg.time.time_since_epoch()); + if (secs != last_log_secs_) + { + cached_tm_ = get_time_(msg); + last_log_secs_ = secs; + } +#endif + for (auto &f : formatters_) + { + f->format(msg, cached_tm_, dest); + } + // write eol + details::fmt_helper::append_string_view(eol_, dest); + } + +private: + std::string pattern_; + std::string eol_; + pattern_time_type pattern_time_type_; + std::tm cached_tm_; + std::chrono::seconds last_log_secs_; + + std::vector<std::unique_ptr<details::flag_formatter>> formatters_; + + std::tm get_time_(const details::log_msg &msg) + { + if (pattern_time_type_ == pattern_time_type::local) + { + return details::os::localtime(log_clock::to_time_t(msg.time)); + } + return details::os::gmtime(log_clock::to_time_t(msg.time)); + } + + void handle_flag_(char flag, details::padding_info padding) + { + switch (flag) + { + + case ('+'): // default formatter + formatters_.push_back(details::make_unique<details::full_formatter>(padding)); + break; + + case 'n': // logger name + formatters_.push_back(details::make_unique<details::name_formatter>(padding)); + break; + + case 'l': // level + formatters_.push_back(details::make_unique<details::level_formatter>(padding)); + break; + + case 'L': // short level + formatters_.push_back(details::make_unique<details::short_level_formatter>(padding)); + break; + + case ('t'): // thread id + formatters_.push_back(details::make_unique<details::t_formatter>(padding)); + break; + + case ('v'): // the message text + formatters_.push_back(details::make_unique<details::v_formatter>(padding)); + break; + + case ('a'): // weekday + formatters_.push_back(details::make_unique<details::a_formatter>(padding)); + break; + + case ('A'): // short weekday + formatters_.push_back(details::make_unique<details::A_formatter>(padding)); + break; + + case ('b'): + case ('h'): // month + formatters_.push_back(details::make_unique<details::b_formatter>(padding)); + break; + + case ('B'): // short month + formatters_.push_back(details::make_unique<details::B_formatter>(padding)); + break; + + case ('c'): // datetime + formatters_.push_back(details::make_unique<details::c_formatter>(padding)); + break; + + case ('C'): // year 2 digits + formatters_.push_back(details::make_unique<details::C_formatter>(padding)); + break; + + case ('Y'): // year 4 digits + formatters_.push_back(details::make_unique<details::Y_formatter>(padding)); + break; + + case ('D'): + case ('x'): // datetime MM/DD/YY + formatters_.push_back(details::make_unique<details::D_formatter>(padding)); + break; + + case ('m'): // month 1-12 + formatters_.push_back(details::make_unique<details::m_formatter>(padding)); + break; + + case ('d'): // day of month 1-31 + formatters_.push_back(details::make_unique<details::d_formatter>(padding)); + break; + + case ('H'): // hours 24 + formatters_.push_back(details::make_unique<details::H_formatter>(padding)); + break; + + case ('I'): // hours 12 + formatters_.push_back(details::make_unique<details::I_formatter>(padding)); + break; + + case ('M'): // minutes + formatters_.push_back(details::make_unique<details::M_formatter>(padding)); + break; + + case ('S'): // seconds + formatters_.push_back(details::make_unique<details::S_formatter>(padding)); + break; + + case ('e'): // milliseconds + formatters_.push_back(details::make_unique<details::e_formatter>(padding)); + break; + + case ('f'): // microseconds + formatters_.push_back(details::make_unique<details::f_formatter>(padding)); + break; + + case ('F'): // nanoseconds + formatters_.push_back(details::make_unique<details::F_formatter>(padding)); + break; + + case ('E'): // seconds since epoch + formatters_.push_back(details::make_unique<details::E_formatter>(padding)); + break; + + case ('p'): // am/pm + formatters_.push_back(details::make_unique<details::p_formatter>(padding)); + break; + + case ('r'): // 12 hour clock 02:55:02 pm + formatters_.push_back(details::make_unique<details::r_formatter>(padding)); + break; + + case ('R'): // 24-hour HH:MM time + formatters_.push_back(details::make_unique<details::R_formatter>(padding)); + break; + + case ('T'): + case ('X'): // ISO 8601 time format (HH:MM:SS) + formatters_.push_back(details::make_unique<details::T_formatter>(padding)); + break; + + case ('z'): // timezone + formatters_.push_back(details::make_unique<details::z_formatter>(padding)); + break; + + case ('P'): // pid + formatters_.push_back(details::make_unique<details::pid_formatter>(padding)); + break; + +#ifdef SPDLOG_ENABLE_MESSAGE_COUNTER + case ('i'): + formatters_.push_back(details::make_unique<details::i_formatter>(padding)); + break; +#endif + case ('^'): // color range start + formatters_.push_back(details::make_unique<details::color_start_formatter>(padding)); + break; + + case ('$'): // color range end + formatters_.push_back(details::make_unique<details::color_stop_formatter>(padding)); + break; + + case ('@'): // source location (filename:filenumber) + formatters_.push_back(details::make_unique<details::source_location_formatter>(padding)); + break; + + case ('s'): // source filename + formatters_.push_back(details::make_unique<details::source_filename_formatter>(padding)); + break; + + case ('#'): // source line number + formatters_.push_back(details::make_unique<details::source_linenum_formatter>(padding)); + break; + + case ('!'): // source funcname + formatters_.push_back(details::make_unique<details::source_funcname_formatter>(padding)); + break; + + case ('%'): // % char + formatters_.push_back(details::make_unique<details::ch_formatter>('%')); + break; + + default: // Unknown flag appears as is + auto unknown_flag = details::make_unique<details::aggregate_formatter>(); + unknown_flag->add_ch('%'); + unknown_flag->add_ch(flag); + formatters_.push_back((std::move(unknown_flag))); + break; + } + } + + // Extract given pad spec (e.g. %8X) + // Advance the given it pass the end of the padding spec found (if any) + // Return padding. + details::padding_info handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end) + { + using details::padding_info; + using details::scoped_pad; + const size_t max_width = 128; + if (it == end) + { + return padding_info{}; + } + + padding_info::pad_side side; + switch (*it) + { + case '-': + side = padding_info::right; + ++it; + break; + case '=': + side = padding_info::center; + ++it; + break; + default: + side = details::padding_info::left; + break; + } + + if (it == end || !std::isdigit(static_cast<unsigned char>(*it))) + { + return padding_info{0, side}; + } + + auto width = static_cast<size_t>(*it - '0'); + for (++it; it != end && std::isdigit(static_cast<unsigned char>(*it)); ++it) + { + auto digit = static_cast<size_t>(*it - '0'); + width = width * 10 + digit; + } + return details::padding_info{std::min<size_t>(width, max_width), side}; + } + + void compile_pattern_(const std::string &pattern) + { + auto end = pattern.end(); + std::unique_ptr<details::aggregate_formatter> user_chars; + formatters_.clear(); + for (auto it = pattern.begin(); it != end; ++it) + { + if (*it == '%') + { + if (user_chars) // append user chars found so far + { + formatters_.push_back(std::move(user_chars)); + } + + auto padding = handle_padspec_(++it, end); + + if (it != end) + { + handle_flag_(*it, padding); + } + else + { + break; + } + } + else // chars not following the % sign should be displayed as is + { + if (!user_chars) + { + user_chars = details::make_unique<details::aggregate_formatter>(); + } + user_chars->add_ch(*it); + } + } + if (user_chars) // append raw chars found so far + { + formatters_.push_back(std::move(user_chars)); + } + } +}; +} // namespace spdlog diff --git a/matching/include/spdlog/details/periodic_worker.h b/matching/include/spdlog/details/periodic_worker.h new file mode 100644 index 0000000..fa6488d --- /dev/null +++ b/matching/include/spdlog/details/periodic_worker.h @@ -0,0 +1,71 @@ + +// +// Copyright(c) 2018 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +// periodic worker thread - periodically executes the given callback function. +// +// RAII over the owned thread: +// creates the thread on construction. +// stops and joins the thread on destruction (if the thread is executing a callback, wait for it to finish first). + +#include <chrono> +#include <condition_variable> +#include <functional> +#include <mutex> +#include <thread> +namespace spdlog { +namespace details { + +class periodic_worker +{ +public: + periodic_worker(const std::function<void()> &callback_fun, std::chrono::seconds interval) + { + active_ = (interval > std::chrono::seconds::zero()); + if (!active_) + { + return; + } + + worker_thread_ = std::thread([this, callback_fun, interval]() { + for (;;) + { + std::unique_lock<std::mutex> lock(this->mutex_); + if (this->cv_.wait_for(lock, interval, [this] { return !this->active_; })) + { + return; // active_ == false, so exit this thread + } + callback_fun(); + } + }); + } + + periodic_worker(const periodic_worker &) = delete; + periodic_worker &operator=(const periodic_worker &) = delete; + + // stop the worker thread and join it + ~periodic_worker() + { + if (worker_thread_.joinable()) + { + { + std::lock_guard<std::mutex> lock(mutex_); + active_ = false; + } + cv_.notify_one(); + worker_thread_.join(); + } + } + +private: + bool active_; + std::thread worker_thread_; + std::mutex mutex_; + std::condition_variable cv_; +}; +} // namespace details +} // namespace spdlog diff --git a/matching/include/spdlog/details/registry.h b/matching/include/spdlog/details/registry.h new file mode 100644 index 0000000..ccd5395 --- /dev/null +++ b/matching/include/spdlog/details/registry.h @@ -0,0 +1,285 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +// Loggers registy of unique name->logger pointer +// An attempt to create a logger with an already existing name will be ignored +// If user requests a non existing logger, nullptr will be returned +// This class is thread safe + +#include "spdlog/common.h" +#include "spdlog/details/periodic_worker.h" +#include "spdlog/logger.h" + +#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER +// support for the default stdout color logger +#ifdef _WIN32 +#include "spdlog/sinks/wincolor_sink.h" +#else +#include "spdlog/sinks/ansicolor_sink.h" +#endif +#endif // SPDLOG_DISABLE_DEFAULT_LOGGER + +#include <chrono> +#include <functional> +#include <memory> +#include <string> +#include <unordered_map> + +namespace spdlog { +namespace details { +class thread_pool; + +class registry +{ +public: + registry(const registry &) = delete; + registry &operator=(const registry &) = delete; + + void register_logger(std::shared_ptr<logger> new_logger) + { + std::lock_guard<std::mutex> lock(logger_map_mutex_); + register_logger_(std::move(new_logger)); + } + + void initialize_logger(std::shared_ptr<logger> new_logger) + { + std::lock_guard<std::mutex> lock(logger_map_mutex_); + new_logger->set_formatter(formatter_->clone()); + + if (err_handler_) + { + new_logger->set_error_handler(err_handler_); + } + + new_logger->set_level(level_); + new_logger->flush_on(flush_level_); + + if (automatic_registration_) + { + register_logger_(std::move(new_logger)); + } + } + + std::shared_ptr<logger> get(const std::string &logger_name) + { + std::lock_guard<std::mutex> lock(logger_map_mutex_); + auto found = loggers_.find(logger_name); + return found == loggers_.end() ? nullptr : found->second; + } + + std::shared_ptr<logger> default_logger() + { + std::lock_guard<std::mutex> lock(logger_map_mutex_); + return default_logger_; + } + + // Return raw ptr to the default logger. + // To be used directly by the spdlog default api (e.g. spdlog::info) + // This make the default API faster, but cannot be used concurrently with set_default_logger(). + // e.g do not call set_default_logger() from one thread while calling spdlog::info() from another. + logger *get_default_raw() + { + return default_logger_.get(); + } + + // set default logger. + // default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map. + void set_default_logger(std::shared_ptr<logger> new_default_logger) + { + std::lock_guard<std::mutex> lock(logger_map_mutex_); + // remove previous default logger from the map + if (default_logger_ != nullptr) + { + loggers_.erase(default_logger_->name()); + } + if (new_default_logger != nullptr) + { + loggers_[new_default_logger->name()] = new_default_logger; + } + default_logger_ = std::move(new_default_logger); + } + + void set_tp(std::shared_ptr<thread_pool> tp) + { + std::lock_guard<std::recursive_mutex> lock(tp_mutex_); + tp_ = std::move(tp); + } + + std::shared_ptr<thread_pool> get_tp() + { + std::lock_guard<std::recursive_mutex> lock(tp_mutex_); + return tp_; + } + + // Set global formatter. Each sink in each logger will get a clone of this object + void set_formatter(std::unique_ptr<formatter> formatter) + { + std::lock_guard<std::mutex> lock(logger_map_mutex_); + formatter_ = std::move(formatter); + for (auto &l : loggers_) + { + l.second->set_formatter(formatter_->clone()); + } + } + + void set_level(level::level_enum log_level) + { + std::lock_guard<std::mutex> lock(logger_map_mutex_); + for (auto &l : loggers_) + { + l.second->set_level(log_level); + } + level_ = log_level; + } + + void flush_on(level::level_enum log_level) + { + std::lock_guard<std::mutex> lock(logger_map_mutex_); + for (auto &l : loggers_) + { + l.second->flush_on(log_level); + } + flush_level_ = log_level; + } + + void flush_every(std::chrono::seconds interval) + { + std::lock_guard<std::mutex> lock(flusher_mutex_); + std::function<void()> clbk = std::bind(®istry::flush_all, this); + periodic_flusher_ = details::make_unique<periodic_worker>(clbk, interval); + } + + void set_error_handler(log_err_handler handler) + { + std::lock_guard<std::mutex> lock(logger_map_mutex_); + for (auto &l : loggers_) + { + l.second->set_error_handler(handler); + } + err_handler_ = handler; + } + + void apply_all(const std::function<void(const std::shared_ptr<logger>)> &fun) + { + std::lock_guard<std::mutex> lock(logger_map_mutex_); + for (auto &l : loggers_) + { + fun(l.second); + } + } + + void flush_all() + { + std::lock_guard<std::mutex> lock(logger_map_mutex_); + for (auto &l : loggers_) + { + l.second->flush(); + } + } + + void drop(const std::string &logger_name) + { + std::lock_guard<std::mutex> lock(logger_map_mutex_); + loggers_.erase(logger_name); + if (default_logger_ && default_logger_->name() == logger_name) + { + default_logger_.reset(); + } + } + + void drop_all() + { + std::lock_guard<std::mutex> lock(logger_map_mutex_); + loggers_.clear(); + default_logger_.reset(); + } + + // clean all resources and threads started by the registry + void shutdown() + { + { + std::lock_guard<std::mutex> lock(flusher_mutex_); + periodic_flusher_.reset(); + } + + drop_all(); + + { + std::lock_guard<std::recursive_mutex> lock(tp_mutex_); + tp_.reset(); + } + } + + std::recursive_mutex &tp_mutex() + { + return tp_mutex_; + } + + void set_automatic_registration(bool automatic_regsistration) + { + std::lock_guard<std::mutex> lock(logger_map_mutex_); + automatic_registration_ = automatic_regsistration; + } + + static registry &instance() + { + static registry s_instance; + return s_instance; + } + +private: + registry() + : formatter_(new pattern_formatter()) + { + +#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER + // create default logger (ansicolor_stdout_sink_mt or wincolor_stdout_sink_mt in windows). +#ifdef _WIN32 + auto color_sink = std::make_shared<sinks::wincolor_stdout_sink_mt>(); +#else + auto color_sink = std::make_shared<sinks::ansicolor_stdout_sink_mt>(); +#endif + + const char *default_logger_name = ""; + default_logger_ = std::make_shared<spdlog::logger>(default_logger_name, std::move(color_sink)); + loggers_[default_logger_name] = default_logger_; + +#endif // SPDLOG_DISABLE_DEFAULT_LOGGER + } + + ~registry() = default; + + void throw_if_exists_(const std::string &logger_name) + { + if (loggers_.find(logger_name) != loggers_.end()) + { + throw spdlog_ex("logger with name '" + logger_name + "' already exists"); + } + } + + void register_logger_(std::shared_ptr<logger> new_logger) + { + auto logger_name = new_logger->name(); + throw_if_exists_(logger_name); + loggers_[logger_name] = std::move(new_logger); + } + + std::mutex logger_map_mutex_, flusher_mutex_; + std::recursive_mutex tp_mutex_; + std::unordered_map<std::string, std::shared_ptr<logger>> loggers_; + std::unique_ptr<formatter> formatter_; + level::level_enum level_ = spdlog::logger::default_level(); + level::level_enum flush_level_ = level::off; + log_err_handler err_handler_; + std::shared_ptr<thread_pool> tp_; + std::unique_ptr<periodic_worker> periodic_flusher_; + std::shared_ptr<logger> default_logger_; + bool automatic_registration_ = true; +}; + +} // namespace details +} // namespace spdlog diff --git a/matching/include/spdlog/details/thread_pool.h b/matching/include/spdlog/details/thread_pool.h new file mode 100644 index 0000000..3557897 --- /dev/null +++ b/matching/include/spdlog/details/thread_pool.h @@ -0,0 +1,238 @@ +#pragma once + +#include "spdlog/details/fmt_helper.h" +#include "spdlog/details/log_msg.h" +#include "spdlog/details/mpmc_blocking_q.h" +#include "spdlog/details/os.h" + +#include <chrono> +#include <memory> +#include <thread> +#include <vector> + +namespace spdlog { +namespace details { + +using async_logger_ptr = std::shared_ptr<spdlog::async_logger>; + +enum class async_msg_type +{ + log, + flush, + terminate +}; + +// Async msg to move to/from the queue +// Movable only. should never be copied +struct async_msg +{ + async_msg_type msg_type; + level::level_enum level; + log_clock::time_point time; + size_t thread_id; + fmt::basic_memory_buffer<char, 176> raw; + + size_t msg_id; + source_loc source; + async_logger_ptr worker_ptr; + + async_msg() = default; + ~async_msg() = default; + + // should only be moved in or out of the queue.. + async_msg(const async_msg &) = delete; + +// support for vs2013 move +#if defined(_MSC_VER) && _MSC_VER <= 1800 + async_msg(async_msg &&other) SPDLOG_NOEXCEPT : msg_type(other.msg_type), + level(other.level), + time(other.time), + thread_id(other.thread_id), + raw(move(other.raw)), + msg_id(other.msg_id), + source(other.source), + worker_ptr(std::move(other.worker_ptr)) + { + } + + async_msg &operator=(async_msg &&other) SPDLOG_NOEXCEPT + { + msg_type = other.msg_type; + level = other.level; + time = other.time; + thread_id = other.thread_id; + raw = std::move(other.raw); + msg_id = other.msg_id; + source = other.source; + worker_ptr = std::move(other.worker_ptr); + return *this; + } +#else // (_MSC_VER) && _MSC_VER <= 1800 + async_msg(async_msg &&) = default; + async_msg &operator=(async_msg &&) = default; +#endif + + // construct from log_msg with given type + async_msg(async_logger_ptr &&worker, async_msg_type the_type, details::log_msg &m) + : msg_type(the_type) + , level(m.level) + , time(m.time) + , thread_id(m.thread_id) + , msg_id(m.msg_id) + , source(m.source) + , worker_ptr(std::move(worker)) + { + fmt_helper::append_string_view(m.payload, raw); + } + + async_msg(async_logger_ptr &&worker, async_msg_type the_type) + : msg_type(the_type) + , level(level::off) + , time() + , thread_id(0) + , msg_id(0) + , source() + , worker_ptr(std::move(worker)) + { + } + + explicit async_msg(async_msg_type the_type) + : async_msg(nullptr, the_type) + { + } + + // copy into log_msg + log_msg to_log_msg() + { + log_msg msg(&worker_ptr->name(), level, string_view_t(raw.data(), raw.size())); + msg.time = time; + msg.thread_id = thread_id; + msg.msg_id = msg_id; + msg.source = source; + msg.color_range_start = 0; + msg.color_range_end = 0; + return msg; + } +}; + +class thread_pool +{ +public: + using item_type = async_msg; + using q_type = details::mpmc_blocking_queue<item_type>; + + thread_pool(size_t q_max_items, size_t threads_n) + : q_(q_max_items) + { + // std::cout << "thread_pool() q_size_bytes: " << q_size_bytes << + // "\tthreads_n: " << threads_n << std::endl; + if (threads_n == 0 || threads_n > 1000) + { + throw spdlog_ex("spdlog::thread_pool(): invalid threads_n param (valid " + "range is 1-1000)"); + } + for (size_t i = 0; i < threads_n; i++) + { + threads_.emplace_back(&thread_pool::worker_loop_, this); + } + } + + // message all threads to terminate gracefully join them + ~thread_pool() + { + try + { + for (size_t i = 0; i < threads_.size(); i++) + { + post_async_msg_(async_msg(async_msg_type::terminate), async_overflow_policy::block); + } + + for (auto &t : threads_) + { + t.join(); + } + } + catch (...) + { + } + } + + thread_pool(const thread_pool &) = delete; + thread_pool &operator=(thread_pool &&) = delete; + + void post_log(async_logger_ptr &&worker_ptr, details::log_msg &msg, async_overflow_policy overflow_policy) + { + async_msg async_m(std::move(worker_ptr), async_msg_type::log, msg); + post_async_msg_(std::move(async_m), overflow_policy); + } + + void post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy) + { + post_async_msg_(async_msg(std::move(worker_ptr), async_msg_type::flush), overflow_policy); + } + + size_t overrun_counter() + { + return q_.overrun_counter(); + } + +private: + q_type q_; + + std::vector<std::thread> threads_; + + void post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy) + { + if (overflow_policy == async_overflow_policy::block) + { + q_.enqueue(std::move(new_msg)); + } + else + { + q_.enqueue_nowait(std::move(new_msg)); + } + } + + void worker_loop_() + { + while (process_next_msg_()) {}; + } + + // process next message in the queue + // return true if this thread should still be active (while no terminate msg + // was received) + bool process_next_msg_() + { + async_msg incoming_async_msg; + bool dequeued = q_.dequeue_for(incoming_async_msg, std::chrono::seconds(10)); + if (!dequeued) + { + return true; + } + + switch (incoming_async_msg.msg_type) + { + case async_msg_type::log: + { + auto msg = incoming_async_msg.to_log_msg(); + incoming_async_msg.worker_ptr->backend_log_(msg); + return true; + } + case async_msg_type::flush: + { + incoming_async_msg.worker_ptr->backend_flush_(); + return true; + } + + case async_msg_type::terminate: + { + return false; + } + } + assert(false && "Unexpected async_msg_type"); + return true; + } +}; + +} // namespace details +} // namespace spdlog diff --git a/matching/include/spdlog/fmt/bin_to_hex.h b/matching/include/spdlog/fmt/bin_to_hex.h new file mode 100644 index 0000000..3523380 --- /dev/null +++ b/matching/include/spdlog/fmt/bin_to_hex.h @@ -0,0 +1,172 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +// +// Support for logging binary data as hex +// format flags: +// {:X} - print in uppercase. +// {:s} - don't separate each byte with space. +// {:p} - don't print the position on each line start. +// {:n} - don't split the output to lines. + +// +// Examples: +// +// std::vector<char> v(200, 0x0b); +// logger->info("Some buffer {}", spdlog::to_hex(v)); +// char buf[128]; +// logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf))); + +namespace spdlog { +namespace details { + +template<typename It> +class bytes_range +{ +public: + bytes_range(It range_begin, It range_end) + : begin_(range_begin) + , end_(range_end) + { + } + + It begin() const + { + return begin_; + } + It end() const + { + return end_; + } + +private: + It begin_, end_; +}; +} // namespace details + +// create a bytes_range that wraps the given container +template<typename Container> +inline details::bytes_range<typename Container::const_iterator> to_hex(const Container &container) +{ + static_assert(sizeof(typename Container::value_type) == 1, "sizeof(Container::value_type) != 1"); + using Iter = typename Container::const_iterator; + return details::bytes_range<Iter>(std::begin(container), std::end(container)); +} + +// create bytes_range from ranges +template<typename It> +inline details::bytes_range<It> to_hex(const It range_begin, const It range_end) +{ + return details::bytes_range<It>(range_begin, range_end); +} + +} // namespace spdlog + +namespace fmt { + +template<typename T> +struct formatter<spdlog::details::bytes_range<T>> +{ + const std::size_t line_size = 100; + const char delimiter = ' '; + + bool put_newlines = true; + bool put_delimiters = true; + bool use_uppercase = false; + bool put_positions = true; // position on start of each line + + // parse the format string flags + template<typename ParseContext> + auto parse(ParseContext &ctx) -> decltype(ctx.begin()) + { + auto it = ctx.begin(); + while (*it && *it != '}') + { + switch (*it) + { + case 'X': + use_uppercase = true; + break; + case 's': + put_delimiters = false; + break; + case 'p': + put_positions = false; + break; + case 'n': + put_newlines = false; + break; + } + + ++it; + } + return it; + } + + // format the given bytes range as hex + template<typename FormatContext, typename Container> + auto format(const spdlog::details::bytes_range<Container> &the_range, FormatContext &ctx) -> decltype(ctx.out()) + { + SPDLOG_CONSTEXPR const char *hex_upper = "0123456789ABCDEF"; + SPDLOG_CONSTEXPR const char *hex_lower = "0123456789abcdef"; + const char *hex_chars = use_uppercase ? hex_upper : hex_lower; + + std::size_t pos = 0; + std::size_t column = line_size; + auto inserter = ctx.begin(); + + for (auto &item : the_range) + { + auto ch = static_cast<unsigned char>(item); + pos++; + + if (put_newlines && column >= line_size) + { + column = put_newline(inserter, pos); + + // put first byte without delimiter in front of it + *inserter++ = hex_chars[(ch >> 4) & 0x0f]; + *inserter++ = hex_chars[ch & 0x0f]; + column += 2; + continue; + } + + if (put_delimiters) + { + *inserter++ = delimiter; + ++column; + } + + *inserter++ = hex_chars[(ch >> 4) & 0x0f]; + *inserter++ = hex_chars[ch & 0x0f]; + column += 2; + } + return inserter; + } + + // put newline(and position header) + // return the next column + template<typename It> + std::size_t put_newline(It inserter, std::size_t pos) + { +#ifdef _WIN32 + *inserter++ = '\r'; +#endif + *inserter++ = '\n'; + + if (put_positions) + { + fmt::format_to(inserter, "{:<04X}: ", pos - 1); + return 7; + } + else + { + return 1; + } + } +}; +} // namespace fmt diff --git a/matching/include/spdlog/fmt/bundled/LICENSE.rst b/matching/include/spdlog/fmt/bundled/LICENSE.rst new file mode 100644 index 0000000..eb6be65 --- /dev/null +++ b/matching/include/spdlog/fmt/bundled/LICENSE.rst @@ -0,0 +1,23 @@ +Copyright (c) 2012 - 2016, Victor Zverovich + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/matching/include/spdlog/fmt/bundled/chrono.h b/matching/include/spdlog/fmt/bundled/chrono.h new file mode 100644 index 0000000..209cdc2 --- /dev/null +++ b/matching/include/spdlog/fmt/bundled/chrono.h @@ -0,0 +1,452 @@ +// Formatting library for C++ - chrono support +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_CHRONO_H_ +#define FMT_CHRONO_H_ + +#include "format.h" +#include "locale.h" + +#include <chrono> +#include <ctime> +#include <locale> +#include <sstream> + +FMT_BEGIN_NAMESPACE + +namespace internal{ + +enum class numeric_system { + standard, + // Alternative numeric system, e.g. 十二 instead of 12 in ja_JP locale. + alternative +}; + +// Parses a put_time-like format string and invokes handler actions. +template <typename Char, typename Handler> +FMT_CONSTEXPR const Char *parse_chrono_format( + const Char *begin, const Char *end, Handler &&handler) { + auto ptr = begin; + while (ptr != end) { + auto c = *ptr; + if (c == '}') break; + if (c != '%') { + ++ptr; + continue; + } + if (begin != ptr) + handler.on_text(begin, ptr); + ++ptr; // consume '%' + if (ptr == end) + throw format_error("invalid format"); + c = *ptr++; + switch (c) { + case '%': + handler.on_text(ptr - 1, ptr); + break; + case 'n': { + const char newline[] = "\n"; + handler.on_text(newline, newline + 1); + break; + } + case 't': { + const char tab[] = "\t"; + handler.on_text(tab, tab + 1); + break; + } + // Day of the week: + case 'a': + handler.on_abbr_weekday(); + break; + case 'A': + handler.on_full_weekday(); + break; + case 'w': + handler.on_dec0_weekday(numeric_system::standard); + break; + case 'u': + handler.on_dec1_weekday(numeric_system::standard); + break; + // Month: + case 'b': + handler.on_abbr_month(); + break; + case 'B': + handler.on_full_month(); + break; + // Hour, minute, second: + case 'H': + handler.on_24_hour(numeric_system::standard); + break; + case 'I': + handler.on_12_hour(numeric_system::standard); + break; + case 'M': + handler.on_minute(numeric_system::standard); + break; + case 'S': + handler.on_second(numeric_system::standard); + break; + // Other: + case 'c': + handler.on_datetime(numeric_system::standard); + break; + case 'x': + handler.on_loc_date(numeric_system::standard); + break; + case 'X': + handler.on_loc_time(numeric_system::standard); + break; + case 'D': + handler.on_us_date(); + break; + case 'F': + handler.on_iso_date(); + break; + case 'r': + handler.on_12_hour_time(); + break; + case 'R': + handler.on_24_hour_time(); + break; + case 'T': + handler.on_iso_time(); + break; + case 'p': + handler.on_am_pm(); + break; + case 'z': + handler.on_utc_offset(); + break; + case 'Z': + handler.on_tz_name(); + break; + // Alternative representation: + case 'E': { + if (ptr == end) + throw format_error("invalid format"); + c = *ptr++; + switch (c) { + case 'c': + handler.on_datetime(numeric_system::alternative); + break; + case 'x': + handler.on_loc_date(numeric_system::alternative); + break; + case 'X': + handler.on_loc_time(numeric_system::alternative); + break; + default: + throw format_error("invalid format"); + } + break; + } + case 'O': + if (ptr == end) + throw format_error("invalid format"); + c = *ptr++; + switch (c) { + case 'w': + handler.on_dec0_weekday(numeric_system::alternative); + break; + case 'u': + handler.on_dec1_weekday(numeric_system::alternative); + break; + case 'H': + handler.on_24_hour(numeric_system::alternative); + break; + case 'I': + handler.on_12_hour(numeric_system::alternative); + break; + case 'M': + handler.on_minute(numeric_system::alternative); + break; + case 'S': + handler.on_second(numeric_system::alternative); + break; + default: + throw format_error("invalid format"); + } + break; + default: + throw format_error("invalid format"); + } + begin = ptr; + } + if (begin != ptr) + handler.on_text(begin, ptr); + return ptr; +} + +struct chrono_format_checker { + void report_no_date() { throw format_error("no date"); } + + template <typename Char> + void on_text(const Char *, const Char *) {} + void on_abbr_weekday() { report_no_date(); } + void on_full_weekday() { report_no_date(); } + void on_dec0_weekday(numeric_system) { report_no_date(); } + void on_dec1_weekday(numeric_system) { report_no_date(); } + void on_abbr_month() { report_no_date(); } + void on_full_month() { report_no_date(); } + void on_24_hour(numeric_system) {} + void on_12_hour(numeric_system) {} + void on_minute(numeric_system) {} + void on_second(numeric_system) {} + void on_datetime(numeric_system) { report_no_date(); } + void on_loc_date(numeric_system) { report_no_date(); } + void on_loc_time(numeric_system) { report_no_date(); } + void on_us_date() { report_no_date(); } + void on_iso_date() { report_no_date(); } + void on_12_hour_time() {} + void on_24_hour_time() {} + void on_iso_time() {} + void on_am_pm() {} + void on_utc_offset() { report_no_date(); } + void on_tz_name() { report_no_date(); } +}; + +template <typename Int> +inline int to_int(Int value) { + FMT_ASSERT(value >= (std::numeric_limits<int>::min)() && + value <= (std::numeric_limits<int>::max)(), "invalid value"); + return static_cast<int>(value); +} + +template <typename FormatContext, typename OutputIt> +struct chrono_formatter { + FormatContext &context; + OutputIt out; + std::chrono::seconds s; + std::chrono::milliseconds ms; + + typedef typename FormatContext::char_type char_type; + + explicit chrono_formatter(FormatContext &ctx, OutputIt o) + : context(ctx), out(o) {} + + int hour() const { return to_int((s.count() / 3600) % 24); } + + int hour12() const { + auto hour = to_int((s.count() / 3600) % 12); + return hour > 0 ? hour : 12; + } + + int minute() const { return to_int((s.count() / 60) % 60); } + int second() const { return to_int(s.count() % 60); } + + std::tm time() const { + auto time = std::tm(); + time.tm_hour = hour(); + time.tm_min = minute(); + time.tm_sec = second(); + return time; + } + + void write(int value, int width) { + typedef typename int_traits<int>::main_type main_type; + main_type n = to_unsigned(value); + int num_digits = internal::count_digits(n); + if (width > num_digits) + out = std::fill_n(out, width - num_digits, '0'); + out = format_decimal<char_type>(out, n, num_digits); + } + + void format_localized(const tm &time, const char *format) { + auto locale = context.locale().template get<std::locale>(); + auto &facet = std::use_facet<std::time_put<char_type>>(locale); + std::basic_ostringstream<char_type> os; + os.imbue(locale); + facet.put(os, os, ' ', &time, format, format + std::strlen(format)); + auto str = os.str(); + std::copy(str.begin(), str.end(), out); + } + + void on_text(const char_type *begin, const char_type *end) { + std::copy(begin, end, out); + } + + // These are not implemented because durations don't have date information. + void on_abbr_weekday() {} + void on_full_weekday() {} + void on_dec0_weekday(numeric_system) {} + void on_dec1_weekday(numeric_system) {} + void on_abbr_month() {} + void on_full_month() {} + void on_datetime(numeric_system) {} + void on_loc_date(numeric_system) {} + void on_loc_time(numeric_system) {} + void on_us_date() {} + void on_iso_date() {} + void on_utc_offset() {} + void on_tz_name() {} + + void on_24_hour(numeric_system ns) { + if (ns == numeric_system::standard) + return write(hour(), 2); + auto time = tm(); + time.tm_hour = hour(); + format_localized(time, "%OH"); + } + + void on_12_hour(numeric_system ns) { + if (ns == numeric_system::standard) + return write(hour12(), 2); + auto time = tm(); + time.tm_hour = hour(); + format_localized(time, "%OI"); + } + + void on_minute(numeric_system ns) { + if (ns == numeric_system::standard) + return write(minute(), 2); + auto time = tm(); + time.tm_min = minute(); + format_localized(time, "%OM"); + } + + void on_second(numeric_system ns) { + if (ns == numeric_system::standard) { + write(second(), 2); + if (ms != std::chrono::milliseconds(0)) { + *out++ = '.'; + write(to_int(ms.count()), 3); + } + return; + } + auto time = tm(); + time.tm_sec = second(); + format_localized(time, "%OS"); + } + + void on_12_hour_time() { format_localized(time(), "%r"); } + + void on_24_hour_time() { + write(hour(), 2); + *out++ = ':'; + write(minute(), 2); + } + + void on_iso_time() { + on_24_hour_time(); + *out++ = ':'; + write(second(), 2); + } + + void on_am_pm() { format_localized(time(), "%p"); } +}; +} // namespace internal + +template <typename Period> FMT_CONSTEXPR const char *get_units() { + return FMT_NULL; +} +template <> FMT_CONSTEXPR const char *get_units<std::atto>() { return "as"; } +template <> FMT_CONSTEXPR const char *get_units<std::femto>() { return "fs"; } +template <> FMT_CONSTEXPR const char *get_units<std::pico>() { return "ps"; } +template <> FMT_CONSTEXPR const char *get_units<std::nano>() { return "ns"; } +template <> FMT_CONSTEXPR const char *get_units<std::micro>() { return "µs"; } +template <> FMT_CONSTEXPR const char *get_units<std::milli>() { return "ms"; } +template <> FMT_CONSTEXPR const char *get_units<std::centi>() { return "cs"; } +template <> FMT_CONSTEXPR const char *get_units<std::deci>() { return "ds"; } +template <> FMT_CONSTEXPR const char *get_units<std::ratio<1>>() { return "s"; } +template <> FMT_CONSTEXPR const char *get_units<std::deca>() { return "das"; } +template <> FMT_CONSTEXPR const char *get_units<std::hecto>() { return "hs"; } +template <> FMT_CONSTEXPR const char *get_units<std::kilo>() { return "ks"; } +template <> FMT_CONSTEXPR const char *get_units<std::mega>() { return "Ms"; } +template <> FMT_CONSTEXPR const char *get_units<std::giga>() { return "Gs"; } +template <> FMT_CONSTEXPR const char *get_units<std::tera>() { return "Ts"; } +template <> FMT_CONSTEXPR const char *get_units<std::peta>() { return "Ps"; } +template <> FMT_CONSTEXPR const char *get_units<std::exa>() { return "Es"; } +template <> FMT_CONSTEXPR const char *get_units<std::ratio<60>>() { + return "m"; +} +template <> FMT_CONSTEXPR const char *get_units<std::ratio<3600>>() { + return "h"; +} + +template <typename Rep, typename Period, typename Char> +struct formatter<std::chrono::duration<Rep, Period>, Char> { + private: + align_spec spec; + internal::arg_ref<Char> width_ref; + mutable basic_string_view<Char> format_str; + typedef std::chrono::duration<Rep, Period> duration; + + struct spec_handler { + formatter &f; + basic_parse_context<Char> &context; + + typedef internal::arg_ref<Char> arg_ref_type; + + template <typename Id> + FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) { + context.check_arg_id(arg_id); + return arg_ref_type(arg_id); + } + + FMT_CONSTEXPR arg_ref_type make_arg_ref(internal::auto_id) { + return arg_ref_type(context.next_arg_id()); + } + + void on_error(const char *msg) { throw format_error(msg); } + void on_fill(Char fill) { f.spec.fill_ = fill; } + void on_align(alignment align) { f.spec.align_ = align; } + void on_width(unsigned width) { f.spec.width_ = width; } + + template <typename Id> + void on_dynamic_width(Id arg_id) { + f.width_ref = make_arg_ref(arg_id); + } + }; + + public: + formatter() : spec() {} + + FMT_CONSTEXPR auto parse(basic_parse_context<Char> &ctx) + -> decltype(ctx.begin()) { + auto begin = ctx.begin(), end = ctx.end(); + if (begin == end) return begin; + spec_handler handler{*this, ctx}; + begin = internal::parse_align(begin, end, handler); + if (begin == end) return begin; + begin = internal::parse_width(begin, end, handler); + end = parse_chrono_format(begin, end, internal::chrono_format_checker()); + format_str = basic_string_view<Char>(&*begin, internal::to_unsigned(end - begin)); + return end; + } + + template <typename FormatContext> + auto format(const duration &d, FormatContext &ctx) + -> decltype(ctx.out()) { + auto begin = format_str.begin(), end = format_str.end(); + memory_buffer buf; + typedef output_range<decltype(ctx.out()), Char> range; + basic_writer<range> w(range(ctx.out())); + if (begin == end || *begin == '}') { + if (const char *unit = get_units<Period>()) + format_to(buf, "{}{}", d.count(), unit); + else if (Period::den == 1) + format_to(buf, "{}[{}]s", d.count(), Period::num); + else + format_to(buf, "{}[{}/{}]s", d.count(), Period::num, Period::den); + internal::handle_dynamic_spec<internal::width_checker>( + spec.width_, width_ref, ctx); + } else { + auto out = std::back_inserter(buf); + internal::chrono_formatter<FormatContext, decltype(out)> f(ctx, out); + f.s = std::chrono::duration_cast<std::chrono::seconds>(d); + f.ms = std::chrono::duration_cast<std::chrono::milliseconds>(d - f.s); + parse_chrono_format(begin, end, f); + } + w.write(buf.data(), buf.size(), spec); + return w.out(); + } +}; + +FMT_END_NAMESPACE + +#endif // FMT_CHRONO_H_ diff --git a/matching/include/spdlog/fmt/bundled/color.h b/matching/include/spdlog/fmt/bundled/color.h new file mode 100644 index 0000000..5db861c --- /dev/null +++ b/matching/include/spdlog/fmt/bundled/color.h @@ -0,0 +1,577 @@ +// Formatting library for C++ - color support +// +// Copyright (c) 2018 - present, Victor Zverovich and fmt contributors +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_COLOR_H_ +#define FMT_COLOR_H_ + +#include "format.h" + +FMT_BEGIN_NAMESPACE + +#ifdef FMT_DEPRECATED_COLORS + +// color and (v)print_colored are deprecated. +enum color { black, red, green, yellow, blue, magenta, cyan, white }; +FMT_API void vprint_colored(color c, string_view format, format_args args); +FMT_API void vprint_colored(color c, wstring_view format, wformat_args args); +template <typename... Args> +inline void print_colored(color c, string_view format_str, + const Args & ... args) { + vprint_colored(c, format_str, make_format_args(args...)); +} +template <typename... Args> +inline void print_colored(color c, wstring_view format_str, + const Args & ... args) { + vprint_colored(c, format_str, make_format_args<wformat_context>(args...)); +} + +inline void vprint_colored(color c, string_view format, format_args args) { + char escape[] = "\x1b[30m"; + escape[3] = static_cast<char>('0' + c); + std::fputs(escape, stdout); + vprint(format, args); + std::fputs(internal::data::RESET_COLOR, stdout); +} + +inline void vprint_colored(color c, wstring_view format, wformat_args args) { + wchar_t escape[] = L"\x1b[30m"; + escape[3] = static_cast<wchar_t>('0' + c); + std::fputws(escape, stdout); + vprint(format, args); + std::fputws(internal::data::WRESET_COLOR, stdout); +} + +#else + +enum class color : uint32_t { + alice_blue = 0xF0F8FF, // rgb(240,248,255) + antique_white = 0xFAEBD7, // rgb(250,235,215) + aqua = 0x00FFFF, // rgb(0,255,255) + aquamarine = 0x7FFFD4, // rgb(127,255,212) + azure = 0xF0FFFF, // rgb(240,255,255) + beige = 0xF5F5DC, // rgb(245,245,220) + bisque = 0xFFE4C4, // rgb(255,228,196) + black = 0x000000, // rgb(0,0,0) + blanched_almond = 0xFFEBCD, // rgb(255,235,205) + blue = 0x0000FF, // rgb(0,0,255) + blue_violet = 0x8A2BE2, // rgb(138,43,226) + brown = 0xA52A2A, // rgb(165,42,42) + burly_wood = 0xDEB887, // rgb(222,184,135) + cadet_blue = 0x5F9EA0, // rgb(95,158,160) + chartreuse = 0x7FFF00, // rgb(127,255,0) + chocolate = 0xD2691E, // rgb(210,105,30) + coral = 0xFF7F50, // rgb(255,127,80) + cornflower_blue = 0x6495ED, // rgb(100,149,237) + cornsilk = 0xFFF8DC, // rgb(255,248,220) + crimson = 0xDC143C, // rgb(220,20,60) + cyan = 0x00FFFF, // rgb(0,255,255) + dark_blue = 0x00008B, // rgb(0,0,139) + dark_cyan = 0x008B8B, // rgb(0,139,139) + dark_golden_rod = 0xB8860B, // rgb(184,134,11) + dark_gray = 0xA9A9A9, // rgb(169,169,169) + dark_green = 0x006400, // rgb(0,100,0) + dark_khaki = 0xBDB76B, // rgb(189,183,107) + dark_magenta = 0x8B008B, // rgb(139,0,139) + dark_olive_green = 0x556B2F, // rgb(85,107,47) + dark_orange = 0xFF8C00, // rgb(255,140,0) + dark_orchid = 0x9932CC, // rgb(153,50,204) + dark_red = 0x8B0000, // rgb(139,0,0) + dark_salmon = 0xE9967A, // rgb(233,150,122) + dark_sea_green = 0x8FBC8F, // rgb(143,188,143) + dark_slate_blue = 0x483D8B, // rgb(72,61,139) + dark_slate_gray = 0x2F4F4F, // rgb(47,79,79) + dark_turquoise = 0x00CED1, // rgb(0,206,209) + dark_violet = 0x9400D3, // rgb(148,0,211) + deep_pink = 0xFF1493, // rgb(255,20,147) + deep_sky_blue = 0x00BFFF, // rgb(0,191,255) + dim_gray = 0x696969, // rgb(105,105,105) + dodger_blue = 0x1E90FF, // rgb(30,144,255) + fire_brick = 0xB22222, // rgb(178,34,34) + floral_white = 0xFFFAF0, // rgb(255,250,240) + forest_green = 0x228B22, // rgb(34,139,34) + fuchsia = 0xFF00FF, // rgb(255,0,255) + gainsboro = 0xDCDCDC, // rgb(220,220,220) + ghost_white = 0xF8F8FF, // rgb(248,248,255) + gold = 0xFFD700, // rgb(255,215,0) + golden_rod = 0xDAA520, // rgb(218,165,32) + gray = 0x808080, // rgb(128,128,128) + green = 0x008000, // rgb(0,128,0) + green_yellow = 0xADFF2F, // rgb(173,255,47) + honey_dew = 0xF0FFF0, // rgb(240,255,240) + hot_pink = 0xFF69B4, // rgb(255,105,180) + indian_red = 0xCD5C5C, // rgb(205,92,92) + indigo = 0x4B0082, // rgb(75,0,130) + ivory = 0xFFFFF0, // rgb(255,255,240) + khaki = 0xF0E68C, // rgb(240,230,140) + lavender = 0xE6E6FA, // rgb(230,230,250) + lavender_blush = 0xFFF0F5, // rgb(255,240,245) + lawn_green = 0x7CFC00, // rgb(124,252,0) + lemon_chiffon = 0xFFFACD, // rgb(255,250,205) + light_blue = 0xADD8E6, // rgb(173,216,230) + light_coral = 0xF08080, // rgb(240,128,128) + light_cyan = 0xE0FFFF, // rgb(224,255,255) + light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210) + light_gray = 0xD3D3D3, // rgb(211,211,211) + light_green = 0x90EE90, // rgb(144,238,144) + light_pink = 0xFFB6C1, // rgb(255,182,193) + light_salmon = 0xFFA07A, // rgb(255,160,122) + light_sea_green = 0x20B2AA, // rgb(32,178,170) + light_sky_blue = 0x87CEFA, // rgb(135,206,250) + light_slate_gray = 0x778899, // rgb(119,136,153) + light_steel_blue = 0xB0C4DE, // rgb(176,196,222) + light_yellow = 0xFFFFE0, // rgb(255,255,224) + lime = 0x00FF00, // rgb(0,255,0) + lime_green = 0x32CD32, // rgb(50,205,50) + linen = 0xFAF0E6, // rgb(250,240,230) + magenta = 0xFF00FF, // rgb(255,0,255) + maroon = 0x800000, // rgb(128,0,0) + medium_aquamarine = 0x66CDAA, // rgb(102,205,170) + medium_blue = 0x0000CD, // rgb(0,0,205) + medium_orchid = 0xBA55D3, // rgb(186,85,211) + medium_purple = 0x9370DB, // rgb(147,112,219) + medium_sea_green = 0x3CB371, // rgb(60,179,113) + medium_slate_blue = 0x7B68EE, // rgb(123,104,238) + medium_spring_green = 0x00FA9A, // rgb(0,250,154) + medium_turquoise = 0x48D1CC, // rgb(72,209,204) + medium_violet_red = 0xC71585, // rgb(199,21,133) + midnight_blue = 0x191970, // rgb(25,25,112) + mint_cream = 0xF5FFFA, // rgb(245,255,250) + misty_rose = 0xFFE4E1, // rgb(255,228,225) + moccasin = 0xFFE4B5, // rgb(255,228,181) + navajo_white = 0xFFDEAD, // rgb(255,222,173) + navy = 0x000080, // rgb(0,0,128) + old_lace = 0xFDF5E6, // rgb(253,245,230) + olive = 0x808000, // rgb(128,128,0) + olive_drab = 0x6B8E23, // rgb(107,142,35) + orange = 0xFFA500, // rgb(255,165,0) + orange_red = 0xFF4500, // rgb(255,69,0) + orchid = 0xDA70D6, // rgb(218,112,214) + pale_golden_rod = 0xEEE8AA, // rgb(238,232,170) + pale_green = 0x98FB98, // rgb(152,251,152) + pale_turquoise = 0xAFEEEE, // rgb(175,238,238) + pale_violet_red = 0xDB7093, // rgb(219,112,147) + papaya_whip = 0xFFEFD5, // rgb(255,239,213) + peach_puff = 0xFFDAB9, // rgb(255,218,185) + peru = 0xCD853F, // rgb(205,133,63) + pink = 0xFFC0CB, // rgb(255,192,203) + plum = 0xDDA0DD, // rgb(221,160,221) + powder_blue = 0xB0E0E6, // rgb(176,224,230) + purple = 0x800080, // rgb(128,0,128) + rebecca_purple = 0x663399, // rgb(102,51,153) + red = 0xFF0000, // rgb(255,0,0) + rosy_brown = 0xBC8F8F, // rgb(188,143,143) + royal_blue = 0x4169E1, // rgb(65,105,225) + saddle_brown = 0x8B4513, // rgb(139,69,19) + salmon = 0xFA8072, // rgb(250,128,114) + sandy_brown = 0xF4A460, // rgb(244,164,96) + sea_green = 0x2E8B57, // rgb(46,139,87) + sea_shell = 0xFFF5EE, // rgb(255,245,238) + sienna = 0xA0522D, // rgb(160,82,45) + silver = 0xC0C0C0, // rgb(192,192,192) + sky_blue = 0x87CEEB, // rgb(135,206,235) + slate_blue = 0x6A5ACD, // rgb(106,90,205) + slate_gray = 0x708090, // rgb(112,128,144) + snow = 0xFFFAFA, // rgb(255,250,250) + spring_green = 0x00FF7F, // rgb(0,255,127) + steel_blue = 0x4682B4, // rgb(70,130,180) + tan = 0xD2B48C, // rgb(210,180,140) + teal = 0x008080, // rgb(0,128,128) + thistle = 0xD8BFD8, // rgb(216,191,216) + tomato = 0xFF6347, // rgb(255,99,71) + turquoise = 0x40E0D0, // rgb(64,224,208) + violet = 0xEE82EE, // rgb(238,130,238) + wheat = 0xF5DEB3, // rgb(245,222,179) + white = 0xFFFFFF, // rgb(255,255,255) + white_smoke = 0xF5F5F5, // rgb(245,245,245) + yellow = 0xFFFF00, // rgb(255,255,0) + yellow_green = 0x9ACD32 // rgb(154,205,50) +}; // enum class color + +enum class terminal_color : uint8_t { + black = 30, + red, + green, + yellow, + blue, + magenta, + cyan, + white, + bright_black = 90, + bright_red, + bright_green, + bright_yellow, + bright_blue, + bright_magenta, + bright_cyan, + bright_white +}; // enum class terminal_color + +enum class emphasis : uint8_t { + bold = 1, + italic = 1 << 1, + underline = 1 << 2, + strikethrough = 1 << 3 +}; // enum class emphasis + +// rgb is a struct for red, green and blue colors. +// We use rgb as name because some editors will show it as color direct in the +// editor. +struct rgb { + FMT_CONSTEXPR_DECL rgb() : r(0), g(0), b(0) {} + FMT_CONSTEXPR_DECL rgb(uint8_t r_, uint8_t g_, uint8_t b_) + : r(r_), g(g_), b(b_) {} + FMT_CONSTEXPR_DECL rgb(uint32_t hex) + : r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b((hex) & 0xFF) {} + FMT_CONSTEXPR_DECL rgb(color hex) + : r((uint32_t(hex) >> 16) & 0xFF), g((uint32_t(hex) >> 8) & 0xFF), + b(uint32_t(hex) & 0xFF) {} + uint8_t r; + uint8_t g; + uint8_t b; +}; + +namespace internal { + +// color is a struct of either a rgb color or a terminal color. +struct color_type { + FMT_CONSTEXPR color_type() FMT_NOEXCEPT + : is_rgb(), value{} {} + FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT + : is_rgb(true), value{} { + value.rgb_color = static_cast<uint32_t>(rgb_color); + } + FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT + : is_rgb(true), value{} { + value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) + | (static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b; + } + FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT + : is_rgb(), value{} { + value.term_color = static_cast<uint8_t>(term_color); + } + bool is_rgb; + union color_union { + uint8_t term_color; + uint32_t rgb_color; + } value; +}; +} // namespace internal + +// Experimental text formatting support. +class text_style { + public: + FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT + : set_foreground_color(), set_background_color(), ems(em) {} + + FMT_CONSTEXPR text_style &operator|=(const text_style &rhs) { + if (!set_foreground_color) { + set_foreground_color = rhs.set_foreground_color; + foreground_color = rhs.foreground_color; + } else if (rhs.set_foreground_color) { + if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) + throw format_error("can't OR a terminal color"); + foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color; + } + + if (!set_background_color) { + set_background_color = rhs.set_background_color; + background_color = rhs.background_color; + } else if (rhs.set_background_color) { + if (!background_color.is_rgb || !rhs.background_color.is_rgb) + throw format_error("can't OR a terminal color"); + background_color.value.rgb_color |= rhs.background_color.value.rgb_color; + } + + ems = static_cast<emphasis>(static_cast<uint8_t>(ems) | + static_cast<uint8_t>(rhs.ems)); + return *this; + } + + friend FMT_CONSTEXPR + text_style operator|(text_style lhs, const text_style &rhs) { + return lhs |= rhs; + } + + FMT_CONSTEXPR text_style &operator&=(const text_style &rhs) { + if (!set_foreground_color) { + set_foreground_color = rhs.set_foreground_color; + foreground_color = rhs.foreground_color; + } else if (rhs.set_foreground_color) { + if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) + throw format_error("can't AND a terminal color"); + foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color; + } + + if (!set_background_color) { + set_background_color = rhs.set_background_color; + background_color = rhs.background_color; + } else if (rhs.set_background_color) { + if (!background_color.is_rgb || !rhs.background_color.is_rgb) + throw format_error("can't AND a terminal color"); + background_color.value.rgb_color &= rhs.background_color.value.rgb_color; + } + + ems = static_cast<emphasis>(static_cast<uint8_t>(ems) & + static_cast<uint8_t>(rhs.ems)); + return *this; + } + + friend FMT_CONSTEXPR + text_style operator&(text_style lhs, const text_style &rhs) { + return lhs &= rhs; + } + + FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT { + return set_foreground_color; + } + FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT { + return set_background_color; + } + FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT { + return static_cast<uint8_t>(ems) != 0; + } + FMT_CONSTEXPR internal::color_type get_foreground() const FMT_NOEXCEPT { + assert(has_foreground() && "no foreground specified for this style"); + return foreground_color; + } + FMT_CONSTEXPR internal::color_type get_background() const FMT_NOEXCEPT { + assert(has_background() && "no background specified for this style"); + return background_color; + } + FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT { + assert(has_emphasis() && "no emphasis specified for this style"); + return ems; + } + +private: + FMT_CONSTEXPR text_style(bool is_foreground, + internal::color_type text_color) FMT_NOEXCEPT + : set_foreground_color(), + set_background_color(), + ems() { + if (is_foreground) { + foreground_color = text_color; + set_foreground_color = true; + } else { + background_color = text_color; + set_background_color = true; + } + } + + friend FMT_CONSTEXPR_DECL text_style fg(internal::color_type foreground) + FMT_NOEXCEPT; + friend FMT_CONSTEXPR_DECL text_style bg(internal::color_type background) + FMT_NOEXCEPT; + + internal::color_type foreground_color; + internal::color_type background_color; + bool set_foreground_color; + bool set_background_color; + emphasis ems; +}; + +FMT_CONSTEXPR text_style fg(internal::color_type foreground) FMT_NOEXCEPT { + return text_style(/*is_foreground=*/true, foreground); +} + +FMT_CONSTEXPR text_style bg(internal::color_type background) FMT_NOEXCEPT { + return text_style(/*is_foreground=*/false, background); +} + +FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT { + return text_style(lhs) | rhs; +} + +namespace internal { + +template <typename Char> +struct ansi_color_escape { + FMT_CONSTEXPR ansi_color_escape(internal::color_type text_color, + const char * esc) FMT_NOEXCEPT { + // If we have a terminal color, we need to output another escape code + // sequence. + if (!text_color.is_rgb) { + bool is_background = esc == internal::data::BACKGROUND_COLOR; + uint32_t value = text_color.value.term_color; + // Background ASCII codes are the same as the foreground ones but with + // 10 more. + if (is_background) + value += 10u; + + std::size_t index = 0; + buffer[index++] = static_cast<Char>('\x1b'); + buffer[index++] = static_cast<Char>('['); + + if (value >= 100u) { + buffer[index++] = static_cast<Char>('1'); + value %= 100u; + } + buffer[index++] = static_cast<Char>('0' + value / 10u); + buffer[index++] = static_cast<Char>('0' + value % 10u); + + buffer[index++] = static_cast<Char>('m'); + buffer[index++] = static_cast<Char>('\0'); + return; + } + + for (int i = 0; i < 7; i++) { + buffer[i] = static_cast<Char>(esc[i]); + } + rgb color(text_color.value.rgb_color); + to_esc(color.r, buffer + 7, ';'); + to_esc(color.g, buffer + 11, ';'); + to_esc(color.b, buffer + 15, 'm'); + buffer[19] = static_cast<Char>(0); + } + FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT { + uint8_t em_codes[4] = {}; + uint8_t em_bits = static_cast<uint8_t>(em); + if (em_bits & static_cast<uint8_t>(emphasis::bold)) + em_codes[0] = 1; + if (em_bits & static_cast<uint8_t>(emphasis::italic)) + em_codes[1] = 3; + if (em_bits & static_cast<uint8_t>(emphasis::underline)) + em_codes[2] = 4; + if (em_bits & static_cast<uint8_t>(emphasis::strikethrough)) + em_codes[3] = 9; + + std::size_t index = 0; + for (int i = 0; i < 4; ++i) { + if (!em_codes[i]) + continue; + buffer[index++] = static_cast<Char>('\x1b'); + buffer[index++] = static_cast<Char>('['); + buffer[index++] = static_cast<Char>('0' + em_codes[i]); + buffer[index++] = static_cast<Char>('m'); + } + buffer[index++] = static_cast<Char>(0); + } + FMT_CONSTEXPR operator const Char *() const FMT_NOEXCEPT { return buffer; } + +private: + Char buffer[7u + 3u * 4u + 1u]; + + static FMT_CONSTEXPR void to_esc(uint8_t c, Char *out, + char delimiter) FMT_NOEXCEPT { + out[0] = static_cast<Char>('0' + c / 100); + out[1] = static_cast<Char>('0' + c / 10 % 10); + out[2] = static_cast<Char>('0' + c % 10); + out[3] = static_cast<Char>(delimiter); + } +}; + +template <typename Char> +FMT_CONSTEXPR ansi_color_escape<Char> +make_foreground_color(internal::color_type foreground) FMT_NOEXCEPT { + return ansi_color_escape<Char>(foreground, internal::data::FOREGROUND_COLOR); +} + +template <typename Char> +FMT_CONSTEXPR ansi_color_escape<Char> +make_background_color(internal::color_type background) FMT_NOEXCEPT { + return ansi_color_escape<Char>(background, internal::data::BACKGROUND_COLOR); +} + +template <typename Char> +FMT_CONSTEXPR ansi_color_escape<Char> +make_emphasis(emphasis em) FMT_NOEXCEPT { + return ansi_color_escape<Char>(em); +} + +template <typename Char> +inline void fputs(const Char *chars, FILE *stream) FMT_NOEXCEPT { + std::fputs(chars, stream); +} + +template <> +inline void fputs<wchar_t>(const wchar_t *chars, FILE *stream) FMT_NOEXCEPT { + std::fputws(chars, stream); +} + +template <typename Char> +inline void reset_color(FILE *stream) FMT_NOEXCEPT { + fputs(internal::data::RESET_COLOR, stream); +} + +template <> +inline void reset_color<wchar_t>(FILE *stream) FMT_NOEXCEPT { + fputs(internal::data::WRESET_COLOR, stream); +} + +// The following specialiazation disables using std::FILE as a character type, +// which is needed because or else +// fmt::print(stderr, fmt::emphasis::bold, ""); +// would take stderr (a std::FILE *) as the format string. +template <> +struct is_string<std::FILE *> : std::false_type {}; +template <> +struct is_string<const std::FILE *> : std::false_type {}; +} // namespace internal + +template < + typename S, typename Char = typename internal::char_t<S>::type> +void vprint(std::FILE *f, const text_style &ts, const S &format, + basic_format_args<typename buffer_context<Char>::type> args) { + bool has_style = false; + if (ts.has_emphasis()) { + has_style = true; + internal::fputs<Char>( + internal::make_emphasis<Char>(ts.get_emphasis()), f); + } + if (ts.has_foreground()) { + has_style = true; + internal::fputs<Char>( + internal::make_foreground_color<Char>(ts.get_foreground()), f); + } + if (ts.has_background()) { + has_style = true; + internal::fputs<Char>( + internal::make_background_color<Char>(ts.get_background()), f); + } + vprint(f, format, args); + if (has_style) { + internal::reset_color<Char>(f); + } +} + +/** + Formats a string and prints it to the specified file stream using ANSI + escape sequences to specify text formatting. + Example: + fmt::print(fmt::emphasis::bold | fg(fmt::color::red), + "Elapsed time: {0:.2f} seconds", 1.23); + */ +template <typename String, typename... Args> +typename std::enable_if<internal::is_string<String>::value>::type print( + std::FILE *f, const text_style &ts, const String &format_str, + const Args &... args) { + internal::check_format_string<Args...>(format_str); + typedef typename internal::char_t<String>::type char_t; + typedef typename buffer_context<char_t>::type context_t; + format_arg_store<context_t, Args...> as{args...}; + vprint(f, ts, format_str, basic_format_args<context_t>(as)); +} + +/** + Formats a string and prints it to stdout using ANSI escape sequences to + specify text formatting. + Example: + fmt::print(fmt::emphasis::bold | fg(fmt::color::red), + "Elapsed time: {0:.2f} seconds", 1.23); + */ +template <typename String, typename... Args> +typename std::enable_if<internal::is_string<String>::value>::type print( + const text_style &ts, const String &format_str, + const Args &... args) { + return print(stdout, ts, format_str, args...); +} + +#endif + +FMT_END_NAMESPACE + +#endif // FMT_COLOR_H_ diff --git a/matching/include/spdlog/fmt/bundled/core.h b/matching/include/spdlog/fmt/bundled/core.h new file mode 100644 index 0000000..50b7935 --- /dev/null +++ b/matching/include/spdlog/fmt/bundled/core.h @@ -0,0 +1,1502 @@ +// Formatting library for C++ - the core API +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_CORE_H_ +#define FMT_CORE_H_ + +#include <cassert> +#include <cstdio> // std::FILE +#include <cstring> +#include <iterator> +#include <string> +#include <type_traits> + +// The fmt library version in the form major * 10000 + minor * 100 + patch. +#define FMT_VERSION 50300 + +#ifdef __has_feature +# define FMT_HAS_FEATURE(x) __has_feature(x) +#else +# define FMT_HAS_FEATURE(x) 0 +#endif + +#if defined(__has_include) && !defined(__INTELLISENSE__) && \ + !(defined(__INTEL_COMPILER) && __INTEL_COMPILER < 1600) +# define FMT_HAS_INCLUDE(x) __has_include(x) +#else +# define FMT_HAS_INCLUDE(x) 0 +#endif + +#ifdef __has_cpp_attribute +# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define FMT_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +#if defined(__GNUC__) && !defined(__clang__) +# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#else +# define FMT_GCC_VERSION 0 +#endif + +#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define FMT_HAS_GXX_CXX11 FMT_GCC_VERSION +#else +# define FMT_HAS_GXX_CXX11 0 +#endif + +#ifdef _MSC_VER +# define FMT_MSC_VER _MSC_VER +#else +# define FMT_MSC_VER 0 +#endif + +// Check if relaxed C++14 constexpr is supported. +// GCC doesn't allow throw in constexpr until version 6 (bug 67371). +#ifndef FMT_USE_CONSTEXPR +# define FMT_USE_CONSTEXPR \ + (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1910 || \ + (FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) +#endif +#if FMT_USE_CONSTEXPR +# define FMT_CONSTEXPR constexpr +# define FMT_CONSTEXPR_DECL constexpr +#else +# define FMT_CONSTEXPR inline +# define FMT_CONSTEXPR_DECL +#endif + +#ifndef FMT_USE_CONSTEXPR11 +# define FMT_USE_CONSTEXPR11 \ + (FMT_USE_CONSTEXPR || FMT_GCC_VERSION >= 406 || FMT_MSC_VER >= 1900) +#endif +#if FMT_USE_CONSTEXPR11 +# define FMT_CONSTEXPR11 constexpr +#else +# define FMT_CONSTEXPR11 +#endif + +#ifndef FMT_OVERRIDE +# if FMT_HAS_FEATURE(cxx_override) || \ + (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 +# define FMT_OVERRIDE override +# else +# define FMT_OVERRIDE +# endif +#endif + +#if FMT_HAS_FEATURE(cxx_explicit_conversions) || \ + FMT_GCC_VERSION >= 405 || FMT_MSC_VER >= 1800 +# define FMT_USE_EXPLICIT 1 +# define FMT_EXPLICIT explicit +#else +# define FMT_USE_EXPLICIT 0 +# define FMT_EXPLICIT +#endif + +#ifndef FMT_NULL +# if FMT_HAS_FEATURE(cxx_nullptr) || \ + (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1600 +# define FMT_NULL nullptr +# define FMT_USE_NULLPTR 1 +# else +# define FMT_NULL NULL +# endif +#endif +#ifndef FMT_USE_NULLPTR +# define FMT_USE_NULLPTR 0 +#endif + +// Check if exceptions are disabled. +#ifndef FMT_EXCEPTIONS +# if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \ + FMT_MSC_VER && !_HAS_EXCEPTIONS +# define FMT_EXCEPTIONS 0 +# else +# define FMT_EXCEPTIONS 1 +# endif +#endif + +// Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature). +#ifndef FMT_USE_NOEXCEPT +# define FMT_USE_NOEXCEPT 0 +#endif + +#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ + (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 +# define FMT_DETECTED_NOEXCEPT noexcept +# define FMT_HAS_CXX11_NOEXCEPT 1 +#else +# define FMT_DETECTED_NOEXCEPT throw() +# define FMT_HAS_CXX11_NOEXCEPT 0 +#endif + +#ifndef FMT_NOEXCEPT +# if FMT_EXCEPTIONS || FMT_HAS_CXX11_NOEXCEPT +# define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT +# else +# define FMT_NOEXCEPT +# endif +#endif + +#ifndef FMT_BEGIN_NAMESPACE +# if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \ + FMT_MSC_VER >= 1900 +# define FMT_INLINE_NAMESPACE inline namespace +# define FMT_END_NAMESPACE }} +# else +# define FMT_INLINE_NAMESPACE namespace +# define FMT_END_NAMESPACE } using namespace v5; } +# endif +# define FMT_BEGIN_NAMESPACE namespace fmt { FMT_INLINE_NAMESPACE v5 { +#endif + +#if !defined(FMT_HEADER_ONLY) && defined(_WIN32) +# ifdef FMT_EXPORT +# define FMT_API __declspec(dllexport) +# elif defined(FMT_SHARED) +# define FMT_API __declspec(dllimport) +# endif +#endif +#ifndef FMT_API +# define FMT_API +#endif + +#ifndef FMT_ASSERT +# define FMT_ASSERT(condition, message) assert((condition) && message) +#endif + +// libc++ supports string_view in pre-c++17. +#if (FMT_HAS_INCLUDE(<string_view>) && \ + (__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \ + (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) +# include <string_view> +# define FMT_STRING_VIEW std::basic_string_view +#elif FMT_HAS_INCLUDE(<experimental/string_view>) && __cplusplus >= 201402L +# include <experimental/string_view> +# define FMT_STRING_VIEW std::experimental::basic_string_view +#endif + +// std::result_of is defined in <functional> in gcc 4.4. +#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 404 +# include <functional> +#endif + +FMT_BEGIN_NAMESPACE +namespace internal { + +// An implementation of declval for pre-C++11 compilers such as gcc 4. +template <typename T> +typename std::add_rvalue_reference<T>::type declval() FMT_NOEXCEPT; + +template <typename> +struct result_of; + +template <typename F, typename... Args> +struct result_of<F(Args...)> { + // A workaround for gcc 4.4 that doesn't allow F to be a reference. + typedef typename std::result_of< + typename std::remove_reference<F>::type(Args...)>::type type; +}; + +// Casts nonnegative integer to unsigned. +template <typename Int> +FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) { + FMT_ASSERT(value >= 0, "negative value"); + return static_cast<typename std::make_unsigned<Int>::type>(value); +} + +/** A contiguous memory buffer with an optional growing ability. */ +template <typename T> +class basic_buffer { + private: + basic_buffer(const basic_buffer &) = delete; + void operator=(const basic_buffer &) = delete; + + T *ptr_; + std::size_t size_; + std::size_t capacity_; + + protected: + // Don't initialize ptr_ since it is not accessed to save a few cycles. + basic_buffer(std::size_t sz) FMT_NOEXCEPT: size_(sz), capacity_(sz) {} + + basic_buffer(T *p = FMT_NULL, std::size_t sz = 0, std::size_t cap = 0) + FMT_NOEXCEPT: ptr_(p), size_(sz), capacity_(cap) {} + + /** Sets the buffer data and capacity. */ + void set(T *buf_data, std::size_t buf_capacity) FMT_NOEXCEPT { + ptr_ = buf_data; + capacity_ = buf_capacity; + } + + /** Increases the buffer capacity to hold at least *capacity* elements. */ + virtual void grow(std::size_t capacity) = 0; + + public: + typedef T value_type; + typedef const T &const_reference; + + virtual ~basic_buffer() {} + + T *begin() FMT_NOEXCEPT { return ptr_; } + T *end() FMT_NOEXCEPT { return ptr_ + size_; } + + /** Returns the size of this buffer. */ + std::size_t size() const FMT_NOEXCEPT { return size_; } + + /** Returns the capacity of this buffer. */ + std::size_t capacity() const FMT_NOEXCEPT { return capacity_; } + + /** Returns a pointer to the buffer data. */ + T *data() FMT_NOEXCEPT { return ptr_; } + + /** Returns a pointer to the buffer data. */ + const T *data() const FMT_NOEXCEPT { return ptr_; } + + /** + Resizes the buffer. If T is a POD type new elements may not be initialized. + */ + void resize(std::size_t new_size) { + reserve(new_size); + size_ = new_size; + } + + /** Clears this buffer. */ + void clear() { size_ = 0; } + + /** Reserves space to store at least *capacity* elements. */ + void reserve(std::size_t new_capacity) { + if (new_capacity > capacity_) + grow(new_capacity); + } + + void push_back(const T &value) { + reserve(size_ + 1); + ptr_[size_++] = value; + } + + /** Appends data to the end of the buffer. */ + template <typename U> + void append(const U *begin, const U *end); + + T &operator[](std::size_t index) { return ptr_[index]; } + const T &operator[](std::size_t index) const { return ptr_[index]; } +}; + +typedef basic_buffer<char> buffer; +typedef basic_buffer<wchar_t> wbuffer; + +// A container-backed buffer. +template <typename Container> +class container_buffer : public basic_buffer<typename Container::value_type> { + private: + Container &container_; + + protected: + void grow(std::size_t capacity) FMT_OVERRIDE { + container_.resize(capacity); + this->set(&container_[0], capacity); + } + + public: + explicit container_buffer(Container &c) + : basic_buffer<typename Container::value_type>(c.size()), container_(c) {} +}; + +// Extracts a reference to the container from back_insert_iterator. +template <typename Container> +inline Container &get_container(std::back_insert_iterator<Container> it) { + typedef std::back_insert_iterator<Container> bi_iterator; + struct accessor: bi_iterator { + accessor(bi_iterator iter) : bi_iterator(iter) {} + using bi_iterator::container; + }; + return *accessor(it).container; +} + +struct error_handler { + FMT_CONSTEXPR error_handler() {} + FMT_CONSTEXPR error_handler(const error_handler &) {} + + // This function is intentionally not constexpr to give a compile-time error. + FMT_API void on_error(const char *message); +}; + +template <typename T> +struct no_formatter_error : std::false_type {}; +} // namespace internal + +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 405 +template <typename... T> +struct is_constructible: std::false_type {}; +#else +template <typename... T> +struct is_constructible : std::is_constructible<T...> {}; +#endif + +/** + An implementation of ``std::basic_string_view`` for pre-C++17. It provides a + subset of the API. ``fmt::basic_string_view`` is used for format strings even + if ``std::string_view`` is available to prevent issues when a library is + compiled with a different ``-std`` option than the client code (which is not + recommended). + */ +template <typename Char> +class basic_string_view { + private: + const Char *data_; + size_t size_; + + public: + typedef Char char_type; + typedef const Char *iterator; + + FMT_CONSTEXPR basic_string_view() FMT_NOEXCEPT : data_(FMT_NULL), size_(0) {} + + /** Constructs a string reference object from a C string and a size. */ + FMT_CONSTEXPR basic_string_view(const Char *s, size_t count) FMT_NOEXCEPT + : data_(s), size_(count) {} + + /** + \rst + Constructs a string reference object from a C string computing + the size with ``std::char_traits<Char>::length``. + \endrst + */ + basic_string_view(const Char *s) + : data_(s), size_(std::char_traits<Char>::length(s)) {} + + /** Constructs a string reference from a ``std::basic_string`` object. */ + template <typename Alloc> + FMT_CONSTEXPR basic_string_view( + const std::basic_string<Char, Alloc> &s) FMT_NOEXCEPT + : data_(s.data()), size_(s.size()) {} + +#ifdef FMT_STRING_VIEW + FMT_CONSTEXPR basic_string_view(FMT_STRING_VIEW<Char> s) FMT_NOEXCEPT + : data_(s.data()), size_(s.size()) {} +#endif + + /** Returns a pointer to the string data. */ + FMT_CONSTEXPR const Char *data() const { return data_; } + + /** Returns the string size. */ + FMT_CONSTEXPR size_t size() const { return size_; } + + FMT_CONSTEXPR iterator begin() const { return data_; } + FMT_CONSTEXPR iterator end() const { return data_ + size_; } + + FMT_CONSTEXPR void remove_prefix(size_t n) { + data_ += n; + size_ -= n; + } + + // Lexicographically compare this string reference to other. + int compare(basic_string_view other) const { + size_t str_size = size_ < other.size_ ? size_ : other.size_; + int result = std::char_traits<Char>::compare(data_, other.data_, str_size); + if (result == 0) + result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); + return result; + } + + friend bool operator==(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) == 0; + } + friend bool operator!=(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) != 0; + } + friend bool operator<(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) < 0; + } + friend bool operator<=(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) <= 0; + } + friend bool operator>(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) > 0; + } + friend bool operator>=(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) >= 0; + } +}; + +typedef basic_string_view<char> string_view; +typedef basic_string_view<wchar_t> wstring_view; + +/** + \rst + The function ``to_string_view`` adapts non-intrusively any kind of string or + string-like type if the user provides a (possibly templated) overload of + ``to_string_view`` which takes an instance of the string class + ``StringType<Char>`` and returns a ``fmt::basic_string_view<Char>``. + The conversion function must live in the very same namespace as + ``StringType<Char>`` to be picked up by ADL. Non-templated string types + like f.e. QString must return a ``basic_string_view`` with a fixed matching + char type. + + **Example**:: + + namespace my_ns { + inline string_view to_string_view(const my_string &s) { + return {s.data(), s.length()}; + } + } + + std::string message = fmt::format(my_string("The answer is {}"), 42); + \endrst + */ +template <typename Char> +inline basic_string_view<Char> + to_string_view(basic_string_view<Char> s) { return s; } + +template <typename Char> +inline basic_string_view<Char> + to_string_view(const std::basic_string<Char> &s) { return s; } + +template <typename Char> +inline basic_string_view<Char> to_string_view(const Char *s) { return s; } + +#ifdef FMT_STRING_VIEW +template <typename Char> +inline basic_string_view<Char> + to_string_view(FMT_STRING_VIEW<Char> s) { return s; } +#endif + +// A base class for compile-time strings. It is defined in the fmt namespace to +// make formatting functions visible via ADL, e.g. format(fmt("{}"), 42). +struct compile_string {}; + +template <typename S> +struct is_compile_string : std::is_base_of<compile_string, S> {}; + +template < + typename S, + typename Enable = typename std::enable_if<is_compile_string<S>::value>::type> +FMT_CONSTEXPR basic_string_view<typename S::char_type> + to_string_view(const S &s) { return s; } + +template <typename Context> +class basic_format_arg; + +template <typename Context> +class basic_format_args; + +// A formatter for objects of type T. +template <typename T, typename Char = char, typename Enable = void> +struct formatter { + static_assert(internal::no_formatter_error<T>::value, + "don't know how to format the type, include fmt/ostream.h if it provides " + "an operator<< that should be used"); + + // The following functions are not defined intentionally. + template <typename ParseContext> + typename ParseContext::iterator parse(ParseContext &); + template <typename FormatContext> + auto format(const T &val, FormatContext &ctx) -> decltype(ctx.out()); +}; + +template <typename T, typename Char, typename Enable = void> +struct convert_to_int: std::integral_constant< + bool, !std::is_arithmetic<T>::value && std::is_convertible<T, int>::value> {}; + +namespace internal { + +struct dummy_string_view { typedef void char_type; }; +dummy_string_view to_string_view(...); +using fmt::v5::to_string_view; + +// Specifies whether S is a string type convertible to fmt::basic_string_view. +template <typename S> +struct is_string : std::integral_constant<bool, !std::is_same< + dummy_string_view, decltype(to_string_view(declval<S>()))>::value> {}; + +template <typename S> +struct char_t { + typedef decltype(to_string_view(declval<S>())) result; + typedef typename result::char_type type; +}; + +template <typename Char> +struct named_arg_base; + +template <typename T, typename Char> +struct named_arg; + +enum type { + none_type, named_arg_type, + // Integer types should go first, + int_type, uint_type, long_long_type, ulong_long_type, bool_type, char_type, + last_integer_type = char_type, + // followed by floating-point types. + double_type, long_double_type, last_numeric_type = long_double_type, + cstring_type, string_type, pointer_type, custom_type +}; + +FMT_CONSTEXPR bool is_integral(type t) { + FMT_ASSERT(t != internal::named_arg_type, "invalid argument type"); + return t > internal::none_type && t <= internal::last_integer_type; +} + +FMT_CONSTEXPR bool is_arithmetic(type t) { + FMT_ASSERT(t != internal::named_arg_type, "invalid argument type"); + return t > internal::none_type && t <= internal::last_numeric_type; +} + +template <typename Char> +struct string_value { + const Char *value; + std::size_t size; +}; + +template <typename Context> +struct custom_value { + const void *value; + void (*format)(const void *arg, Context &ctx); +}; + +// A formatting argument value. +template <typename Context> +class value { + public: + typedef typename Context::char_type char_type; + + union { + int int_value; + unsigned uint_value; + long long long_long_value; + unsigned long long ulong_long_value; + double double_value; + long double long_double_value; + const void *pointer; + string_value<char_type> string; + string_value<signed char> sstring; + string_value<unsigned char> ustring; + custom_value<Context> custom; + }; + + FMT_CONSTEXPR value(int val = 0) : int_value(val) {} + value(unsigned val) { uint_value = val; } + value(long long val) { long_long_value = val; } + value(unsigned long long val) { ulong_long_value = val; } + value(double val) { double_value = val; } + value(long double val) { long_double_value = val; } + value(const char_type *val) { string.value = val; } + value(const signed char *val) { + static_assert(std::is_same<char, char_type>::value, + "incompatible string types"); + sstring.value = val; + } + value(const unsigned char *val) { + static_assert(std::is_same<char, char_type>::value, + "incompatible string types"); + ustring.value = val; + } + value(basic_string_view<char_type> val) { + string.value = val.data(); + string.size = val.size(); + } + value(const void *val) { pointer = val; } + + template <typename T> + explicit value(const T &val) { + custom.value = &val; + custom.format = &format_custom_arg<T>; + } + + const named_arg_base<char_type> &as_named_arg() { + return *static_cast<const named_arg_base<char_type>*>(pointer); + } + + private: + // Formats an argument of a custom type, such as a user-defined class. + template <typename T> + static void format_custom_arg(const void *arg, Context &ctx) { + // Get the formatter type through the context to allow different contexts + // have different extension points, e.g. `formatter<T>` for `format` and + // `printf_formatter<T>` for `printf`. + typename Context::template formatter_type<T>::type f; + auto &&parse_ctx = ctx.parse_context(); + parse_ctx.advance_to(f.parse(parse_ctx)); + ctx.advance_to(f.format(*static_cast<const T*>(arg), ctx)); + } +}; + +// Value initializer used to delay conversion to value and reduce memory churn. +template <typename Context, typename T, type TYPE> +struct init { + T val; + static const type type_tag = TYPE; + + FMT_CONSTEXPR init(const T &v) : val(v) {} + FMT_CONSTEXPR operator value<Context>() const { return value<Context>(val); } +}; + +template <typename Context, typename T> +FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T &value); + +#define FMT_MAKE_VALUE(TAG, ArgType, ValueType) \ + template <typename C> \ + FMT_CONSTEXPR init<C, ValueType, TAG> make_value(ArgType val) { \ + return static_cast<ValueType>(val); \ + } + +#define FMT_MAKE_VALUE_SAME(TAG, Type) \ + template <typename C> \ + FMT_CONSTEXPR init<C, Type, TAG> make_value(Type val) { return val; } + +FMT_MAKE_VALUE(bool_type, bool, int) +FMT_MAKE_VALUE(int_type, short, int) +FMT_MAKE_VALUE(uint_type, unsigned short, unsigned) +FMT_MAKE_VALUE_SAME(int_type, int) +FMT_MAKE_VALUE_SAME(uint_type, unsigned) + +// To minimize the number of types we need to deal with, long is translated +// either to int or to long long depending on its size. +typedef std::conditional<sizeof(long) == sizeof(int), int, long long>::type + long_type; +FMT_MAKE_VALUE( + (sizeof(long) == sizeof(int) ? int_type : long_long_type), long, long_type) +typedef std::conditional<sizeof(unsigned long) == sizeof(unsigned), + unsigned, unsigned long long>::type ulong_type; +FMT_MAKE_VALUE( + (sizeof(unsigned long) == sizeof(unsigned) ? uint_type : ulong_long_type), + unsigned long, ulong_type) + +FMT_MAKE_VALUE_SAME(long_long_type, long long) +FMT_MAKE_VALUE_SAME(ulong_long_type, unsigned long long) +FMT_MAKE_VALUE(int_type, signed char, int) +FMT_MAKE_VALUE(uint_type, unsigned char, unsigned) + +// This doesn't use FMT_MAKE_VALUE because of ambiguity in gcc 4.4. +template <typename C, typename Char> +FMT_CONSTEXPR typename std::enable_if< + std::is_same<typename C::char_type, Char>::value, + init<C, int, char_type>>::type make_value(Char val) { return val; } + +template <typename C> +FMT_CONSTEXPR typename std::enable_if< + !std::is_same<typename C::char_type, char>::value, + init<C, int, char_type>>::type make_value(char val) { return val; } + +FMT_MAKE_VALUE(double_type, float, double) +FMT_MAKE_VALUE_SAME(double_type, double) +FMT_MAKE_VALUE_SAME(long_double_type, long double) + +// Formatting of wide strings into a narrow buffer and multibyte strings +// into a wide buffer is disallowed (https://github.com/fmtlib/fmt/pull/606). +FMT_MAKE_VALUE(cstring_type, typename C::char_type*, + const typename C::char_type*) +FMT_MAKE_VALUE(cstring_type, const typename C::char_type*, + const typename C::char_type*) + +FMT_MAKE_VALUE(cstring_type, signed char*, const signed char*) +FMT_MAKE_VALUE_SAME(cstring_type, const signed char*) +FMT_MAKE_VALUE(cstring_type, unsigned char*, const unsigned char*) +FMT_MAKE_VALUE_SAME(cstring_type, const unsigned char*) +FMT_MAKE_VALUE_SAME(string_type, basic_string_view<typename C::char_type>) +FMT_MAKE_VALUE(string_type, + typename basic_string_view<typename C::char_type>::type, + basic_string_view<typename C::char_type>) +FMT_MAKE_VALUE(string_type, const std::basic_string<typename C::char_type>&, + basic_string_view<typename C::char_type>) +FMT_MAKE_VALUE(pointer_type, void*, const void*) +FMT_MAKE_VALUE_SAME(pointer_type, const void*) + +#if FMT_USE_NULLPTR +FMT_MAKE_VALUE(pointer_type, std::nullptr_t, const void*) +#endif + +// Formatting of arbitrary pointers is disallowed. If you want to output a +// pointer cast it to "void *" or "const void *". In particular, this forbids +// formatting of "[const] volatile char *" which is printed as bool by +// iostreams. +template <typename C, typename T> +typename std::enable_if<!std::is_same<T, typename C::char_type>::value>::type + make_value(const T *) { + static_assert(!sizeof(T), "formatting of non-void pointers is disallowed"); +} + +template <typename C, typename T> +inline typename std::enable_if< + std::is_enum<T>::value && convert_to_int<T, typename C::char_type>::value, + init<C, int, int_type>>::type + make_value(const T &val) { return static_cast<int>(val); } + +template <typename C, typename T, typename Char = typename C::char_type> +inline typename std::enable_if< + is_constructible<basic_string_view<Char>, T>::value && + !internal::is_string<T>::value, + init<C, basic_string_view<Char>, string_type>>::type + make_value(const T &val) { return basic_string_view<Char>(val); } + +template <typename C, typename T, typename Char = typename C::char_type> +inline typename std::enable_if< + !convert_to_int<T, Char>::value && !std::is_same<T, Char>::value && + !std::is_convertible<T, basic_string_view<Char>>::value && + !is_constructible<basic_string_view<Char>, T>::value && + !internal::is_string<T>::value, + // Implicit conversion to std::string is not handled here because it's + // unsafe: https://github.com/fmtlib/fmt/issues/729 + init<C, const T &, custom_type>>::type + make_value(const T &val) { return val; } + +template <typename C, typename T> +init<C, const void*, named_arg_type> + make_value(const named_arg<T, typename C::char_type> &val) { + basic_format_arg<C> arg = make_arg<C>(val.value); + std::memcpy(val.data, &arg, sizeof(arg)); + return static_cast<const void*>(&val); +} + +template <typename C, typename S> +FMT_CONSTEXPR11 typename std::enable_if< + internal::is_string<S>::value, + init<C, basic_string_view<typename C::char_type>, string_type>>::type + make_value(const S &val) { + // Handle adapted strings. + static_assert(std::is_same< + typename C::char_type, typename internal::char_t<S>::type>::value, + "mismatch between char-types of context and argument"); + return to_string_view(val); +} + +// Maximum number of arguments with packed types. +enum { max_packed_args = 15 }; +enum : unsigned long long { is_unpacked_bit = 1ull << 63 }; + +template <typename Context> +class arg_map; +} // namespace internal + +// A formatting argument. It is a trivially copyable/constructible type to +// allow storage in basic_memory_buffer. +template <typename Context> +class basic_format_arg { + private: + internal::value<Context> value_; + internal::type type_; + + template <typename ContextType, typename T> + friend FMT_CONSTEXPR basic_format_arg<ContextType> + internal::make_arg(const T &value); + + template <typename Visitor, typename Ctx> + friend FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type + visit_format_arg(Visitor &&vis, const basic_format_arg<Ctx> &arg); + + friend class basic_format_args<Context>; + friend class internal::arg_map<Context>; + + typedef typename Context::char_type char_type; + + public: + class handle { + public: + explicit handle(internal::custom_value<Context> custom): custom_(custom) {} + + void format(Context &ctx) const { custom_.format(custom_.value, ctx); } + + private: + internal::custom_value<Context> custom_; + }; + + FMT_CONSTEXPR basic_format_arg() : type_(internal::none_type) {} + + FMT_EXPLICIT operator bool() const FMT_NOEXCEPT { + return type_ != internal::none_type; + } + + internal::type type() const { return type_; } + + bool is_integral() const { return internal::is_integral(type_); } + bool is_arithmetic() const { return internal::is_arithmetic(type_); } +}; + +struct monostate {}; + +/** + \rst + Visits an argument dispatching to the appropriate visit method based on + the argument type. For example, if the argument type is ``double`` then + ``vis(value)`` will be called with the value of type ``double``. + \endrst + */ +template <typename Visitor, typename Context> +FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type + visit_format_arg(Visitor &&vis, const basic_format_arg<Context> &arg) { + typedef typename Context::char_type char_type; + switch (arg.type_) { + case internal::none_type: + break; + case internal::named_arg_type: + FMT_ASSERT(false, "invalid argument type"); + break; + case internal::int_type: + return vis(arg.value_.int_value); + case internal::uint_type: + return vis(arg.value_.uint_value); + case internal::long_long_type: + return vis(arg.value_.long_long_value); + case internal::ulong_long_type: + return vis(arg.value_.ulong_long_value); + case internal::bool_type: + return vis(arg.value_.int_value != 0); + case internal::char_type: + return vis(static_cast<char_type>(arg.value_.int_value)); + case internal::double_type: + return vis(arg.value_.double_value); + case internal::long_double_type: + return vis(arg.value_.long_double_value); + case internal::cstring_type: + return vis(arg.value_.string.value); + case internal::string_type: + return vis(basic_string_view<char_type>( + arg.value_.string.value, arg.value_.string.size)); + case internal::pointer_type: + return vis(arg.value_.pointer); + case internal::custom_type: + return vis(typename basic_format_arg<Context>::handle(arg.value_.custom)); + } + return vis(monostate()); +} + +// DEPRECATED! +template <typename Visitor, typename Context> +FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type + visit(Visitor &&vis, const basic_format_arg<Context> &arg) { + return visit_format_arg(std::forward<Visitor>(vis), arg); +} + +// Parsing context consisting of a format string range being parsed and an +// argument counter for automatic indexing. +template <typename Char, typename ErrorHandler = internal::error_handler> +class basic_parse_context : private ErrorHandler { + private: + basic_string_view<Char> format_str_; + int next_arg_id_; + + public: + typedef Char char_type; + typedef typename basic_string_view<Char>::iterator iterator; + + explicit FMT_CONSTEXPR basic_parse_context( + basic_string_view<Char> format_str, ErrorHandler eh = ErrorHandler()) + : ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {} + + // Returns an iterator to the beginning of the format string range being + // parsed. + FMT_CONSTEXPR iterator begin() const FMT_NOEXCEPT { + return format_str_.begin(); + } + + // Returns an iterator past the end of the format string range being parsed. + FMT_CONSTEXPR iterator end() const FMT_NOEXCEPT { return format_str_.end(); } + + // Advances the begin iterator to ``it``. + FMT_CONSTEXPR void advance_to(iterator it) { + format_str_.remove_prefix(internal::to_unsigned(it - begin())); + } + + // Returns the next argument index. + FMT_CONSTEXPR unsigned next_arg_id(); + + FMT_CONSTEXPR bool check_arg_id(unsigned) { + if (next_arg_id_ > 0) { + on_error("cannot switch from automatic to manual argument indexing"); + return false; + } + next_arg_id_ = -1; + return true; + } + void check_arg_id(basic_string_view<Char>) {} + + FMT_CONSTEXPR void on_error(const char *message) { + ErrorHandler::on_error(message); + } + + FMT_CONSTEXPR ErrorHandler error_handler() const { return *this; } +}; + +typedef basic_parse_context<char> format_parse_context; +typedef basic_parse_context<wchar_t> wformat_parse_context; + +// DEPRECATED! +typedef basic_parse_context<char> parse_context; +typedef basic_parse_context<wchar_t> wparse_context; + +namespace internal { +// A map from argument names to their values for named arguments. +template <typename Context> +class arg_map { + private: + arg_map(const arg_map &) = delete; + void operator=(const arg_map &) = delete; + + typedef typename Context::char_type char_type; + + struct entry { + basic_string_view<char_type> name; + basic_format_arg<Context> arg; + }; + + entry *map_; + unsigned size_; + + void push_back(value<Context> val) { + const internal::named_arg_base<char_type> &named = val.as_named_arg(); + map_[size_] = entry{named.name, named.template deserialize<Context>()}; + ++size_; + } + + public: + arg_map() : map_(FMT_NULL), size_(0) {} + void init(const basic_format_args<Context> &args); + ~arg_map() { delete [] map_; } + + basic_format_arg<Context> find(basic_string_view<char_type> name) const { + // The list is unsorted, so just return the first matching name. + for (entry *it = map_, *end = map_ + size_; it != end; ++it) { + if (it->name == name) + return it->arg; + } + return {}; + } +}; + +// A type-erased reference to an std::locale to avoid heavy <locale> include. +class locale_ref { + private: + const void *locale_; // A type-erased pointer to std::locale. + friend class locale; + + public: + locale_ref() : locale_(FMT_NULL) {} + + template <typename Locale> + explicit locale_ref(const Locale &loc); + + template <typename Locale> + Locale get() const; +}; + +template <typename OutputIt, typename Context, typename Char> +class context_base { + public: + typedef OutputIt iterator; + + private: + basic_parse_context<Char> parse_context_; + iterator out_; + basic_format_args<Context> args_; + locale_ref loc_; + + protected: + typedef Char char_type; + typedef basic_format_arg<Context> format_arg; + + context_base(OutputIt out, basic_string_view<char_type> format_str, + basic_format_args<Context> ctx_args, + locale_ref loc = locale_ref()) + : parse_context_(format_str), out_(out), args_(ctx_args), loc_(loc) {} + + // Returns the argument with specified index. + format_arg do_get_arg(unsigned arg_id) { + format_arg arg = args_.get(arg_id); + if (!arg) + parse_context_.on_error("argument index out of range"); + return arg; + } + + // Checks if manual indexing is used and returns the argument with + // specified index. + format_arg get_arg(unsigned arg_id) { + return this->parse_context().check_arg_id(arg_id) ? + this->do_get_arg(arg_id) : format_arg(); + } + + public: + basic_parse_context<char_type> &parse_context() { return parse_context_; } + basic_format_args<Context> args() const { return args_; } // DEPRECATED! + basic_format_arg<Context> arg(unsigned id) const { return args_.get(id); } + + internal::error_handler error_handler() { + return parse_context_.error_handler(); + } + + void on_error(const char *message) { parse_context_.on_error(message); } + + // Returns an iterator to the beginning of the output range. + iterator out() { return out_; } + iterator begin() { return out_; } // deprecated + + // Advances the begin iterator to ``it``. + void advance_to(iterator it) { out_ = it; } + + locale_ref locale() { return loc_; } +}; + +template <typename Context, typename T> +struct get_type { + typedef decltype(make_value<Context>( + declval<typename std::decay<T>::type&>())) value_type; + static const type value = value_type::type_tag; +}; + +template <typename Context> +FMT_CONSTEXPR11 unsigned long long get_types() { return 0; } + +template <typename Context, typename Arg, typename... Args> +FMT_CONSTEXPR11 unsigned long long get_types() { + return get_type<Context, Arg>::value | (get_types<Context, Args...>() << 4); +} + +template <typename Context, typename T> +FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T &value) { + basic_format_arg<Context> arg; + arg.type_ = get_type<Context, T>::value; + arg.value_ = make_value<Context>(value); + return arg; +} + +template <bool IS_PACKED, typename Context, typename T> +inline typename std::enable_if<IS_PACKED, value<Context>>::type + make_arg(const T &value) { + return make_value<Context>(value); +} + +template <bool IS_PACKED, typename Context, typename T> +inline typename std::enable_if<!IS_PACKED, basic_format_arg<Context>>::type + make_arg(const T &value) { + return make_arg<Context>(value); +} +} // namespace internal + +// Formatting context. +template <typename OutputIt, typename Char> +class basic_format_context : + public internal::context_base< + OutputIt, basic_format_context<OutputIt, Char>, Char> { + public: + /** The character type for the output. */ + typedef Char char_type; + + // using formatter_type = formatter<T, char_type>; + template <typename T> + struct formatter_type { typedef formatter<T, char_type> type; }; + + private: + internal::arg_map<basic_format_context> map_; + + basic_format_context(const basic_format_context &) = delete; + void operator=(const basic_format_context &) = delete; + + typedef internal::context_base<OutputIt, basic_format_context, Char> base; + typedef typename base::format_arg format_arg; + using base::get_arg; + + public: + using typename base::iterator; + + /** + Constructs a ``basic_format_context`` object. References to the arguments are + stored in the object so make sure they have appropriate lifetimes. + */ + basic_format_context(OutputIt out, basic_string_view<char_type> format_str, + basic_format_args<basic_format_context> ctx_args, + internal::locale_ref loc = internal::locale_ref()) + : base(out, format_str, ctx_args, loc) {} + + format_arg next_arg() { + return this->do_get_arg(this->parse_context().next_arg_id()); + } + format_arg get_arg(unsigned arg_id) { return this->do_get_arg(arg_id); } + + // Checks if manual indexing is used and returns the argument with the + // specified name. + format_arg get_arg(basic_string_view<char_type> name); +}; + +template <typename Char> +struct buffer_context { + typedef basic_format_context< + std::back_insert_iterator<internal::basic_buffer<Char>>, Char> type; +}; +typedef buffer_context<char>::type format_context; +typedef buffer_context<wchar_t>::type wformat_context; + +/** + \rst + An array of references to arguments. It can be implicitly converted into + `~fmt::basic_format_args` for passing into type-erased formatting functions + such as `~fmt::vformat`. + \endrst + */ +template <typename Context, typename ...Args> +class format_arg_store { + private: + static const size_t NUM_ARGS = sizeof...(Args); + + // Packed is a macro on MinGW so use IS_PACKED instead. + static const bool IS_PACKED = NUM_ARGS < internal::max_packed_args; + + typedef typename std::conditional<IS_PACKED, + internal::value<Context>, basic_format_arg<Context>>::type value_type; + + // If the arguments are not packed, add one more element to mark the end. + static const size_t DATA_SIZE = + NUM_ARGS + (IS_PACKED && NUM_ARGS != 0 ? 0 : 1); + value_type data_[DATA_SIZE]; + + friend class basic_format_args<Context>; + + static FMT_CONSTEXPR11 unsigned long long get_types() { + return IS_PACKED ? + internal::get_types<Context, Args...>() : + internal::is_unpacked_bit | NUM_ARGS; + } + + public: +#if FMT_USE_CONSTEXPR11 + static FMT_CONSTEXPR11 unsigned long long TYPES = get_types(); +#else + static const unsigned long long TYPES; +#endif + +#if (FMT_GCC_VERSION && FMT_GCC_VERSION <= 405) || \ + (FMT_MSC_VER && FMT_MSC_VER <= 1800) + // Workaround array initialization issues in gcc <= 4.5 and MSVC <= 2013. + format_arg_store(const Args &... args) { + value_type init[DATA_SIZE] = + {internal::make_arg<IS_PACKED, Context>(args)...}; + std::memcpy(data_, init, sizeof(init)); + } +#else + format_arg_store(const Args &... args) + : data_{internal::make_arg<IS_PACKED, Context>(args)...} {} +#endif +}; + +#if !FMT_USE_CONSTEXPR11 +template <typename Context, typename ...Args> +const unsigned long long format_arg_store<Context, Args...>::TYPES = + get_types(); +#endif + +/** + \rst + Constructs an `~fmt::format_arg_store` object that contains references to + arguments and can be implicitly converted to `~fmt::format_args`. `Context` + can be omitted in which case it defaults to `~fmt::context`. + \endrst + */ +template <typename Context = format_context, typename ...Args> +inline format_arg_store<Context, Args...> + make_format_args(const Args &... args) { return {args...}; } + +/** Formatting arguments. */ +template <typename Context> +class basic_format_args { + public: + typedef unsigned size_type; + typedef basic_format_arg<Context> format_arg; + + private: + // To reduce compiled code size per formatting function call, types of first + // max_packed_args arguments are passed in the types_ field. + unsigned long long types_; + union { + // If the number of arguments is less than max_packed_args, the argument + // values are stored in values_, otherwise they are stored in args_. + // This is done to reduce compiled code size as storing larger objects + // may require more code (at least on x86-64) even if the same amount of + // data is actually copied to stack. It saves ~10% on the bloat test. + const internal::value<Context> *values_; + const format_arg *args_; + }; + + bool is_packed() const { return (types_ & internal::is_unpacked_bit) == 0; } + + typename internal::type type(unsigned index) const { + unsigned shift = index * 4; + return static_cast<typename internal::type>( + (types_ & (0xfull << shift)) >> shift); + } + + friend class internal::arg_map<Context>; + + void set_data(const internal::value<Context> *values) { values_ = values; } + void set_data(const format_arg *args) { args_ = args; } + + format_arg do_get(size_type index) const { + format_arg arg; + if (!is_packed()) { + auto num_args = max_size(); + if (index < num_args) + arg = args_[index]; + return arg; + } + if (index > internal::max_packed_args) + return arg; + arg.type_ = type(index); + if (arg.type_ == internal::none_type) + return arg; + internal::value<Context> &val = arg.value_; + val = values_[index]; + return arg; + } + + public: + basic_format_args() : types_(0) {} + + /** + \rst + Constructs a `basic_format_args` object from `~fmt::format_arg_store`. + \endrst + */ + template <typename... Args> + basic_format_args(const format_arg_store<Context, Args...> &store) + : types_(static_cast<unsigned long long>(store.TYPES)) { + set_data(store.data_); + } + + /** + \rst + Constructs a `basic_format_args` object from a dynamic set of arguments. + \endrst + */ + basic_format_args(const format_arg *args, size_type count) + : types_(internal::is_unpacked_bit | count) { + set_data(args); + } + + /** Returns the argument at specified index. */ + format_arg get(size_type index) const { + format_arg arg = do_get(index); + if (arg.type_ == internal::named_arg_type) + arg = arg.value_.as_named_arg().template deserialize<Context>(); + return arg; + } + + size_type max_size() const { + unsigned long long max_packed = internal::max_packed_args; + return static_cast<size_type>( + is_packed() ? max_packed : types_ & ~internal::is_unpacked_bit); + } +}; + +/** An alias to ``basic_format_args<context>``. */ +// It is a separate type rather than a typedef to make symbols readable. +struct format_args : basic_format_args<format_context> { + template <typename ...Args> + format_args(Args &&... arg) + : basic_format_args<format_context>(std::forward<Args>(arg)...) {} +}; +struct wformat_args : basic_format_args<wformat_context> { + template <typename ...Args> + wformat_args(Args &&... arg) + : basic_format_args<wformat_context>(std::forward<Args>(arg)...) {} +}; + +#define FMT_ENABLE_IF_T(B, T) typename std::enable_if<B, T>::type + +#ifndef FMT_USE_ALIAS_TEMPLATES +# define FMT_USE_ALIAS_TEMPLATES FMT_HAS_FEATURE(cxx_alias_templates) +#endif +#if FMT_USE_ALIAS_TEMPLATES +/** String's character type. */ +template <typename S> +using char_t = FMT_ENABLE_IF_T( + internal::is_string<S>::value, typename internal::char_t<S>::type); +#define FMT_CHAR(S) fmt::char_t<S> +#else +template <typename S> +struct char_t : std::enable_if< + internal::is_string<S>::value, typename internal::char_t<S>::type> {}; +#define FMT_CHAR(S) typename char_t<S>::type +#endif + +namespace internal { +template <typename Char> +struct named_arg_base { + basic_string_view<Char> name; + + // Serialized value<context>. + mutable char data[ + sizeof(basic_format_arg<typename buffer_context<Char>::type>)]; + + named_arg_base(basic_string_view<Char> nm) : name(nm) {} + + template <typename Context> + basic_format_arg<Context> deserialize() const { + basic_format_arg<Context> arg; + std::memcpy(&arg, data, sizeof(basic_format_arg<Context>)); + return arg; + } +}; + +template <typename T, typename Char> +struct named_arg : named_arg_base<Char> { + const T &value; + + named_arg(basic_string_view<Char> name, const T &val) + : named_arg_base<Char>(name), value(val) {} +}; + +template <typename... Args, typename S> +inline typename std::enable_if<!is_compile_string<S>::value>::type + check_format_string(const S &) {} +template <typename... Args, typename S> +typename std::enable_if<is_compile_string<S>::value>::type + check_format_string(S); + +template <typename S, typename... Args> +struct checked_args : format_arg_store< + typename buffer_context<FMT_CHAR(S)>::type, Args...> { + typedef typename buffer_context<FMT_CHAR(S)>::type context; + + checked_args(const S &format_str, const Args &... args): + format_arg_store<context, Args...>(args...) { + internal::check_format_string<Args...>(format_str); + } + + basic_format_args<context> operator*() const { return *this; } +}; + +template <typename Char> +std::basic_string<Char> vformat( + basic_string_view<Char> format_str, + basic_format_args<typename buffer_context<Char>::type> args); + +template <typename Char> +typename buffer_context<Char>::type::iterator vformat_to( + internal::basic_buffer<Char> &buf, basic_string_view<Char> format_str, + basic_format_args<typename buffer_context<Char>::type> args); +} + +/** + \rst + Returns a named argument to be used in a formatting function. + + **Example**:: + + fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23)); + \endrst + */ +template <typename T> +inline internal::named_arg<T, char> arg(string_view name, const T &arg) { + return {name, arg}; +} + +template <typename T> +inline internal::named_arg<T, wchar_t> arg(wstring_view name, const T &arg) { + return {name, arg}; +} + +// Disable nested named arguments, e.g. ``arg("a", arg("b", 42))``. +template <typename S, typename T, typename Char> +void arg(S, internal::named_arg<T, Char>) = delete; + +template <typename Container> +struct is_contiguous: std::false_type {}; + +template <typename Char> +struct is_contiguous<std::basic_string<Char> >: std::true_type {}; + +template <typename Char> +struct is_contiguous<internal::basic_buffer<Char> >: std::true_type {}; + +/** Formats a string and writes the output to ``out``. */ +template <typename Container, typename S> +typename std::enable_if< + is_contiguous<Container>::value, std::back_insert_iterator<Container>>::type + vformat_to( + std::back_insert_iterator<Container> out, + const S &format_str, + basic_format_args<typename buffer_context<FMT_CHAR(S)>::type> args) { + internal::container_buffer<Container> buf(internal::get_container(out)); + internal::vformat_to(buf, to_string_view(format_str), args); + return out; +} + +template <typename Container, typename S, typename... Args> +inline typename std::enable_if< + is_contiguous<Container>::value && internal::is_string<S>::value, + std::back_insert_iterator<Container>>::type + format_to(std::back_insert_iterator<Container> out, const S &format_str, + const Args &... args) { + internal::checked_args<S, Args...> ca(format_str, args...); + return vformat_to(out, to_string_view(format_str), *ca); +} + +template <typename S, typename Char = FMT_CHAR(S)> +inline std::basic_string<Char> vformat( + const S &format_str, + basic_format_args<typename buffer_context<Char>::type> args) { + return internal::vformat(to_string_view(format_str), args); +} + +/** + \rst + Formats arguments and returns the result as a string. + + **Example**:: + + #include <fmt/core.h> + std::string message = fmt::format("The answer is {}", 42); + \endrst +*/ +template <typename S, typename... Args> +inline std::basic_string<FMT_CHAR(S)> format( + const S &format_str, const Args &... args) { + return internal::vformat( + to_string_view(format_str), + *internal::checked_args<S, Args...>(format_str, args...)); +} + +FMT_API void vprint(std::FILE *f, string_view format_str, format_args args); +FMT_API void vprint(std::FILE *f, wstring_view format_str, wformat_args args); + +/** + \rst + Prints formatted data to the file *f*. For wide format strings, + *f* should be in wide-oriented mode set via ``fwide(f, 1)`` or + ``_setmode(_fileno(f), _O_U8TEXT)`` on Windows. + + **Example**:: + + fmt::print(stderr, "Don't {}!", "panic"); + \endrst + */ +template <typename S, typename... Args> +inline FMT_ENABLE_IF_T(internal::is_string<S>::value, void) + print(std::FILE *f, const S &format_str, const Args &... args) { + vprint(f, to_string_view(format_str), + internal::checked_args<S, Args...>(format_str, args...)); +} + +FMT_API void vprint(string_view format_str, format_args args); +FMT_API void vprint(wstring_view format_str, wformat_args args); + +/** + \rst + Prints formatted data to ``stdout``. + + **Example**:: + + fmt::print("Elapsed time: {0:.2f} seconds", 1.23); + \endrst + */ +template <typename S, typename... Args> +inline FMT_ENABLE_IF_T(internal::is_string<S>::value, void) + print(const S &format_str, const Args &... args) { + vprint(to_string_view(format_str), + internal::checked_args<S, Args...>(format_str, args...)); +} +FMT_END_NAMESPACE + +#endif // FMT_CORE_H_ diff --git a/matching/include/spdlog/fmt/bundled/format-inl.h b/matching/include/spdlog/fmt/bundled/format-inl.h new file mode 100644 index 0000000..552c943 --- /dev/null +++ b/matching/include/spdlog/fmt/bundled/format-inl.h @@ -0,0 +1,972 @@ +// Formatting library for C++ +// +// Copyright (c) 2012 - 2016, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_FORMAT_INL_H_ +#define FMT_FORMAT_INL_H_ + +#include "format.h" + +#include <string.h> + +#include <cctype> +#include <cerrno> +#include <climits> +#include <cmath> +#include <cstdarg> +#include <cstddef> // for std::ptrdiff_t +#include <cstring> // for std::memmove +#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) +# include <locale> +#endif + +#if FMT_USE_WINDOWS_H +# if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN) +# define WIN32_LEAN_AND_MEAN +# endif +# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX) +# include <windows.h> +# else +# define NOMINMAX +# include <windows.h> +# undef NOMINMAX +# endif +#endif + +#if FMT_EXCEPTIONS +# define FMT_TRY try +# define FMT_CATCH(x) catch (x) +#else +# define FMT_TRY if (true) +# define FMT_CATCH(x) if (false) +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4127) // conditional expression is constant +# pragma warning(disable: 4702) // unreachable code +// Disable deprecation warning for strerror. The latter is not called but +// MSVC fails to detect it. +# pragma warning(disable: 4996) +#endif + +// Dummy implementations of strerror_r and strerror_s called if corresponding +// system functions are not available. +inline fmt::internal::null<> strerror_r(int, char *, ...) { + return fmt::internal::null<>(); +} +inline fmt::internal::null<> strerror_s(char *, std::size_t, ...) { + return fmt::internal::null<>(); +} + +FMT_BEGIN_NAMESPACE + +namespace { + +#ifndef _MSC_VER +# define FMT_SNPRINTF snprintf +#else // _MSC_VER +inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { + va_list args; + va_start(args, format); + int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); + va_end(args); + return result; +} +# define FMT_SNPRINTF fmt_snprintf +#endif // _MSC_VER + +#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) +# define FMT_SWPRINTF snwprintf +#else +# define FMT_SWPRINTF swprintf +#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) + +typedef void (*FormatFunc)(internal::buffer &, int, string_view); + +// Portable thread-safe version of strerror. +// Sets buffer to point to a string describing the error code. +// This can be either a pointer to a string stored in buffer, +// or a pointer to some static immutable string. +// Returns one of the following values: +// 0 - success +// ERANGE - buffer is not large enough to store the error message +// other - failure +// Buffer should be at least of size 1. +int safe_strerror( + int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT { + FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer"); + + class dispatcher { + private: + int error_code_; + char *&buffer_; + std::size_t buffer_size_; + + // A noop assignment operator to avoid bogus warnings. + void operator=(const dispatcher &) {} + + // Handle the result of XSI-compliant version of strerror_r. + int handle(int result) { + // glibc versions before 2.13 return result in errno. + return result == -1 ? errno : result; + } + + // Handle the result of GNU-specific version of strerror_r. + int handle(char *message) { + // If the buffer is full then the message is probably truncated. + if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1) + return ERANGE; + buffer_ = message; + return 0; + } + + // Handle the case when strerror_r is not available. + int handle(internal::null<>) { + return fallback(strerror_s(buffer_, buffer_size_, error_code_)); + } + + // Fallback to strerror_s when strerror_r is not available. + int fallback(int result) { + // If the buffer is full then the message is probably truncated. + return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? + ERANGE : result; + } + +#if !FMT_MSC_VER + // Fallback to strerror if strerror_r and strerror_s are not available. + int fallback(internal::null<>) { + errno = 0; + buffer_ = strerror(error_code_); + return errno; + } +#endif + + public: + dispatcher(int err_code, char *&buf, std::size_t buf_size) + : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} + + int run() { + return handle(strerror_r(error_code_, buffer_, buffer_size_)); + } + }; + return dispatcher(error_code, buffer, buffer_size).run(); +} + +void format_error_code(internal::buffer &out, int error_code, + string_view message) FMT_NOEXCEPT { + // Report error code making sure that the output fits into + // inline_buffer_size to avoid dynamic memory allocation and potential + // bad_alloc. + out.resize(0); + static const char SEP[] = ": "; + static const char ERROR_STR[] = "error "; + // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. + std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; + typedef internal::int_traits<int>::main_type main_type; + main_type abs_value = static_cast<main_type>(error_code); + if (internal::is_negative(error_code)) { + abs_value = 0 - abs_value; + ++error_code_size; + } + error_code_size += internal::to_unsigned(internal::count_digits(abs_value)); + writer w(out); + if (message.size() <= inline_buffer_size - error_code_size) { + w.write(message); + w.write(SEP); + } + w.write(ERROR_STR); + w.write(error_code); + assert(out.size() <= inline_buffer_size); +} + +void report_error(FormatFunc func, int error_code, + string_view message) FMT_NOEXCEPT { + memory_buffer full_message; + func(full_message, error_code, message); + // Use Writer::data instead of Writer::c_str to avoid potential memory + // allocation. + std::fwrite(full_message.data(), full_message.size(), 1, stderr); + std::fputc('\n', stderr); +} +} // namespace + +FMT_FUNC size_t internal::count_code_points(basic_string_view<char8_t> s) { + const char8_t *data = s.data(); + size_t num_code_points = 0; + for (size_t i = 0, size = s.size(); i != size; ++i) { + if ((data[i] & 0xc0) != 0x80) + ++num_code_points; + } + return num_code_points; +} + +#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) +namespace internal { + +template <typename Locale> +locale_ref::locale_ref(const Locale &loc) : locale_(&loc) { + static_assert(std::is_same<Locale, std::locale>::value, ""); +} + +template <typename Locale> +Locale locale_ref::get() const { + static_assert(std::is_same<Locale, std::locale>::value, ""); + return locale_ ? *static_cast<const std::locale*>(locale_) : std::locale(); +} + +template <typename Char> +FMT_FUNC Char thousands_sep_impl(locale_ref loc) { + return std::use_facet<std::numpunct<Char> >( + loc.get<std::locale>()).thousands_sep(); +} +} +#else +template <typename Char> +FMT_FUNC Char internal::thousands_sep_impl(locale_ref) { + return FMT_STATIC_THOUSANDS_SEPARATOR; +} +#endif + +FMT_FUNC void system_error::init( + int err_code, string_view format_str, format_args args) { + error_code_ = err_code; + memory_buffer buffer; + format_system_error(buffer, err_code, vformat(format_str, args)); + std::runtime_error &base = *this; + base = std::runtime_error(to_string(buffer)); +} + +namespace internal { +template <typename T> +int char_traits<char>::format_float( + char *buf, std::size_t size, const char *format, int precision, T value) { + return precision < 0 ? + FMT_SNPRINTF(buf, size, format, value) : + FMT_SNPRINTF(buf, size, format, precision, value); +} + +template <typename T> +int char_traits<wchar_t>::format_float( + wchar_t *buf, std::size_t size, const wchar_t *format, int precision, + T value) { + return precision < 0 ? + FMT_SWPRINTF(buf, size, format, value) : + FMT_SWPRINTF(buf, size, format, precision, value); +} + +template <typename T> +const char basic_data<T>::DIGITS[] = + "0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899"; + +#define FMT_POWERS_OF_10(factor) \ + factor * 10, \ + factor * 100, \ + factor * 1000, \ + factor * 10000, \ + factor * 100000, \ + factor * 1000000, \ + factor * 10000000, \ + factor * 100000000, \ + factor * 1000000000 + +template <typename T> +const uint32_t basic_data<T>::POWERS_OF_10_32[] = { + 1, FMT_POWERS_OF_10(1) +}; + +template <typename T> +const uint32_t basic_data<T>::ZERO_OR_POWERS_OF_10_32[] = { + 0, FMT_POWERS_OF_10(1) +}; + +template <typename T> +const uint64_t basic_data<T>::ZERO_OR_POWERS_OF_10_64[] = { + 0, + FMT_POWERS_OF_10(1), + FMT_POWERS_OF_10(1000000000ull), + 10000000000000000000ull +}; + +// Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340. +// These are generated by support/compute-powers.py. +template <typename T> +const uint64_t basic_data<T>::POW10_SIGNIFICANDS[] = { + 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76, + 0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df, + 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c, + 0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5, + 0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57, + 0xc21094364dfb5637, 0x9096ea6f3848984f, 0xd77485cb25823ac7, + 0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e, + 0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996, + 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126, + 0xb5b5ada8aaff80b8, 0x87625f056c7c4a8b, 0xc9bcff6034c13053, + 0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f, + 0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b, + 0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06, + 0xaa242499697392d3, 0xfd87b5f28300ca0e, 0xbce5086492111aeb, + 0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000, + 0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984, + 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068, + 0x9f4f2726179a2245, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8, + 0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758, + 0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85, + 0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d, + 0x952ab45cfa97a0b3, 0xde469fbd99a05fe3, 0xa59bc234db398c25, + 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2, + 0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a, + 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410, + 0x8bab8eefb6409c1a, 0xd01fef10a657842c, 0x9b10a4e5e9913129, + 0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85, + 0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841, + 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b, +}; + +// Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding +// to significands above. +template <typename T> +const int16_t basic_data<T>::POW10_EXPONENTS[] = { + -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, + -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661, + -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369, + -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77, + -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, + 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508, + 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, + 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066 +}; + +template <typename T> const char basic_data<T>::FOREGROUND_COLOR[] = "\x1b[38;2;"; +template <typename T> const char basic_data<T>::BACKGROUND_COLOR[] = "\x1b[48;2;"; +template <typename T> const char basic_data<T>::RESET_COLOR[] = "\x1b[0m"; +template <typename T> const wchar_t basic_data<T>::WRESET_COLOR[] = L"\x1b[0m"; + +// A handmade floating-point number f * pow(2, e). +class fp { + private: + typedef uint64_t significand_type; + + // All sizes are in bits. + static FMT_CONSTEXPR_DECL const int char_size = + std::numeric_limits<unsigned char>::digits; + // Subtract 1 to account for an implicit most significant bit in the + // normalized form. + static FMT_CONSTEXPR_DECL const int double_significand_size = + std::numeric_limits<double>::digits - 1; + static FMT_CONSTEXPR_DECL const uint64_t implicit_bit = + 1ull << double_significand_size; + + public: + significand_type f; + int e; + + static FMT_CONSTEXPR_DECL const int significand_size = + sizeof(significand_type) * char_size; + + fp(): f(0), e(0) {} + fp(uint64_t f_val, int e_val): f(f_val), e(e_val) {} + + // Constructs fp from an IEEE754 double. It is a template to prevent compile + // errors on platforms where double is not IEEE754. + template <typename Double> + explicit fp(Double d) { + // Assume double is in the format [sign][exponent][significand]. + typedef std::numeric_limits<Double> limits; + const int double_size = static_cast<int>(sizeof(Double) * char_size); + const int exponent_size = + double_size - double_significand_size - 1; // -1 for sign + const uint64_t significand_mask = implicit_bit - 1; + const uint64_t exponent_mask = (~0ull >> 1) & ~significand_mask; + const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1; + auto u = bit_cast<uint64_t>(d); + auto biased_e = (u & exponent_mask) >> double_significand_size; + f = u & significand_mask; + if (biased_e != 0) + f += implicit_bit; + else + biased_e = 1; // Subnormals use biased exponent 1 (min exponent). + e = static_cast<int>(biased_e - exponent_bias - double_significand_size); + } + + // Normalizes the value converted from double and multiplied by (1 << SHIFT). + template <int SHIFT = 0> + void normalize() { + // Handle subnormals. + auto shifted_implicit_bit = implicit_bit << SHIFT; + while ((f & shifted_implicit_bit) == 0) { + f <<= 1; + --e; + } + // Subtract 1 to account for hidden bit. + auto offset = significand_size - double_significand_size - SHIFT - 1; + f <<= offset; + e -= offset; + } + + // Compute lower and upper boundaries (m^- and m^+ in the Grisu paper), where + // a boundary is a value half way between the number and its predecessor + // (lower) or successor (upper). The upper boundary is normalized and lower + // has the same exponent but may be not normalized. + void compute_boundaries(fp &lower, fp &upper) const { + lower = f == implicit_bit ? + fp((f << 2) - 1, e - 2) : fp((f << 1) - 1, e - 1); + upper = fp((f << 1) + 1, e - 1); + upper.normalize<1>(); // 1 is to account for the exponent shift above. + lower.f <<= lower.e - upper.e; + lower.e = upper.e; + } +}; + +// Returns an fp number representing x - y. Result may not be normalized. +inline fp operator-(fp x, fp y) { + FMT_ASSERT(x.f >= y.f && x.e == y.e, "invalid operands"); + return fp(x.f - y.f, x.e); +} + +// Computes an fp number r with r.f = x.f * y.f / pow(2, 64) rounded to nearest +// with half-up tie breaking, r.e = x.e + y.e + 64. Result may not be normalized. +FMT_API fp operator*(fp x, fp y); + +// Returns cached power (of 10) c_k = c_k.f * pow(2, c_k.e) such that its +// (binary) exponent satisfies min_exponent <= c_k.e <= min_exponent + 3. +FMT_API fp get_cached_power(int min_exponent, int &pow10_exponent); + +FMT_FUNC fp operator*(fp x, fp y) { + // Multiply 32-bit parts of significands. + uint64_t mask = (1ULL << 32) - 1; + uint64_t a = x.f >> 32, b = x.f & mask; + uint64_t c = y.f >> 32, d = y.f & mask; + uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d; + // Compute mid 64-bit of result and round. + uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31); + return fp(ac + (ad >> 32) + (bc >> 32) + (mid >> 32), x.e + y.e + 64); +} + +FMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) { + const double one_over_log2_10 = 0.30102999566398114; // 1 / log2(10) + int index = static_cast<int>(std::ceil( + (min_exponent + fp::significand_size - 1) * one_over_log2_10)); + // Decimal exponent of the first (smallest) cached power of 10. + const int first_dec_exp = -348; + // Difference between 2 consecutive decimal exponents in cached powers of 10. + const int dec_exp_step = 8; + index = (index - first_dec_exp - 1) / dec_exp_step + 1; + pow10_exponent = first_dec_exp + index * dec_exp_step; + return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]); +} + +FMT_FUNC bool grisu2_round( + char *buf, int &size, int max_digits, uint64_t delta, + uint64_t remainder, uint64_t exp, uint64_t diff, int &exp10) { + while (remainder < diff && delta - remainder >= exp && + (remainder + exp < diff || diff - remainder > remainder + exp - diff)) { + --buf[size - 1]; + remainder += exp; + } + if (size > max_digits) { + --size; + ++exp10; + if (buf[size] >= '5') + return false; + } + return true; +} + +// Generates output using Grisu2 digit-gen algorithm. +FMT_FUNC bool grisu2_gen_digits( + char *buf, int &size, uint32_t hi, uint64_t lo, int &exp, + uint64_t delta, const fp &one, const fp &diff, int max_digits) { + // Generate digits for the most significant part (hi). + while (exp > 0) { + uint32_t digit = 0; + // This optimization by miloyip reduces the number of integer divisions by + // one per iteration. + switch (exp) { + case 10: digit = hi / 1000000000; hi %= 1000000000; break; + case 9: digit = hi / 100000000; hi %= 100000000; break; + case 8: digit = hi / 10000000; hi %= 10000000; break; + case 7: digit = hi / 1000000; hi %= 1000000; break; + case 6: digit = hi / 100000; hi %= 100000; break; + case 5: digit = hi / 10000; hi %= 10000; break; + case 4: digit = hi / 1000; hi %= 1000; break; + case 3: digit = hi / 100; hi %= 100; break; + case 2: digit = hi / 10; hi %= 10; break; + case 1: digit = hi; hi = 0; break; + default: + FMT_ASSERT(false, "invalid number of digits"); + } + if (digit != 0 || size != 0) + buf[size++] = static_cast<char>('0' + digit); + --exp; + uint64_t remainder = (static_cast<uint64_t>(hi) << -one.e) + lo; + if (remainder <= delta || size > max_digits) { + return grisu2_round( + buf, size, max_digits, delta, remainder, + static_cast<uint64_t>(data::POWERS_OF_10_32[exp]) << -one.e, + diff.f, exp); + } + } + // Generate digits for the least significant part (lo). + for (;;) { + lo *= 10; + delta *= 10; + char digit = static_cast<char>(lo >> -one.e); + if (digit != 0 || size != 0) + buf[size++] = static_cast<char>('0' + digit); + lo &= one.f - 1; + --exp; + if (lo < delta || size > max_digits) { + return grisu2_round(buf, size, max_digits, delta, lo, one.f, + diff.f * data::POWERS_OF_10_32[-exp], exp); + } + } +} + +#if FMT_CLANG_VERSION +# define FMT_FALLTHROUGH [[clang::fallthrough]]; +#elif FMT_GCC_VERSION >= 700 +# define FMT_FALLTHROUGH [[gnu::fallthrough]]; +#else +# define FMT_FALLTHROUGH +#endif + +struct gen_digits_params { + int num_digits; + bool fixed; + bool upper; + bool trailing_zeros; +}; + +struct prettify_handler { + char *data; + ptrdiff_t size; + buffer &buf; + + explicit prettify_handler(buffer &b, ptrdiff_t n) + : data(b.data()), size(n), buf(b) {} + ~prettify_handler() { + assert(buf.size() >= to_unsigned(size)); + buf.resize(to_unsigned(size)); + } + + template <typename F> + void insert(ptrdiff_t pos, ptrdiff_t n, F f) { + std::memmove(data + pos + n, data + pos, to_unsigned(size - pos)); + f(data + pos); + size += n; + } + + void insert(ptrdiff_t pos, char c) { + std::memmove(data + pos + 1, data + pos, to_unsigned(size - pos)); + data[pos] = c; + ++size; + } + + void append(ptrdiff_t n, char c) { + std::uninitialized_fill_n(data + size, n, c); + size += n; + } + + void append(char c) { data[size++] = c; } + + void remove_trailing(char c) { + while (data[size - 1] == c) --size; + } +}; + +// Writes the exponent exp in the form "[+-]d{2,3}" to buffer. +template <typename Handler> +FMT_FUNC void write_exponent(int exp, Handler &&h) { + FMT_ASSERT(-1000 < exp && exp < 1000, "exponent out of range"); + if (exp < 0) { + h.append('-'); + exp = -exp; + } else { + h.append('+'); + } + if (exp >= 100) { + h.append(static_cast<char>('0' + exp / 100)); + exp %= 100; + const char *d = data::DIGITS + exp * 2; + h.append(d[0]); + h.append(d[1]); + } else { + const char *d = data::DIGITS + exp * 2; + h.append(d[0]); + h.append(d[1]); + } +} + +struct fill { + size_t n; + void operator()(char *buf) const { + buf[0] = '0'; + buf[1] = '.'; + std::uninitialized_fill_n(buf + 2, n, '0'); + } +}; + +// The number is given as v = f * pow(10, exp), where f has size digits. +template <typename Handler> +FMT_FUNC void grisu2_prettify(const gen_digits_params ¶ms, + int size, int exp, Handler &&handler) { + if (!params.fixed) { + // Insert a decimal point after the first digit and add an exponent. + handler.insert(1, '.'); + exp += size - 1; + if (size < params.num_digits) + handler.append(params.num_digits - size, '0'); + handler.append(params.upper ? 'E' : 'e'); + write_exponent(exp, handler); + return; + } + // pow(10, full_exp - 1) <= v <= pow(10, full_exp). + int full_exp = size + exp; + const int exp_threshold = 21; + if (size <= full_exp && full_exp <= exp_threshold) { + // 1234e7 -> 12340000000[.0+] + handler.append(full_exp - size, '0'); + int num_zeros = params.num_digits - full_exp; + if (num_zeros > 0 && params.trailing_zeros) { + handler.append('.'); + handler.append(num_zeros, '0'); + } + } else if (full_exp > 0) { + // 1234e-2 -> 12.34[0+] + handler.insert(full_exp, '.'); + if (!params.trailing_zeros) { + // Remove trailing zeros. + handler.remove_trailing('0'); + } else if (params.num_digits > size) { + // Add trailing zeros. + ptrdiff_t num_zeros = params.num_digits - size; + handler.append(num_zeros, '0'); + } + } else { + // 1234e-6 -> 0.001234 + handler.insert(0, 2 - full_exp, fill{to_unsigned(-full_exp)}); + } +} + +struct char_counter { + ptrdiff_t size; + + template <typename F> + void insert(ptrdiff_t, ptrdiff_t n, F) { size += n; } + void insert(ptrdiff_t, char) { ++size; } + void append(ptrdiff_t n, char) { size += n; } + void append(char) { ++size; } + void remove_trailing(char) {} +}; + +// Converts format specifiers into parameters for digit generation and computes +// output buffer size for a number in the range [pow(10, exp - 1), pow(10, exp) +// or 0 if exp == 1. +FMT_FUNC gen_digits_params process_specs(const core_format_specs &specs, + int exp, buffer &buf) { + auto params = gen_digits_params(); + int num_digits = specs.precision >= 0 ? specs.precision : 6; + switch (specs.type) { + case 'G': + params.upper = true; + FMT_FALLTHROUGH + case '\0': case 'g': + params.trailing_zeros = (specs.flags & HASH_FLAG) != 0; + if (-4 <= exp && exp < num_digits + 1) { + params.fixed = true; + if (!specs.type && params.trailing_zeros && exp >= 0) + num_digits = exp + 1; + } + break; + case 'F': + params.upper = true; + FMT_FALLTHROUGH + case 'f': { + params.fixed = true; + params.trailing_zeros = true; + int adjusted_min_digits = num_digits + exp; + if (adjusted_min_digits > 0) + num_digits = adjusted_min_digits; + break; + } + case 'E': + params.upper = true; + FMT_FALLTHROUGH + case 'e': + ++num_digits; + break; + } + params.num_digits = num_digits; + char_counter counter{num_digits}; + grisu2_prettify(params, params.num_digits, exp - num_digits, counter); + buf.resize(to_unsigned(counter.size)); + return params; +} + +template <typename Double> +FMT_FUNC typename std::enable_if<sizeof(Double) == sizeof(uint64_t), bool>::type + grisu2_format(Double value, buffer &buf, core_format_specs specs) { + FMT_ASSERT(value >= 0, "value is negative"); + if (value == 0) { + gen_digits_params params = process_specs(specs, 1, buf); + const size_t size = 1; + buf[0] = '0'; + grisu2_prettify(params, size, 0, prettify_handler(buf, size)); + return true; + } + + fp fp_value(value); + fp lower, upper; // w^- and w^+ in the Grisu paper. + fp_value.compute_boundaries(lower, upper); + + // Find a cached power of 10 close to 1 / upper and use it to scale upper. + const int min_exp = -60; // alpha in Grisu. + int cached_exp = 0; // K in Grisu. + auto cached_pow = get_cached_power( // \tilde{c}_{-k} in Grisu. + min_exp - (upper.e + fp::significand_size), cached_exp); + cached_exp = -cached_exp; + upper = upper * cached_pow; // \tilde{M}^+ in Grisu. + --upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}. + fp one(1ull << -upper.e, upper.e); + // hi (p1 in Grisu) contains the most significant digits of scaled_upper. + // hi = floor(upper / one). + uint32_t hi = static_cast<uint32_t>(upper.f >> -one.e); + int exp = count_digits(hi); // kappa in Grisu. + gen_digits_params params = process_specs(specs, cached_exp + exp, buf); + fp_value.normalize(); + fp scaled_value = fp_value * cached_pow; + lower = lower * cached_pow; // \tilde{M}^- in Grisu. + ++lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}. + uint64_t delta = upper.f - lower.f; + fp diff = upper - scaled_value; // wp_w in Grisu. + // lo (p2 in Grisu) contains the least significants digits of scaled_upper. + // lo = supper % one. + uint64_t lo = upper.f & (one.f - 1); + int size = 0; + if (!grisu2_gen_digits(buf.data(), size, hi, lo, exp, delta, one, diff, + params.num_digits)) { + buf.clear(); + return false; + } + grisu2_prettify(params, size, cached_exp + exp, prettify_handler(buf, size)); + return true; +} + +template <typename Double> +void sprintf_format(Double value, internal::buffer &buf, + core_format_specs spec) { + // Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail. + FMT_ASSERT(buf.capacity() != 0, "empty buffer"); + + // Build format string. + enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg + char format[MAX_FORMAT_SIZE]; + char *format_ptr = format; + *format_ptr++ = '%'; + if (spec.has(HASH_FLAG)) + *format_ptr++ = '#'; + if (spec.precision >= 0) { + *format_ptr++ = '.'; + *format_ptr++ = '*'; + } + if (std::is_same<Double, long double>::value) + *format_ptr++ = 'L'; + *format_ptr++ = spec.type; + *format_ptr = '\0'; + + // Format using snprintf. + char *start = FMT_NULL; + for (;;) { + std::size_t buffer_size = buf.capacity(); + start = &buf[0]; + int result = internal::char_traits<char>::format_float( + start, buffer_size, format, spec.precision, value); + if (result >= 0) { + unsigned n = internal::to_unsigned(result); + if (n < buf.capacity()) { + buf.resize(n); + break; // The buffer is large enough - continue with formatting. + } + buf.reserve(n + 1); + } else { + // If result is negative we ask to increase the capacity by at least 1, + // but as std::vector, the buffer grows exponentially. + buf.reserve(buf.capacity() + 1); + } + } +} +} // namespace internal + +#if FMT_USE_WINDOWS_H + +FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) { + static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; + if (s.size() > INT_MAX) + FMT_THROW(windows_error(ERROR_INVALID_PARAMETER, ERROR_MSG)); + int s_size = static_cast<int>(s.size()); + if (s_size == 0) { + // MultiByteToWideChar does not support zero length, handle separately. + buffer_.resize(1); + buffer_[0] = 0; + return; + } + + int length = MultiByteToWideChar( + CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0); + if (length == 0) + FMT_THROW(windows_error(GetLastError(), ERROR_MSG)); + buffer_.resize(length + 1); + length = MultiByteToWideChar( + CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length); + if (length == 0) + FMT_THROW(windows_error(GetLastError(), ERROR_MSG)); + buffer_[length] = 0; +} + +FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) { + if (int error_code = convert(s)) { + FMT_THROW(windows_error(error_code, + "cannot convert string from UTF-16 to UTF-8")); + } +} + +FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) { + if (s.size() > INT_MAX) + return ERROR_INVALID_PARAMETER; + int s_size = static_cast<int>(s.size()); + if (s_size == 0) { + // WideCharToMultiByte does not support zero length, handle separately. + buffer_.resize(1); + buffer_[0] = 0; + return 0; + } + + int length = WideCharToMultiByte( + CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL); + if (length == 0) + return GetLastError(); + buffer_.resize(length + 1); + length = WideCharToMultiByte( + CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL); + if (length == 0) + return GetLastError(); + buffer_[length] = 0; + return 0; +} + +FMT_FUNC void windows_error::init( + int err_code, string_view format_str, format_args args) { + error_code_ = err_code; + memory_buffer buffer; + internal::format_windows_error(buffer, err_code, vformat(format_str, args)); + std::runtime_error &base = *this; + base = std::runtime_error(to_string(buffer)); +} + +FMT_FUNC void internal::format_windows_error( + internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT { + FMT_TRY { + wmemory_buffer buf; + buf.resize(inline_buffer_size); + for (;;) { + wchar_t *system_message = &buf[0]; + int result = FormatMessageW( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + system_message, static_cast<uint32_t>(buf.size()), FMT_NULL); + if (result != 0) { + utf16_to_utf8 utf8_message; + if (utf8_message.convert(system_message) == ERROR_SUCCESS) { + writer w(out); + w.write(message); + w.write(": "); + w.write(utf8_message); + return; + } + break; + } + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + break; // Can't get error message, report error code instead. + buf.resize(buf.size() * 2); + } + } FMT_CATCH(...) {} + format_error_code(out, error_code, message); +} + +#endif // FMT_USE_WINDOWS_H + +FMT_FUNC void format_system_error( + internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT { + FMT_TRY { + memory_buffer buf; + buf.resize(inline_buffer_size); + for (;;) { + char *system_message = &buf[0]; + int result = safe_strerror(error_code, system_message, buf.size()); + if (result == 0) { + writer w(out); + w.write(message); + w.write(": "); + w.write(system_message); + return; + } + if (result != ERANGE) + break; // Can't get error message, report error code instead. + buf.resize(buf.size() * 2); + } + } FMT_CATCH(...) {} + format_error_code(out, error_code, message); +} + +FMT_FUNC void internal::error_handler::on_error(const char *message) { + FMT_THROW(format_error(message)); +} + +FMT_FUNC void report_system_error( + int error_code, fmt::string_view message) FMT_NOEXCEPT { + report_error(format_system_error, error_code, message); +} + +#if FMT_USE_WINDOWS_H +FMT_FUNC void report_windows_error( + int error_code, fmt::string_view message) FMT_NOEXCEPT { + report_error(internal::format_windows_error, error_code, message); +} +#endif + +FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) { + memory_buffer buffer; + internal::vformat_to(buffer, format_str, + basic_format_args<buffer_context<char>::type>(args)); + std::fwrite(buffer.data(), 1, buffer.size(), f); +} + +FMT_FUNC void vprint(std::FILE *f, wstring_view format_str, wformat_args args) { + wmemory_buffer buffer; + internal::vformat_to(buffer, format_str, args); + std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f); +} + +FMT_FUNC void vprint(string_view format_str, format_args args) { + vprint(stdout, format_str, args); +} + +FMT_FUNC void vprint(wstring_view format_str, wformat_args args) { + vprint(stdout, format_str, args); +} + +FMT_END_NAMESPACE + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif // FMT_FORMAT_INL_H_ diff --git a/matching/include/spdlog/fmt/bundled/format.h b/matching/include/spdlog/fmt/bundled/format.h new file mode 100644 index 0000000..1bb24a5 --- /dev/null +++ b/matching/include/spdlog/fmt/bundled/format.h @@ -0,0 +1,3555 @@ +/* + Formatting library for C++ + + Copyright (c) 2012 - present, Victor Zverovich + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FMT_FORMAT_H_ +#define FMT_FORMAT_H_ + +#include <algorithm> +#include <cassert> +#include <cmath> +#include <cstring> +#include <limits> +#include <memory> +#include <stdexcept> +#include <stdint.h> + +#ifdef __clang__ +# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) +#else +# define FMT_CLANG_VERSION 0 +#endif + +#ifdef __INTEL_COMPILER +# define FMT_ICC_VERSION __INTEL_COMPILER +#elif defined(__ICL) +# define FMT_ICC_VERSION __ICL +#else +# define FMT_ICC_VERSION 0 +#endif + +#ifdef __NVCC__ +# define FMT_CUDA_VERSION (__CUDACC_VER_MAJOR__ * 100 + __CUDACC_VER_MINOR__) +#else +# define FMT_CUDA_VERSION 0 +#endif + +#include "core.h" + +#if FMT_GCC_VERSION >= 406 || FMT_CLANG_VERSION +# pragma GCC diagnostic push + +// Disable the warning about declaration shadowing because it affects too +// many valid cases. +# pragma GCC diagnostic ignored "-Wshadow" + +// Disable the warning about nonliteral format strings because we construct +// them dynamically when falling back to snprintf for FP formatting. +# pragma GCC diagnostic ignored "-Wformat-nonliteral" +#endif + +# if FMT_CLANG_VERSION +# pragma GCC diagnostic ignored "-Wgnu-string-literal-operator-template" +# endif + +#ifdef _SECURE_SCL +# define FMT_SECURE_SCL _SECURE_SCL +#else +# define FMT_SECURE_SCL 0 +#endif + +#if FMT_SECURE_SCL +# include <iterator> +#endif + +#ifdef __has_builtin +# define FMT_HAS_BUILTIN(x) __has_builtin(x) +#else +# define FMT_HAS_BUILTIN(x) 0 +#endif + +#ifdef __GNUC_LIBSTD__ +# define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__) +#endif + +#ifndef FMT_THROW +# if FMT_EXCEPTIONS +# if FMT_MSC_VER +FMT_BEGIN_NAMESPACE +namespace internal { +template <typename Exception> +inline void do_throw(const Exception &x) { + // Silence unreachable code warnings in MSVC because these are nearly + // impossible to fix in a generic code. + volatile bool b = true; + if (b) + throw x; +} +} +FMT_END_NAMESPACE +# define FMT_THROW(x) fmt::internal::do_throw(x) +# else +# define FMT_THROW(x) throw x +# endif +# else +# define FMT_THROW(x) do { static_cast<void>(sizeof(x)); assert(false); } while(false); +# endif +#endif + +#ifndef FMT_USE_USER_DEFINED_LITERALS +// For Intel's compiler and NVIDIA's compiler both it and the system gcc/msc +// must support UDLs. +# if (FMT_HAS_FEATURE(cxx_user_literals) || \ + FMT_GCC_VERSION >= 407 || FMT_MSC_VER >= 1900) && \ + (!(FMT_ICC_VERSION || FMT_CUDA_VERSION) || \ + FMT_ICC_VERSION >= 1500 || FMT_CUDA_VERSION >= 700) +# define FMT_USE_USER_DEFINED_LITERALS 1 +# else +# define FMT_USE_USER_DEFINED_LITERALS 0 +# endif +#endif + +// EDG C++ Front End based compilers (icc, nvcc) do not currently support UDL +// templates. +#if FMT_USE_USER_DEFINED_LITERALS && \ + FMT_ICC_VERSION == 0 && \ + FMT_CUDA_VERSION == 0 && \ + ((FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L) || \ + (defined(FMT_CLANG_VERSION) && FMT_CLANG_VERSION >= 304)) +# define FMT_UDL_TEMPLATE 1 +#else +# define FMT_UDL_TEMPLATE 0 +#endif + +#ifndef FMT_USE_EXTERN_TEMPLATES +# ifndef FMT_HEADER_ONLY +# define FMT_USE_EXTERN_TEMPLATES \ + ((FMT_CLANG_VERSION >= 209 && __cplusplus >= 201103L) || \ + (FMT_GCC_VERSION >= 303 && FMT_HAS_GXX_CXX11)) +# else +# define FMT_USE_EXTERN_TEMPLATES 0 +# endif +#endif + +#if FMT_HAS_GXX_CXX11 || FMT_HAS_FEATURE(cxx_trailing_return) || \ + FMT_MSC_VER >= 1600 +# define FMT_USE_TRAILING_RETURN 1 +#else +# define FMT_USE_TRAILING_RETURN 0 +#endif + +#ifndef FMT_USE_GRISU +# define FMT_USE_GRISU 0 +//# define FMT_USE_GRISU std::numeric_limits<double>::is_iec559 +#endif + +// __builtin_clz is broken in clang with Microsoft CodeGen: +// https://github.com/fmtlib/fmt/issues/519 +#ifndef _MSC_VER +# if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) +# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) +# endif + +# if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) +# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) +# endif +#endif + +// Some compilers masquerade as both MSVC and GCC-likes or otherwise support +// __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the +// MSVC intrinsics if the clz and clzll builtins are not available. +#if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && !defined(_MANAGED) +# include <intrin.h> // _BitScanReverse, _BitScanReverse64 + +FMT_BEGIN_NAMESPACE +namespace internal { +// Avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning. +# ifndef __clang__ +# pragma intrinsic(_BitScanReverse) +# endif +inline uint32_t clz(uint32_t x) { + unsigned long r = 0; + _BitScanReverse(&r, x); + + assert(x != 0); + // Static analysis complains about using uninitialized data + // "r", but the only way that can happen is if "x" is 0, + // which the callers guarantee to not happen. +# pragma warning(suppress: 6102) + return 31 - r; +} +# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n) + +# if defined(_WIN64) && !defined(__clang__) +# pragma intrinsic(_BitScanReverse64) +# endif + +inline uint32_t clzll(uint64_t x) { + unsigned long r = 0; +# ifdef _WIN64 + _BitScanReverse64(&r, x); +# else + // Scan the high 32 bits. + if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32))) + return 63 - (r + 32); + + // Scan the low 32 bits. + _BitScanReverse(&r, static_cast<uint32_t>(x)); +# endif + + assert(x != 0); + // Static analysis complains about using uninitialized data + // "r", but the only way that can happen is if "x" is 0, + // which the callers guarantee to not happen. +# pragma warning(suppress: 6102) + return 63 - r; +} +# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n) +} +FMT_END_NAMESPACE +#endif + +FMT_BEGIN_NAMESPACE +namespace internal { + +// An equivalent of `*reinterpret_cast<Dest*>(&source)` that doesn't produce +// undefined behavior (e.g. due to type aliasing). +// Example: uint64_t d = bit_cast<uint64_t>(2.718); +template <typename Dest, typename Source> +inline Dest bit_cast(const Source& source) { + static_assert(sizeof(Dest) == sizeof(Source), "size mismatch"); + Dest dest; + std::memcpy(&dest, &source, sizeof(dest)); + return dest; +} + +// An implementation of begin and end for pre-C++11 compilers such as gcc 4. +template <typename C> +FMT_CONSTEXPR auto begin(const C &c) -> decltype(c.begin()) { + return c.begin(); +} +template <typename T, std::size_t N> +FMT_CONSTEXPR T *begin(T (&array)[N]) FMT_NOEXCEPT { return array; } +template <typename C> +FMT_CONSTEXPR auto end(const C &c) -> decltype(c.end()) { return c.end(); } +template <typename T, std::size_t N> +FMT_CONSTEXPR T *end(T (&array)[N]) FMT_NOEXCEPT { return array + N; } + +// For std::result_of in gcc 4.4. +template <typename Result> +struct function { + template <typename T> + struct result { typedef Result type; }; +}; + +struct dummy_int { + int data[2]; + operator int() const { return 0; } +}; +typedef std::numeric_limits<internal::dummy_int> fputil; + +// Dummy implementations of system functions called if the latter are not +// available. +inline dummy_int isinf(...) { return dummy_int(); } +inline dummy_int _finite(...) { return dummy_int(); } +inline dummy_int isnan(...) { return dummy_int(); } +inline dummy_int _isnan(...) { return dummy_int(); } + +template <typename Allocator> +typename Allocator::value_type *allocate(Allocator& alloc, std::size_t n) { +#if __cplusplus >= 201103L || FMT_MSC_VER >= 1700 + return std::allocator_traits<Allocator>::allocate(alloc, n); +#else + return alloc.allocate(n); +#endif +} + +// A helper function to suppress bogus "conditional expression is constant" +// warnings. +template <typename T> +inline T const_check(T value) { return value; } +} // namespace internal +FMT_END_NAMESPACE + +namespace std { +// Standard permits specialization of std::numeric_limits. This specialization +// is used to resolve ambiguity between isinf and std::isinf in glibc: +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48891 +// and the same for isnan. +template <> +class numeric_limits<fmt::internal::dummy_int> : + public std::numeric_limits<int> { + public: + // Portable version of isinf. + template <typename T> + static bool isinfinity(T x) { + using namespace fmt::internal; + // The resolution "priority" is: + // isinf macro > std::isinf > ::isinf > fmt::internal::isinf + if (const_check(sizeof(isinf(x)) != sizeof(fmt::internal::dummy_int))) + return isinf(x) != 0; + return !_finite(static_cast<double>(x)); + } + + // Portable version of isnan. + template <typename T> + static bool isnotanumber(T x) { + using namespace fmt::internal; + if (const_check(sizeof(isnan(x)) != sizeof(fmt::internal::dummy_int))) + return isnan(x) != 0; + return _isnan(static_cast<double>(x)) != 0; + } +}; +} // namespace std + +FMT_BEGIN_NAMESPACE +template <typename Range> +class basic_writer; + +template <typename OutputIt, typename T = typename OutputIt::value_type> +class output_range { + private: + OutputIt it_; + + // Unused yet. + typedef void sentinel; + sentinel end() const; + + public: + typedef OutputIt iterator; + typedef T value_type; + + explicit output_range(OutputIt it): it_(it) {} + OutputIt begin() const { return it_; } +}; + +// A range where begin() returns back_insert_iterator. +template <typename Container> +class back_insert_range: + public output_range<std::back_insert_iterator<Container>> { + typedef output_range<std::back_insert_iterator<Container>> base; + public: + typedef typename Container::value_type value_type; + + back_insert_range(Container &c): base(std::back_inserter(c)) {} + back_insert_range(typename base::iterator it): base(it) {} +}; + +typedef basic_writer<back_insert_range<internal::buffer>> writer; +typedef basic_writer<back_insert_range<internal::wbuffer>> wwriter; + +/** A formatting error such as invalid format string. */ +class format_error : public std::runtime_error { + public: + explicit format_error(const char *message) + : std::runtime_error(message) {} + + explicit format_error(const std::string &message) + : std::runtime_error(message) {} +}; + +namespace internal { + +#if FMT_SECURE_SCL +template <typename T> +struct checked { typedef stdext::checked_array_iterator<T*> type; }; + +// Make a checked iterator to avoid warnings on MSVC. +template <typename T> +inline stdext::checked_array_iterator<T*> make_checked(T *p, std::size_t size) { + return {p, size}; +} +#else +template <typename T> +struct checked { typedef T *type; }; +template <typename T> +inline T *make_checked(T *p, std::size_t) { return p; } +#endif + +template <typename T> +template <typename U> +void basic_buffer<T>::append(const U *begin, const U *end) { + std::size_t new_size = size_ + internal::to_unsigned(end - begin); + reserve(new_size); + std::uninitialized_copy(begin, end, + internal::make_checked(ptr_, capacity_) + size_); + size_ = new_size; +} +} // namespace internal + +// C++20 feature test, since r346892 Clang considers char8_t a fundamental +// type in this mode. If this is the case __cpp_char8_t will be defined. +#if !defined(__cpp_char8_t) +// A UTF-8 code unit type. +enum char8_t: unsigned char {}; +#endif + +// A UTF-8 string view. +class u8string_view : public basic_string_view<char8_t> { + public: + typedef char8_t char_type; + + u8string_view(const char *s): + basic_string_view<char8_t>(reinterpret_cast<const char8_t*>(s)) {} + u8string_view(const char *s, size_t count) FMT_NOEXCEPT: + basic_string_view<char8_t>(reinterpret_cast<const char8_t*>(s), count) {} +}; + +#if FMT_USE_USER_DEFINED_LITERALS +inline namespace literals { +inline u8string_view operator"" _u(const char *s, std::size_t n) { + return {s, n}; +} +} +#endif + +// The number of characters to store in the basic_memory_buffer object itself +// to avoid dynamic memory allocation. +enum { inline_buffer_size = 500 }; + +/** + \rst + A dynamically growing memory buffer for trivially copyable/constructible types + with the first ``SIZE`` elements stored in the object itself. + + You can use one of the following typedefs for common character types: + + +----------------+------------------------------+ + | Type | Definition | + +================+==============================+ + | memory_buffer | basic_memory_buffer<char> | + +----------------+------------------------------+ + | wmemory_buffer | basic_memory_buffer<wchar_t> | + +----------------+------------------------------+ + + **Example**:: + + fmt::memory_buffer out; + format_to(out, "The answer is {}.", 42); + + This will append the following output to the ``out`` object: + + .. code-block:: none + + The answer is 42. + + The output can be converted to an ``std::string`` with ``to_string(out)``. + \endrst + */ +template <typename T, std::size_t SIZE = inline_buffer_size, + typename Allocator = std::allocator<T> > +class basic_memory_buffer: private Allocator, public internal::basic_buffer<T> { + private: + T store_[SIZE]; + + // Deallocate memory allocated by the buffer. + void deallocate() { + T* data = this->data(); + if (data != store_) Allocator::deallocate(data, this->capacity()); + } + + protected: + void grow(std::size_t size) FMT_OVERRIDE; + + public: + typedef T value_type; + typedef const T &const_reference; + + explicit basic_memory_buffer(const Allocator &alloc = Allocator()) + : Allocator(alloc) { + this->set(store_, SIZE); + } + ~basic_memory_buffer() { deallocate(); } + + private: + // Move data from other to this buffer. + void move(basic_memory_buffer &other) { + Allocator &this_alloc = *this, &other_alloc = other; + this_alloc = std::move(other_alloc); + T* data = other.data(); + std::size_t size = other.size(), capacity = other.capacity(); + if (data == other.store_) { + this->set(store_, capacity); + std::uninitialized_copy(other.store_, other.store_ + size, + internal::make_checked(store_, capacity)); + } else { + this->set(data, capacity); + // Set pointer to the inline array so that delete is not called + // when deallocating. + other.set(other.store_, 0); + } + this->resize(size); + } + + public: + /** + \rst + Constructs a :class:`fmt::basic_memory_buffer` object moving the content + of the other object to it. + \endrst + */ + basic_memory_buffer(basic_memory_buffer &&other) { + move(other); + } + + /** + \rst + Moves the content of the other ``basic_memory_buffer`` object to this one. + \endrst + */ + basic_memory_buffer &operator=(basic_memory_buffer &&other) { + assert(this != &other); + deallocate(); + move(other); + return *this; + } + + // Returns a copy of the allocator associated with this buffer. + Allocator get_allocator() const { return *this; } +}; + +template <typename T, std::size_t SIZE, typename Allocator> +void basic_memory_buffer<T, SIZE, Allocator>::grow(std::size_t size) { + std::size_t old_capacity = this->capacity(); + std::size_t new_capacity = old_capacity + old_capacity / 2; + if (size > new_capacity) + new_capacity = size; + T *old_data = this->data(); + T *new_data = internal::allocate<Allocator>(*this, new_capacity); + // The following code doesn't throw, so the raw pointer above doesn't leak. + std::uninitialized_copy(old_data, old_data + this->size(), + internal::make_checked(new_data, new_capacity)); + this->set(new_data, new_capacity); + // deallocate must not throw according to the standard, but even if it does, + // the buffer already uses the new storage and will deallocate it in + // destructor. + if (old_data != store_) + Allocator::deallocate(old_data, old_capacity); +} + +typedef basic_memory_buffer<char> memory_buffer; +typedef basic_memory_buffer<wchar_t> wmemory_buffer; + +namespace internal { + +template <typename Char> +struct char_traits; + +template <> +struct char_traits<char> { + // Formats a floating-point number. + template <typename T> + FMT_API static int format_float(char *buffer, std::size_t size, + const char *format, int precision, T value); +}; + +template <> +struct char_traits<wchar_t> { + template <typename T> + FMT_API static int format_float(wchar_t *buffer, std::size_t size, + const wchar_t *format, int precision, T value); +}; + +#if FMT_USE_EXTERN_TEMPLATES +extern template int char_traits<char>::format_float<double>( + char *buffer, std::size_t size, const char* format, int precision, + double value); +extern template int char_traits<char>::format_float<long double>( + char *buffer, std::size_t size, const char* format, int precision, + long double value); + +extern template int char_traits<wchar_t>::format_float<double>( + wchar_t *buffer, std::size_t size, const wchar_t* format, int precision, + double value); +extern template int char_traits<wchar_t>::format_float<long double>( + wchar_t *buffer, std::size_t size, const wchar_t* format, int precision, + long double value); +#endif + +template <typename Container> +inline typename std::enable_if< + is_contiguous<Container>::value, + typename checked<typename Container::value_type>::type>::type + reserve(std::back_insert_iterator<Container> &it, std::size_t n) { + Container &c = internal::get_container(it); + std::size_t size = c.size(); + c.resize(size + n); + return make_checked(&c[size], n); +} + +template <typename Iterator> +inline Iterator &reserve(Iterator &it, std::size_t) { return it; } + +template <typename Char> +class null_terminating_iterator; + +template <typename Char> +FMT_CONSTEXPR_DECL const Char *pointer_from(null_terminating_iterator<Char> it); + +// An output iterator that counts the number of objects written to it and +// discards them. +template <typename T> +class counting_iterator { + private: + std::size_t count_; + mutable T blackhole_; + + public: + typedef std::output_iterator_tag iterator_category; + typedef T value_type; + typedef std::ptrdiff_t difference_type; + typedef T* pointer; + typedef T& reference; + typedef counting_iterator _Unchecked_type; // Mark iterator as checked. + + counting_iterator(): count_(0) {} + + std::size_t count() const { return count_; } + + counting_iterator& operator++() { + ++count_; + return *this; + } + + counting_iterator operator++(int) { + auto it = *this; + ++*this; + return it; + } + + T &operator*() const { return blackhole_; } +}; + +template <typename OutputIt> +class truncating_iterator_base { + protected: + OutputIt out_; + std::size_t limit_; + std::size_t count_; + + truncating_iterator_base(OutputIt out, std::size_t limit) + : out_(out), limit_(limit), count_(0) {} + + public: + typedef std::output_iterator_tag iterator_category; + typedef void difference_type; + typedef void pointer; + typedef void reference; + typedef truncating_iterator_base _Unchecked_type; // Mark iterator as checked. + + OutputIt base() const { return out_; } + std::size_t count() const { return count_; } +}; + +// An output iterator that truncates the output and counts the number of objects +// written to it. +template <typename OutputIt, typename Enable = typename std::is_void< + typename std::iterator_traits<OutputIt>::value_type>::type> +class truncating_iterator; + +template <typename OutputIt> +class truncating_iterator<OutputIt, std::false_type>: + public truncating_iterator_base<OutputIt> { + typedef std::iterator_traits<OutputIt> traits; + + mutable typename traits::value_type blackhole_; + + public: + typedef typename traits::value_type value_type; + + truncating_iterator(OutputIt out, std::size_t limit) + : truncating_iterator_base<OutputIt>(out, limit) {} + + truncating_iterator& operator++() { + if (this->count_++ < this->limit_) + ++this->out_; + return *this; + } + + truncating_iterator operator++(int) { + auto it = *this; + ++*this; + return it; + } + + value_type& operator*() const { + return this->count_ < this->limit_ ? *this->out_ : blackhole_; + } +}; + +template <typename OutputIt> +class truncating_iterator<OutputIt, std::true_type>: + public truncating_iterator_base<OutputIt> { + public: + typedef typename OutputIt::container_type::value_type value_type; + + truncating_iterator(OutputIt out, std::size_t limit) + : truncating_iterator_base<OutputIt>(out, limit) {} + + truncating_iterator& operator=(value_type val) { + if (this->count_++ < this->limit_) + this->out_ = val; + return *this; + } + + truncating_iterator& operator++() { return *this; } + truncating_iterator& operator++(int) { return *this; } + truncating_iterator& operator*() { return *this; } +}; + +// Returns true if value is negative, false otherwise. +// Same as (value < 0) but doesn't produce warnings if T is an unsigned type. +template <typename T> +FMT_CONSTEXPR typename std::enable_if< + std::numeric_limits<T>::is_signed, bool>::type is_negative(T value) { + return value < 0; +} +template <typename T> +FMT_CONSTEXPR typename std::enable_if< + !std::numeric_limits<T>::is_signed, bool>::type is_negative(T) { + return false; +} + +template <typename T> +struct int_traits { + // Smallest of uint32_t and uint64_t that is large enough to represent + // all values of T. + typedef typename std::conditional< + std::numeric_limits<T>::digits <= 32, uint32_t, uint64_t>::type main_type; +}; + +// Static data is placed in this class template to allow header-only +// configuration. +template <typename T = void> +struct FMT_API basic_data { + static const uint32_t POWERS_OF_10_32[]; + static const uint32_t ZERO_OR_POWERS_OF_10_32[]; + static const uint64_t ZERO_OR_POWERS_OF_10_64[]; + static const uint64_t POW10_SIGNIFICANDS[]; + static const int16_t POW10_EXPONENTS[]; + static const char DIGITS[]; + static const char FOREGROUND_COLOR[]; + static const char BACKGROUND_COLOR[]; + static const char RESET_COLOR[]; + static const wchar_t WRESET_COLOR[]; +}; + +#if FMT_USE_EXTERN_TEMPLATES +extern template struct basic_data<void>; +#endif + +typedef basic_data<> data; + +#ifdef FMT_BUILTIN_CLZLL +// Returns the number of decimal digits in n. Leading zeros are not counted +// except for n == 0 in which case count_digits returns 1. +inline int count_digits(uint64_t n) { + // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 + // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits. + int t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12; + return t - (n < data::ZERO_OR_POWERS_OF_10_64[t]) + 1; +} +#else +// Fallback version of count_digits used when __builtin_clz is not available. +inline int count_digits(uint64_t n) { + int count = 1; + for (;;) { + // Integer division is slow so do it for a group of four digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + if (n < 10) return count; + if (n < 100) return count + 1; + if (n < 1000) return count + 2; + if (n < 10000) return count + 3; + n /= 10000u; + count += 4; + } +} +#endif + +template <typename Char> +inline size_t count_code_points(basic_string_view<Char> s) { return s.size(); } + +// Counts the number of code points in a UTF-8 string. +FMT_API size_t count_code_points(basic_string_view<char8_t> s); + +inline char8_t to_char8_t(char c) { return static_cast<char8_t>(c); } + +template <typename InputIt, typename OutChar> +struct needs_conversion: std::integral_constant<bool, + std::is_same< + typename std::iterator_traits<InputIt>::value_type, char>::value && + std::is_same<OutChar, char8_t>::value> {}; + +template <typename OutChar, typename InputIt, typename OutputIt> +typename std::enable_if< + !needs_conversion<InputIt, OutChar>::value, OutputIt>::type + copy_str(InputIt begin, InputIt end, OutputIt it) { + return std::copy(begin, end, it); +} + +template <typename OutChar, typename InputIt, typename OutputIt> +typename std::enable_if< + needs_conversion<InputIt, OutChar>::value, OutputIt>::type + copy_str(InputIt begin, InputIt end, OutputIt it) { + return std::transform(begin, end, it, to_char8_t); +} + +#if FMT_HAS_CPP_ATTRIBUTE(always_inline) +# define FMT_ALWAYS_INLINE __attribute__((always_inline)) +#else +# define FMT_ALWAYS_INLINE +#endif + +template <typename Handler> +inline char *lg(uint32_t n, Handler h) FMT_ALWAYS_INLINE; + +// Computes g = floor(log10(n)) and calls h.on<g>(n); +template <typename Handler> +inline char *lg(uint32_t n, Handler h) { + return n < 100 ? n < 10 ? h.template on<0>(n) : h.template on<1>(n) + : n < 1000000 + ? n < 10000 ? n < 1000 ? h.template on<2>(n) + : h.template on<3>(n) + : n < 100000 ? h.template on<4>(n) + : h.template on<5>(n) + : n < 100000000 ? n < 10000000 ? h.template on<6>(n) + : h.template on<7>(n) + : n < 1000000000 ? h.template on<8>(n) + : h.template on<9>(n); +} + +// An lg handler that formats a decimal number. +// Usage: lg(n, decimal_formatter(buffer)); +class decimal_formatter { + private: + char *buffer_; + + void write_pair(unsigned N, uint32_t index) { + std::memcpy(buffer_ + N, data::DIGITS + index * 2, 2); + } + + public: + explicit decimal_formatter(char *buf) : buffer_(buf) {} + + template <unsigned N> char *on(uint32_t u) { + if (N == 0) { + *buffer_ = static_cast<char>(u) + '0'; + } else if (N == 1) { + write_pair(0, u); + } else { + // The idea of using 4.32 fixed-point numbers is based on + // https://github.com/jeaiii/itoa + unsigned n = N - 1; + unsigned a = n / 5 * n * 53 / 16; + uint64_t t = ((1ULL << (32 + a)) / + data::ZERO_OR_POWERS_OF_10_32[n] + 1 - n / 9); + t = ((t * u) >> a) + n / 5 * 4; + write_pair(0, t >> 32); + for (unsigned i = 2; i < N; i += 2) { + t = 100ULL * static_cast<uint32_t>(t); + write_pair(i, t >> 32); + } + if (N % 2 == 0) { + buffer_[N] = static_cast<char>( + (10ULL * static_cast<uint32_t>(t)) >> 32) + '0'; + } + } + return buffer_ += N + 1; + } +}; + +// An lg handler that formats a decimal number with a terminating null. +class decimal_formatter_null : public decimal_formatter { + public: + explicit decimal_formatter_null(char *buf) : decimal_formatter(buf) {} + + template <unsigned N> char *on(uint32_t u) { + char *buf = decimal_formatter::on<N>(u); + *buf = '\0'; + return buf; + } +}; + +#ifdef FMT_BUILTIN_CLZ +// Optional version of count_digits for better performance on 32-bit platforms. +inline int count_digits(uint32_t n) { + int t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12; + return t - (n < data::ZERO_OR_POWERS_OF_10_32[t]) + 1; +} +#endif + +// A functor that doesn't add a thousands separator. +struct no_thousands_sep { + typedef char char_type; + + template <typename Char> + void operator()(Char *) {} + + enum { size = 0 }; +}; + +// A functor that adds a thousands separator. +template <typename Char> +class add_thousands_sep { + private: + basic_string_view<Char> sep_; + + // Index of a decimal digit with the least significant digit having index 0. + unsigned digit_index_; + + public: + typedef Char char_type; + + explicit add_thousands_sep(basic_string_view<Char> sep) + : sep_(sep), digit_index_(0) {} + + void operator()(Char *&buffer) { + if (++digit_index_ % 3 != 0) + return; + buffer -= sep_.size(); + std::uninitialized_copy(sep_.data(), sep_.data() + sep_.size(), + internal::make_checked(buffer, sep_.size())); + } + + enum { size = 1 }; +}; + +template <typename Char> +FMT_API Char thousands_sep_impl(locale_ref loc); + +template <typename Char> +inline Char thousands_sep(locale_ref loc) { + return Char(thousands_sep_impl<char>(loc)); +} + +template <> +inline wchar_t thousands_sep(locale_ref loc) { + return thousands_sep_impl<wchar_t>(loc); +} + +// Formats a decimal unsigned integer value writing into buffer. +// thousands_sep is a functor that is called after writing each char to +// add a thousands separator if necessary. +template <typename UInt, typename Char, typename ThousandsSep> +inline Char *format_decimal(Char *buffer, UInt value, int num_digits, + ThousandsSep thousands_sep) { + FMT_ASSERT(num_digits >= 0, "invalid digit count"); + buffer += num_digits; + Char *end = buffer; + while (value >= 100) { + // Integer division is slow so do it for a group of two digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + unsigned index = static_cast<unsigned>((value % 100) * 2); + value /= 100; + *--buffer = static_cast<Char>(data::DIGITS[index + 1]); + thousands_sep(buffer); + *--buffer = static_cast<Char>(data::DIGITS[index]); + thousands_sep(buffer); + } + if (value < 10) { + *--buffer = static_cast<Char>('0' + value); + return end; + } + unsigned index = static_cast<unsigned>(value * 2); + *--buffer = static_cast<Char>(data::DIGITS[index + 1]); + thousands_sep(buffer); + *--buffer = static_cast<Char>(data::DIGITS[index]); + return end; +} + +template <typename OutChar, typename UInt, typename Iterator, + typename ThousandsSep> +inline Iterator format_decimal( + Iterator out, UInt value, int num_digits, ThousandsSep sep) { + FMT_ASSERT(num_digits >= 0, "invalid digit count"); + typedef typename ThousandsSep::char_type char_type; + // Buffer should be large enough to hold all digits (<= digits10 + 1). + enum { max_size = std::numeric_limits<UInt>::digits10 + 1 }; + FMT_ASSERT(ThousandsSep::size <= 1, "invalid separator"); + char_type buffer[max_size + max_size / 3]; + auto end = format_decimal(buffer, value, num_digits, sep); + return internal::copy_str<OutChar>(buffer, end, out); +} + +template <typename OutChar, typename It, typename UInt> +inline It format_decimal(It out, UInt value, int num_digits) { + return format_decimal<OutChar>(out, value, num_digits, no_thousands_sep()); +} + +template <unsigned BASE_BITS, typename Char, typename UInt> +inline Char *format_uint(Char *buffer, UInt value, int num_digits, + bool upper = false) { + buffer += num_digits; + Char *end = buffer; + do { + const char *digits = upper ? "0123456789ABCDEF" : "0123456789abcdef"; + unsigned digit = (value & ((1 << BASE_BITS) - 1)); + *--buffer = static_cast<Char>(BASE_BITS < 4 ? static_cast<char>('0' + digit) + : digits[digit]); + } while ((value >>= BASE_BITS) != 0); + return end; +} + +template <unsigned BASE_BITS, typename Char, typename It, typename UInt> +inline It format_uint(It out, UInt value, int num_digits, + bool upper = false) { + // Buffer should be large enough to hold all digits (digits / BASE_BITS + 1) + // and null. + char buffer[std::numeric_limits<UInt>::digits / BASE_BITS + 2]; + format_uint<BASE_BITS>(buffer, value, num_digits, upper); + return internal::copy_str<Char>(buffer, buffer + num_digits, out); +} + +#ifndef _WIN32 +# define FMT_USE_WINDOWS_H 0 +#elif !defined(FMT_USE_WINDOWS_H) +# define FMT_USE_WINDOWS_H 1 +#endif + +// Define FMT_USE_WINDOWS_H to 0 to disable use of windows.h. +// All the functionality that relies on it will be disabled too. +#if FMT_USE_WINDOWS_H +// A converter from UTF-8 to UTF-16. +// It is only provided for Windows since other systems support UTF-8 natively. +class utf8_to_utf16 { + private: + wmemory_buffer buffer_; + + public: + FMT_API explicit utf8_to_utf16(string_view s); + operator wstring_view() const { return wstring_view(&buffer_[0], size()); } + size_t size() const { return buffer_.size() - 1; } + const wchar_t *c_str() const { return &buffer_[0]; } + std::wstring str() const { return std::wstring(&buffer_[0], size()); } +}; + +// A converter from UTF-16 to UTF-8. +// It is only provided for Windows since other systems support UTF-8 natively. +class utf16_to_utf8 { + private: + memory_buffer buffer_; + + public: + utf16_to_utf8() {} + FMT_API explicit utf16_to_utf8(wstring_view s); + operator string_view() const { return string_view(&buffer_[0], size()); } + size_t size() const { return buffer_.size() - 1; } + const char *c_str() const { return &buffer_[0]; } + std::string str() const { return std::string(&buffer_[0], size()); } + + // Performs conversion returning a system error code instead of + // throwing exception on conversion error. This method may still throw + // in case of memory allocation error. + FMT_API int convert(wstring_view s); +}; + +FMT_API void format_windows_error(fmt::internal::buffer &out, int error_code, + fmt::string_view message) FMT_NOEXCEPT; +#endif + +template <typename T = void> +struct null {}; +} // namespace internal + +enum alignment { + ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC +}; + +// Flags. +enum { SIGN_FLAG = 1, PLUS_FLAG = 2, MINUS_FLAG = 4, HASH_FLAG = 8 }; + +// An alignment specifier. +struct align_spec { + unsigned width_; + // Fill is always wchar_t and cast to char if necessary to avoid having + // two specialization of AlignSpec and its subclasses. + wchar_t fill_; + alignment align_; + + FMT_CONSTEXPR align_spec() : width_(0), fill_(' '), align_(ALIGN_DEFAULT) {} + FMT_CONSTEXPR unsigned width() const { return width_; } + FMT_CONSTEXPR wchar_t fill() const { return fill_; } + FMT_CONSTEXPR alignment align() const { return align_; } +}; + +struct core_format_specs { + int precision; + uint_least8_t flags; + char type; + + FMT_CONSTEXPR core_format_specs() : precision(-1), flags(0), type(0) {} + FMT_CONSTEXPR bool has(unsigned f) const { return (flags & f) != 0; } +}; + +// Format specifiers. +template <typename Char> +struct basic_format_specs : align_spec, core_format_specs { + FMT_CONSTEXPR basic_format_specs() {} +}; + +typedef basic_format_specs<char> format_specs; + +template <typename Char, typename ErrorHandler> +FMT_CONSTEXPR unsigned basic_parse_context<Char, ErrorHandler>::next_arg_id() { + if (next_arg_id_ >= 0) + return internal::to_unsigned(next_arg_id_++); + on_error("cannot switch from manual to automatic argument indexing"); + return 0; +} + +namespace internal { + +// Formats value using Grisu2 algorithm: +// https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf +template <typename Double> +FMT_API typename std::enable_if<sizeof(Double) == sizeof(uint64_t), bool>::type + grisu2_format(Double value, buffer &buf, core_format_specs); +template <typename Double> +inline typename std::enable_if<sizeof(Double) != sizeof(uint64_t), bool>::type + grisu2_format(Double, buffer &, core_format_specs) { return false; } + +template <typename Double> +void sprintf_format(Double, internal::buffer &, core_format_specs); + +template <typename Handler> +FMT_CONSTEXPR void handle_int_type_spec(char spec, Handler &&handler) { + switch (spec) { + case 0: case 'd': + handler.on_dec(); + break; + case 'x': case 'X': + handler.on_hex(); + break; + case 'b': case 'B': + handler.on_bin(); + break; + case 'o': + handler.on_oct(); + break; + case 'n': + handler.on_num(); + break; + default: + handler.on_error(); + } +} + +template <typename Handler> +FMT_CONSTEXPR void handle_float_type_spec(char spec, Handler &&handler) { + switch (spec) { + case 0: case 'g': case 'G': + handler.on_general(); + break; + case 'e': case 'E': + handler.on_exp(); + break; + case 'f': case 'F': + handler.on_fixed(); + break; + case 'a': case 'A': + handler.on_hex(); + break; + default: + handler.on_error(); + break; + } +} + +template <typename Char, typename Handler> +FMT_CONSTEXPR void handle_char_specs( + const basic_format_specs<Char> *specs, Handler &&handler) { + if (!specs) return handler.on_char(); + if (specs->type && specs->type != 'c') return handler.on_int(); + if (specs->align() == ALIGN_NUMERIC || specs->flags != 0) + handler.on_error("invalid format specifier for char"); + handler.on_char(); +} + +template <typename Char, typename Handler> +FMT_CONSTEXPR void handle_cstring_type_spec(Char spec, Handler &&handler) { + if (spec == 0 || spec == 's') + handler.on_string(); + else if (spec == 'p') + handler.on_pointer(); + else + handler.on_error("invalid type specifier"); +} + +template <typename Char, typename ErrorHandler> +FMT_CONSTEXPR void check_string_type_spec(Char spec, ErrorHandler &&eh) { + if (spec != 0 && spec != 's') + eh.on_error("invalid type specifier"); +} + +template <typename Char, typename ErrorHandler> +FMT_CONSTEXPR void check_pointer_type_spec(Char spec, ErrorHandler &&eh) { + if (spec != 0 && spec != 'p') + eh.on_error("invalid type specifier"); +} + +template <typename ErrorHandler> +class int_type_checker : private ErrorHandler { + public: + FMT_CONSTEXPR explicit int_type_checker(ErrorHandler eh) : ErrorHandler(eh) {} + + FMT_CONSTEXPR void on_dec() {} + FMT_CONSTEXPR void on_hex() {} + FMT_CONSTEXPR void on_bin() {} + FMT_CONSTEXPR void on_oct() {} + FMT_CONSTEXPR void on_num() {} + + FMT_CONSTEXPR void on_error() { + ErrorHandler::on_error("invalid type specifier"); + } +}; + +template <typename ErrorHandler> +class float_type_checker : private ErrorHandler { + public: + FMT_CONSTEXPR explicit float_type_checker(ErrorHandler eh) + : ErrorHandler(eh) {} + + FMT_CONSTEXPR void on_general() {} + FMT_CONSTEXPR void on_exp() {} + FMT_CONSTEXPR void on_fixed() {} + FMT_CONSTEXPR void on_hex() {} + + FMT_CONSTEXPR void on_error() { + ErrorHandler::on_error("invalid type specifier"); + } +}; + +template <typename ErrorHandler> +class char_specs_checker : public ErrorHandler { + private: + char type_; + + public: + FMT_CONSTEXPR char_specs_checker(char type, ErrorHandler eh) + : ErrorHandler(eh), type_(type) {} + + FMT_CONSTEXPR void on_int() { + handle_int_type_spec(type_, int_type_checker<ErrorHandler>(*this)); + } + FMT_CONSTEXPR void on_char() {} +}; + +template <typename ErrorHandler> +class cstring_type_checker : public ErrorHandler { + public: + FMT_CONSTEXPR explicit cstring_type_checker(ErrorHandler eh) + : ErrorHandler(eh) {} + + FMT_CONSTEXPR void on_string() {} + FMT_CONSTEXPR void on_pointer() {} +}; + +template <typename Context> +void arg_map<Context>::init(const basic_format_args<Context> &args) { + if (map_) + return; + map_ = new entry[args.max_size()]; + if (args.is_packed()) { + for (unsigned i = 0;/*nothing*/; ++i) { + internal::type arg_type = args.type(i); + switch (arg_type) { + case internal::none_type: + return; + case internal::named_arg_type: + push_back(args.values_[i]); + break; + default: + break; // Do nothing. + } + } + } + for (unsigned i = 0; ; ++i) { + switch (args.args_[i].type_) { + case internal::none_type: + return; + case internal::named_arg_type: + push_back(args.args_[i].value_); + break; + default: + break; // Do nothing. + } + } +} + +template <typename Range> +class arg_formatter_base { + public: + typedef typename Range::value_type char_type; + typedef decltype(internal::declval<Range>().begin()) iterator; + typedef basic_format_specs<char_type> format_specs; + + private: + typedef basic_writer<Range> writer_type; + writer_type writer_; + format_specs *specs_; + + struct char_writer { + char_type value; + + size_t size() const { return 1; } + size_t width() const { return 1; } + + template <typename It> + void operator()(It &&it) const { *it++ = value; } + }; + + void write_char(char_type value) { + if (specs_) + writer_.write_padded(*specs_, char_writer{value}); + else + writer_.write(value); + } + + void write_pointer(const void *p) { + format_specs specs = specs_ ? *specs_ : format_specs(); + specs.flags = HASH_FLAG; + specs.type = 'x'; + writer_.write_int(reinterpret_cast<uintptr_t>(p), specs); + } + + protected: + writer_type &writer() { return writer_; } + format_specs *spec() { return specs_; } + iterator out() { return writer_.out(); } + + void write(bool value) { + string_view sv(value ? "true" : "false"); + specs_ ? writer_.write(sv, *specs_) : writer_.write(sv); + } + + void write(const char_type *value) { + if (!value) + FMT_THROW(format_error("string pointer is null")); + auto length = std::char_traits<char_type>::length(value); + basic_string_view<char_type> sv(value, length); + specs_ ? writer_.write(sv, *specs_) : writer_.write(sv); + } + + public: + arg_formatter_base(Range r, format_specs *s, locale_ref loc) + : writer_(r, loc), specs_(s) {} + + iterator operator()(monostate) { + FMT_ASSERT(false, "invalid argument type"); + return out(); + } + + template <typename T> + typename std::enable_if< + std::is_integral<T>::value || std::is_same<T, char_type>::value, + iterator>::type operator()(T value) { + // MSVC2013 fails to compile separate overloads for bool and char_type so + // use std::is_same instead. + if (std::is_same<T, bool>::value) { + if (specs_ && specs_->type) + return (*this)(value ? 1 : 0); + write(value != 0); + } else if (std::is_same<T, char_type>::value) { + internal::handle_char_specs( + specs_, char_spec_handler(*this, static_cast<char_type>(value))); + } else { + specs_ ? writer_.write_int(value, *specs_) : writer_.write(value); + } + return out(); + } + + template <typename T> + typename std::enable_if<std::is_floating_point<T>::value, iterator>::type + operator()(T value) { + writer_.write_double(value, specs_ ? *specs_ : format_specs()); + return out(); + } + + struct char_spec_handler : internal::error_handler { + arg_formatter_base &formatter; + char_type value; + + char_spec_handler(arg_formatter_base& f, char_type val) + : formatter(f), value(val) {} + + void on_int() { + if (formatter.specs_) + formatter.writer_.write_int(value, *formatter.specs_); + else + formatter.writer_.write(value); + } + void on_char() { formatter.write_char(value); } + }; + + struct cstring_spec_handler : internal::error_handler { + arg_formatter_base &formatter; + const char_type *value; + + cstring_spec_handler(arg_formatter_base &f, const char_type *val) + : formatter(f), value(val) {} + + void on_string() { formatter.write(value); } + void on_pointer() { formatter.write_pointer(value); } + }; + + iterator operator()(const char_type *value) { + if (!specs_) return write(value), out(); + internal::handle_cstring_type_spec( + specs_->type, cstring_spec_handler(*this, value)); + return out(); + } + + iterator operator()(basic_string_view<char_type> value) { + if (specs_) { + internal::check_string_type_spec( + specs_->type, internal::error_handler()); + writer_.write(value, *specs_); + } else { + writer_.write(value); + } + return out(); + } + + iterator operator()(const void *value) { + if (specs_) + check_pointer_type_spec(specs_->type, internal::error_handler()); + write_pointer(value); + return out(); + } +}; + +template <typename Char> +FMT_CONSTEXPR bool is_name_start(Char c) { + return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; +} + +// Parses the range [begin, end) as an unsigned integer. This function assumes +// that the range is non-empty and the first character is a digit. +template <typename Char, typename ErrorHandler> +FMT_CONSTEXPR unsigned parse_nonnegative_int( + const Char *&begin, const Char *end, ErrorHandler &&eh) { + assert(begin != end && '0' <= *begin && *begin <= '9'); + if (*begin == '0') { + ++begin; + return 0; + } + unsigned value = 0; + // Convert to unsigned to prevent a warning. + unsigned max_int = (std::numeric_limits<int>::max)(); + unsigned big = max_int / 10; + do { + // Check for overflow. + if (value > big) { + value = max_int + 1; + break; + } + value = value * 10 + unsigned(*begin - '0'); + ++begin; + } while (begin != end && '0' <= *begin && *begin <= '9'); + if (value > max_int) + eh.on_error("number is too big"); + return value; +} + +template <typename Char, typename Context> +class custom_formatter: public function<bool> { + private: + Context &ctx_; + + public: + explicit custom_formatter(Context &ctx): ctx_(ctx) {} + + bool operator()(typename basic_format_arg<Context>::handle h) const { + h.format(ctx_); + return true; + } + + template <typename T> + bool operator()(T) const { return false; } +}; + +template <typename T> +struct is_integer { + enum { + value = std::is_integral<T>::value && !std::is_same<T, bool>::value && + !std::is_same<T, char>::value && !std::is_same<T, wchar_t>::value + }; +}; + +template <typename ErrorHandler> +class width_checker: public function<unsigned long long> { + public: + explicit FMT_CONSTEXPR width_checker(ErrorHandler &eh) : handler_(eh) {} + + template <typename T> + FMT_CONSTEXPR + typename std::enable_if< + is_integer<T>::value, unsigned long long>::type operator()(T value) { + if (is_negative(value)) + handler_.on_error("negative width"); + return static_cast<unsigned long long>(value); + } + + template <typename T> + FMT_CONSTEXPR typename std::enable_if< + !is_integer<T>::value, unsigned long long>::type operator()(T) { + handler_.on_error("width is not integer"); + return 0; + } + + private: + ErrorHandler &handler_; +}; + +template <typename ErrorHandler> +class precision_checker: public function<unsigned long long> { + public: + explicit FMT_CONSTEXPR precision_checker(ErrorHandler &eh) : handler_(eh) {} + + template <typename T> + FMT_CONSTEXPR typename std::enable_if< + is_integer<T>::value, unsigned long long>::type operator()(T value) { + if (is_negative(value)) + handler_.on_error("negative precision"); + return static_cast<unsigned long long>(value); + } + + template <typename T> + FMT_CONSTEXPR typename std::enable_if< + !is_integer<T>::value, unsigned long long>::type operator()(T) { + handler_.on_error("precision is not integer"); + return 0; + } + + private: + ErrorHandler &handler_; +}; + +// A format specifier handler that sets fields in basic_format_specs. +template <typename Char> +class specs_setter { + public: + explicit FMT_CONSTEXPR specs_setter(basic_format_specs<Char> &specs): + specs_(specs) {} + + FMT_CONSTEXPR specs_setter(const specs_setter &other): specs_(other.specs_) {} + + FMT_CONSTEXPR void on_align(alignment align) { specs_.align_ = align; } + FMT_CONSTEXPR void on_fill(Char fill) { specs_.fill_ = fill; } + FMT_CONSTEXPR void on_plus() { specs_.flags |= SIGN_FLAG | PLUS_FLAG; } + FMT_CONSTEXPR void on_minus() { specs_.flags |= MINUS_FLAG; } + FMT_CONSTEXPR void on_space() { specs_.flags |= SIGN_FLAG; } + FMT_CONSTEXPR void on_hash() { specs_.flags |= HASH_FLAG; } + + FMT_CONSTEXPR void on_zero() { + specs_.align_ = ALIGN_NUMERIC; + specs_.fill_ = '0'; + } + + FMT_CONSTEXPR void on_width(unsigned width) { specs_.width_ = width; } + FMT_CONSTEXPR void on_precision(unsigned precision) { + specs_.precision = static_cast<int>(precision); + } + FMT_CONSTEXPR void end_precision() {} + + FMT_CONSTEXPR void on_type(Char type) { + specs_.type = static_cast<char>(type); + } + + protected: + basic_format_specs<Char> &specs_; +}; + +// A format specifier handler that checks if specifiers are consistent with the +// argument type. +template <typename Handler> +class specs_checker : public Handler { + public: + FMT_CONSTEXPR specs_checker(const Handler& handler, internal::type arg_type) + : Handler(handler), arg_type_(arg_type) {} + + FMT_CONSTEXPR specs_checker(const specs_checker &other) + : Handler(other), arg_type_(other.arg_type_) {} + + FMT_CONSTEXPR void on_align(alignment align) { + if (align == ALIGN_NUMERIC) + require_numeric_argument(); + Handler::on_align(align); + } + + FMT_CONSTEXPR void on_plus() { + check_sign(); + Handler::on_plus(); + } + + FMT_CONSTEXPR void on_minus() { + check_sign(); + Handler::on_minus(); + } + + FMT_CONSTEXPR void on_space() { + check_sign(); + Handler::on_space(); + } + + FMT_CONSTEXPR void on_hash() { + require_numeric_argument(); + Handler::on_hash(); + } + + FMT_CONSTEXPR void on_zero() { + require_numeric_argument(); + Handler::on_zero(); + } + + FMT_CONSTEXPR void end_precision() { + if (is_integral(arg_type_) || arg_type_ == pointer_type) + this->on_error("precision not allowed for this argument type"); + } + + private: + FMT_CONSTEXPR void require_numeric_argument() { + if (!is_arithmetic(arg_type_)) + this->on_error("format specifier requires numeric argument"); + } + + FMT_CONSTEXPR void check_sign() { + require_numeric_argument(); + if (is_integral(arg_type_) && arg_type_ != int_type && + arg_type_ != long_long_type && arg_type_ != internal::char_type) { + this->on_error("format specifier requires signed argument"); + } + } + + internal::type arg_type_; +}; + +template <template <typename> class Handler, typename T, + typename Context, typename ErrorHandler> +FMT_CONSTEXPR void set_dynamic_spec( + T &value, basic_format_arg<Context> arg, ErrorHandler eh) { + unsigned long long big_value = + visit_format_arg(Handler<ErrorHandler>(eh), arg); + if (big_value > to_unsigned((std::numeric_limits<int>::max)())) + eh.on_error("number is too big"); + value = static_cast<T>(big_value); +} + +struct auto_id {}; + +// The standard format specifier handler with checking. +template <typename Context> +class specs_handler: public specs_setter<typename Context::char_type> { + public: + typedef typename Context::char_type char_type; + + FMT_CONSTEXPR specs_handler( + basic_format_specs<char_type> &specs, Context &ctx) + : specs_setter<char_type>(specs), context_(ctx) {} + + template <typename Id> + FMT_CONSTEXPR void on_dynamic_width(Id arg_id) { + set_dynamic_spec<width_checker>( + this->specs_.width_, get_arg(arg_id), context_.error_handler()); + } + + template <typename Id> + FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) { + set_dynamic_spec<precision_checker>( + this->specs_.precision, get_arg(arg_id), context_.error_handler()); + } + + void on_error(const char *message) { + context_.on_error(message); + } + + private: + FMT_CONSTEXPR basic_format_arg<Context> get_arg(auto_id) { + return context_.next_arg(); + } + + template <typename Id> + FMT_CONSTEXPR basic_format_arg<Context> get_arg(Id arg_id) { + context_.parse_context().check_arg_id(arg_id); + return context_.get_arg(arg_id); + } + + Context &context_; +}; + +// An argument reference. +template <typename Char> +struct arg_ref { + enum Kind { NONE, INDEX, NAME }; + + FMT_CONSTEXPR arg_ref() : kind(NONE), index(0) {} + FMT_CONSTEXPR explicit arg_ref(unsigned index) : kind(INDEX), index(index) {} + explicit arg_ref(basic_string_view<Char> nm) : kind(NAME) { + name = {nm.data(), nm.size()}; + } + + FMT_CONSTEXPR arg_ref &operator=(unsigned idx) { + kind = INDEX; + index = idx; + return *this; + } + + Kind kind; + union { + unsigned index; + string_value<Char> name; // This is not string_view because of gcc 4.4. + }; +}; + +// Format specifiers with width and precision resolved at formatting rather +// than parsing time to allow re-using the same parsed specifiers with +// differents sets of arguments (precompilation of format strings). +template <typename Char> +struct dynamic_format_specs : basic_format_specs<Char> { + arg_ref<Char> width_ref; + arg_ref<Char> precision_ref; +}; + +// Format spec handler that saves references to arguments representing dynamic +// width and precision to be resolved at formatting time. +template <typename ParseContext> +class dynamic_specs_handler : + public specs_setter<typename ParseContext::char_type> { + public: + typedef typename ParseContext::char_type char_type; + + FMT_CONSTEXPR dynamic_specs_handler( + dynamic_format_specs<char_type> &specs, ParseContext &ctx) + : specs_setter<char_type>(specs), specs_(specs), context_(ctx) {} + + FMT_CONSTEXPR dynamic_specs_handler(const dynamic_specs_handler &other) + : specs_setter<char_type>(other), + specs_(other.specs_), context_(other.context_) {} + + template <typename Id> + FMT_CONSTEXPR void on_dynamic_width(Id arg_id) { + specs_.width_ref = make_arg_ref(arg_id); + } + + template <typename Id> + FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) { + specs_.precision_ref = make_arg_ref(arg_id); + } + + FMT_CONSTEXPR void on_error(const char *message) { + context_.on_error(message); + } + + private: + typedef arg_ref<char_type> arg_ref_type; + + template <typename Id> + FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) { + context_.check_arg_id(arg_id); + return arg_ref_type(arg_id); + } + + FMT_CONSTEXPR arg_ref_type make_arg_ref(auto_id) { + return arg_ref_type(context_.next_arg_id()); + } + + dynamic_format_specs<char_type> &specs_; + ParseContext &context_; +}; + +template <typename Char, typename IDHandler> +FMT_CONSTEXPR const Char *parse_arg_id( + const Char *begin, const Char *end, IDHandler &&handler) { + assert(begin != end); + Char c = *begin; + if (c == '}' || c == ':') + return handler(), begin; + if (c >= '0' && c <= '9') { + unsigned index = parse_nonnegative_int(begin, end, handler); + if (begin == end || (*begin != '}' && *begin != ':')) + return handler.on_error("invalid format string"), begin; + handler(index); + return begin; + } + if (!is_name_start(c)) + return handler.on_error("invalid format string"), begin; + auto it = begin; + do { + ++it; + } while (it != end && (is_name_start(c = *it) || ('0' <= c && c <= '9'))); + handler(basic_string_view<Char>(begin, to_unsigned(it - begin))); + return it; +} + +// Adapts SpecHandler to IDHandler API for dynamic width. +template <typename SpecHandler, typename Char> +struct width_adapter { + explicit FMT_CONSTEXPR width_adapter(SpecHandler &h) : handler(h) {} + + FMT_CONSTEXPR void operator()() { handler.on_dynamic_width(auto_id()); } + FMT_CONSTEXPR void operator()(unsigned id) { handler.on_dynamic_width(id); } + FMT_CONSTEXPR void operator()(basic_string_view<Char> id) { + handler.on_dynamic_width(id); + } + + FMT_CONSTEXPR void on_error(const char *message) { + handler.on_error(message); + } + + SpecHandler &handler; +}; + +// Adapts SpecHandler to IDHandler API for dynamic precision. +template <typename SpecHandler, typename Char> +struct precision_adapter { + explicit FMT_CONSTEXPR precision_adapter(SpecHandler &h) : handler(h) {} + + FMT_CONSTEXPR void operator()() { handler.on_dynamic_precision(auto_id()); } + FMT_CONSTEXPR void operator()(unsigned id) { + handler.on_dynamic_precision(id); + } + FMT_CONSTEXPR void operator()(basic_string_view<Char> id) { + handler.on_dynamic_precision(id); + } + + FMT_CONSTEXPR void on_error(const char *message) { handler.on_error(message); } + + SpecHandler &handler; +}; + +// Parses fill and alignment. +template <typename Char, typename Handler> +FMT_CONSTEXPR const Char *parse_align( + const Char *begin, const Char *end, Handler &&handler) { + FMT_ASSERT(begin != end, ""); + alignment align = ALIGN_DEFAULT; + int i = 0; + if (begin + 1 != end) ++i; + do { + switch (static_cast<char>(begin[i])) { + case '<': + align = ALIGN_LEFT; + break; + case '>': + align = ALIGN_RIGHT; + break; + case '=': + align = ALIGN_NUMERIC; + break; + case '^': + align = ALIGN_CENTER; + break; + } + if (align != ALIGN_DEFAULT) { + if (i > 0) { + auto c = *begin; + if (c == '{') + return handler.on_error("invalid fill character '{'"), begin; + begin += 2; + handler.on_fill(c); + } else ++begin; + handler.on_align(align); + break; + } + } while (i-- > 0); + return begin; +} + +template <typename Char, typename Handler> +FMT_CONSTEXPR const Char *parse_width( + const Char *begin, const Char *end, Handler &&handler) { + FMT_ASSERT(begin != end, ""); + if ('0' <= *begin && *begin <= '9') { + handler.on_width(parse_nonnegative_int(begin, end, handler)); + } else if (*begin == '{') { + ++begin; + if (begin != end) + begin = parse_arg_id(begin, end, width_adapter<Handler, Char>(handler)); + if (begin == end || *begin != '}') + return handler.on_error("invalid format string"), begin; + ++begin; + } + return begin; +} + +// Parses standard format specifiers and sends notifications about parsed +// components to handler. +template <typename Char, typename SpecHandler> +FMT_CONSTEXPR const Char *parse_format_specs( + const Char *begin, const Char *end, SpecHandler &&handler) { + if (begin == end || *begin == '}') + return begin; + + begin = parse_align(begin, end, handler); + if (begin == end) return begin; + + // Parse sign. + switch (static_cast<char>(*begin)) { + case '+': + handler.on_plus(); + ++begin; + break; + case '-': + handler.on_minus(); + ++begin; + break; + case ' ': + handler.on_space(); + ++begin; + break; + } + if (begin == end) return begin; + + if (*begin == '#') { + handler.on_hash(); + if (++begin == end) return begin; + } + + // Parse zero flag. + if (*begin == '0') { + handler.on_zero(); + if (++begin == end) return begin; + } + + begin = parse_width(begin, end, handler); + if (begin == end) return begin; + + // Parse precision. + if (*begin == '.') { + ++begin; + auto c = begin != end ? *begin : 0; + if ('0' <= c && c <= '9') { + handler.on_precision(parse_nonnegative_int(begin, end, handler)); + } else if (c == '{') { + ++begin; + if (begin != end) { + begin = parse_arg_id( + begin, end, precision_adapter<SpecHandler, Char>(handler)); + } + if (begin == end || *begin++ != '}') + return handler.on_error("invalid format string"), begin; + } else { + return handler.on_error("missing precision specifier"), begin; + } + handler.end_precision(); + } + + // Parse type. + if (begin != end && *begin != '}') + handler.on_type(*begin++); + return begin; +} + +// Return the result via the out param to workaround gcc bug 77539. +template <bool IS_CONSTEXPR, typename T, typename Ptr = const T*> +FMT_CONSTEXPR bool find(Ptr first, Ptr last, T value, Ptr &out) { + for (out = first; out != last; ++out) { + if (*out == value) + return true; + } + return false; +} + +template <> +inline bool find<false, char>( + const char *first, const char *last, char value, const char *&out) { + out = static_cast<const char*>(std::memchr(first, value, internal::to_unsigned(last - first))); + return out != FMT_NULL; +} + +template <typename Handler, typename Char> +struct id_adapter { + FMT_CONSTEXPR void operator()() { handler.on_arg_id(); } + FMT_CONSTEXPR void operator()(unsigned id) { handler.on_arg_id(id); } + FMT_CONSTEXPR void operator()(basic_string_view<Char> id) { + handler.on_arg_id(id); + } + FMT_CONSTEXPR void on_error(const char *message) { + handler.on_error(message); + } + Handler &handler; +}; + +template <bool IS_CONSTEXPR, typename Char, typename Handler> +FMT_CONSTEXPR void parse_format_string( + basic_string_view<Char> format_str, Handler &&handler) { + struct writer { + FMT_CONSTEXPR void operator()(const Char *begin, const Char *end) { + if (begin == end) return; + for (;;) { + const Char *p = FMT_NULL; + if (!find<IS_CONSTEXPR>(begin, end, '}', p)) + return handler_.on_text(begin, end); + ++p; + if (p == end || *p != '}') + return handler_.on_error("unmatched '}' in format string"); + handler_.on_text(begin, p); + begin = p + 1; + } + } + Handler &handler_; + } write{handler}; + auto begin = format_str.data(); + auto end = begin + format_str.size(); + while (begin != end) { + // Doing two passes with memchr (one for '{' and another for '}') is up to + // 2.5x faster than the naive one-pass implementation on big format strings. + const Char *p = begin; + if (*begin != '{' && !find<IS_CONSTEXPR>(begin, end, '{', p)) + return write(begin, end); + write(begin, p); + ++p; + if (p == end) + return handler.on_error("invalid format string"); + if (static_cast<char>(*p) == '}') { + handler.on_arg_id(); + handler.on_replacement_field(p); + } else if (*p == '{') { + handler.on_text(p, p + 1); + } else { + p = parse_arg_id(p, end, id_adapter<Handler, Char>{handler}); + Char c = p != end ? *p : Char(); + if (c == '}') { + handler.on_replacement_field(p); + } else if (c == ':') { + p = handler.on_format_specs(p + 1, end); + if (p == end || *p != '}') + return handler.on_error("unknown format specifier"); + } else { + return handler.on_error("missing '}' in format string"); + } + } + begin = p + 1; + } +} + +template <typename T, typename ParseContext> +FMT_CONSTEXPR const typename ParseContext::char_type * + parse_format_specs(ParseContext &ctx) { + // GCC 7.2 requires initializer. + formatter<T, typename ParseContext::char_type> f{}; + return f.parse(ctx); +} + +template <typename Char, typename ErrorHandler, typename... Args> +class format_string_checker { + public: + explicit FMT_CONSTEXPR format_string_checker( + basic_string_view<Char> format_str, ErrorHandler eh) + : arg_id_((std::numeric_limits<unsigned>::max)()), context_(format_str, eh), + parse_funcs_{&parse_format_specs<Args, parse_context_type>...} {} + + FMT_CONSTEXPR void on_text(const Char *, const Char *) {} + + FMT_CONSTEXPR void on_arg_id() { + arg_id_ = context_.next_arg_id(); + check_arg_id(); + } + FMT_CONSTEXPR void on_arg_id(unsigned id) { + arg_id_ = id; + context_.check_arg_id(id); + check_arg_id(); + } + FMT_CONSTEXPR void on_arg_id(basic_string_view<Char>) {} + + FMT_CONSTEXPR void on_replacement_field(const Char *) {} + + FMT_CONSTEXPR const Char *on_format_specs(const Char *begin, const Char *) { + context_.advance_to(begin); + return arg_id_ < NUM_ARGS ? + parse_funcs_[arg_id_](context_) : begin; + } + + FMT_CONSTEXPR void on_error(const char *message) { + context_.on_error(message); + } + + private: + typedef basic_parse_context<Char, ErrorHandler> parse_context_type; + enum { NUM_ARGS = sizeof...(Args) }; + + FMT_CONSTEXPR void check_arg_id() { + if (arg_id_ >= NUM_ARGS) + context_.on_error("argument index out of range"); + } + + // Format specifier parsing function. + typedef const Char *(*parse_func)(parse_context_type &); + + unsigned arg_id_; + parse_context_type context_; + parse_func parse_funcs_[NUM_ARGS > 0 ? NUM_ARGS : 1]; +}; + +template <typename Char, typename ErrorHandler, typename... Args> +FMT_CONSTEXPR bool do_check_format_string( + basic_string_view<Char> s, ErrorHandler eh = ErrorHandler()) { + format_string_checker<Char, ErrorHandler, Args...> checker(s, eh); + parse_format_string<true>(s, checker); + return true; +} + +template <typename... Args, typename S> +typename std::enable_if<is_compile_string<S>::value>::type + check_format_string(S format_str) { + typedef typename S::char_type char_t; + FMT_CONSTEXPR_DECL bool invalid_format = internal::do_check_format_string< + char_t, internal::error_handler, Args...>(to_string_view(format_str)); + (void)invalid_format; +} + +// Specifies whether to format T using the standard formatter. +// It is not possible to use get_type in formatter specialization directly +// because of a bug in MSVC. +template <typename Context, typename T> +struct format_type : + std::integral_constant<bool, get_type<Context, T>::value != custom_type> {}; + +template <template <typename> class Handler, typename Spec, typename Context> +void handle_dynamic_spec( + Spec &value, arg_ref<typename Context::char_type> ref, Context &ctx) { + typedef typename Context::char_type char_type; + switch (ref.kind) { + case arg_ref<char_type>::NONE: + break; + case arg_ref<char_type>::INDEX: + internal::set_dynamic_spec<Handler>( + value, ctx.get_arg(ref.index), ctx.error_handler()); + break; + case arg_ref<char_type>::NAME: + internal::set_dynamic_spec<Handler>( + value, ctx.get_arg({ref.name.value, ref.name.size}), + ctx.error_handler()); + break; + } +} +} // namespace internal + +/** The default argument formatter. */ +template <typename Range> +class arg_formatter: + public internal::function< + typename internal::arg_formatter_base<Range>::iterator>, + public internal::arg_formatter_base<Range> { + private: + typedef typename Range::value_type char_type; + typedef internal::arg_formatter_base<Range> base; + typedef basic_format_context<typename base::iterator, char_type> context_type; + + context_type &ctx_; + + public: + typedef Range range; + typedef typename base::iterator iterator; + typedef typename base::format_specs format_specs; + + /** + \rst + Constructs an argument formatter object. + *ctx* is a reference to the formatting context, + *spec* contains format specifier information for standard argument types. + \endrst + */ + explicit arg_formatter(context_type &ctx, format_specs *spec = FMT_NULL) + : base(Range(ctx.out()), spec, ctx.locale()), ctx_(ctx) {} + + // Deprecated. + arg_formatter(context_type &ctx, format_specs &spec) + : base(Range(ctx.out()), &spec), ctx_(ctx) {} + + using base::operator(); + + /** Formats an argument of a user-defined type. */ + iterator operator()(typename basic_format_arg<context_type>::handle handle) { + handle.format(ctx_); + return this->out(); + } +}; + +/** + An error returned by an operating system or a language runtime, + for example a file opening error. +*/ +class system_error : public std::runtime_error { + private: + FMT_API void init(int err_code, string_view format_str, format_args args); + + protected: + int error_code_; + + system_error() : std::runtime_error("") {} + + public: + /** + \rst + Constructs a :class:`fmt::system_error` object with a description + formatted with `fmt::format_system_error`. *message* and additional + arguments passed into the constructor are formatted similarly to + `fmt::format`. + + **Example**:: + + // This throws a system_error with the description + // cannot open file 'madeup': No such file or directory + // or similar (system message may vary). + const char *filename = "madeup"; + std::FILE *file = std::fopen(filename, "r"); + if (!file) + throw fmt::system_error(errno, "cannot open file '{}'", filename); + \endrst + */ + template <typename... Args> + system_error(int error_code, string_view message, const Args &... args) + : std::runtime_error("") { + init(error_code, message, make_format_args(args...)); + } + + int error_code() const { return error_code_; } +}; + +/** + \rst + Formats an error returned by an operating system or a language runtime, + for example a file opening error, and writes it to *out* in the following + form: + + .. parsed-literal:: + *<message>*: *<system-message>* + + where *<message>* is the passed message and *<system-message>* is + the system message corresponding to the error code. + *error_code* is a system error code as given by ``errno``. + If *error_code* is not a valid error code such as -1, the system message + may look like "Unknown error -1" and is platform-dependent. + \endrst + */ +FMT_API void format_system_error(internal::buffer &out, int error_code, + fmt::string_view message) FMT_NOEXCEPT; + +/** + This template provides operations for formatting and writing data into a + character range. + */ +template <typename Range> +class basic_writer { + public: + typedef typename Range::value_type char_type; + typedef decltype(internal::declval<Range>().begin()) iterator; + typedef basic_format_specs<char_type> format_specs; + + private: + iterator out_; // Output iterator. + internal::locale_ref locale_; + + // Attempts to reserve space for n extra characters in the output range. + // Returns a pointer to the reserved range or a reference to out_. + auto reserve(std::size_t n) -> decltype(internal::reserve(out_, n)) { + return internal::reserve(out_, n); + } + + // Writes a value in the format + // <left-padding><value><right-padding> + // where <value> is written by f(it). + template <typename F> + void write_padded(const align_spec &spec, F &&f) { + unsigned width = spec.width(); // User-perceived width (in code points). + size_t size = f.size(); // The number of code units. + size_t num_code_points = width != 0 ? f.width() : size; + if (width <= num_code_points) + return f(reserve(size)); + auto &&it = reserve(width + (size - num_code_points)); + char_type fill = static_cast<char_type>(spec.fill()); + std::size_t padding = width - num_code_points; + if (spec.align() == ALIGN_RIGHT) { + it = std::fill_n(it, padding, fill); + f(it); + } else if (spec.align() == ALIGN_CENTER) { + std::size_t left_padding = padding / 2; + it = std::fill_n(it, left_padding, fill); + f(it); + it = std::fill_n(it, padding - left_padding, fill); + } else { + f(it); + it = std::fill_n(it, padding, fill); + } + } + + template <typename F> + struct padded_int_writer { + size_t size_; + string_view prefix; + char_type fill; + std::size_t padding; + F f; + + size_t size() const { return size_; } + size_t width() const { return size_; } + + template <typename It> + void operator()(It &&it) const { + if (prefix.size() != 0) + it = internal::copy_str<char_type>(prefix.begin(), prefix.end(), it); + it = std::fill_n(it, padding, fill); + f(it); + } + }; + + // Writes an integer in the format + // <left-padding><prefix><numeric-padding><digits><right-padding> + // where <digits> are written by f(it). + template <typename Spec, typename F> + void write_int(int num_digits, string_view prefix, + const Spec &spec, F f) { + std::size_t size = prefix.size() + internal::to_unsigned(num_digits); + char_type fill = static_cast<char_type>(spec.fill()); + std::size_t padding = 0; + if (spec.align() == ALIGN_NUMERIC) { + if (spec.width() > size) { + padding = spec.width() - size; + size = spec.width(); + } + } else if (spec.precision > num_digits) { + size = prefix.size() + internal::to_unsigned(spec.precision); + padding = internal::to_unsigned(spec.precision - num_digits); + fill = static_cast<char_type>('0'); + } + align_spec as = spec; + if (spec.align() == ALIGN_DEFAULT) + as.align_ = ALIGN_RIGHT; + write_padded(as, padded_int_writer<F>{size, prefix, fill, padding, f}); + } + + // Writes a decimal integer. + template <typename Int> + void write_decimal(Int value) { + typedef typename internal::int_traits<Int>::main_type main_type; + main_type abs_value = static_cast<main_type>(value); + bool is_negative = internal::is_negative(value); + if (is_negative) + abs_value = 0 - abs_value; + int num_digits = internal::count_digits(abs_value); + auto &&it = reserve((is_negative ? 1 : 0) + static_cast<size_t>(num_digits)); + if (is_negative) + *it++ = static_cast<char_type>('-'); + it = internal::format_decimal<char_type>(it, abs_value, num_digits); + } + + // The handle_int_type_spec handler that writes an integer. + template <typename Int, typename Spec> + struct int_writer { + typedef typename internal::int_traits<Int>::main_type unsigned_type; + + basic_writer<Range> &writer; + const Spec &spec; + unsigned_type abs_value; + char prefix[4]; + unsigned prefix_size; + + string_view get_prefix() const { return string_view(prefix, prefix_size); } + + // Counts the number of digits in abs_value. BITS = log2(radix). + template <unsigned BITS> + int count_digits() const { + unsigned_type n = abs_value; + int num_digits = 0; + do { + ++num_digits; + } while ((n >>= BITS) != 0); + return num_digits; + } + + int_writer(basic_writer<Range> &w, Int value, const Spec &s) + : writer(w), spec(s), abs_value(static_cast<unsigned_type>(value)), + prefix_size(0) { + if (internal::is_negative(value)) { + prefix[0] = '-'; + ++prefix_size; + abs_value = 0 - abs_value; + } else if (spec.has(SIGN_FLAG)) { + prefix[0] = spec.has(PLUS_FLAG) ? '+' : ' '; + ++prefix_size; + } + } + + struct dec_writer { + unsigned_type abs_value; + int num_digits; + + template <typename It> + void operator()(It &&it) const { + it = internal::format_decimal<char_type>(it, abs_value, num_digits); + } + }; + + void on_dec() { + int num_digits = internal::count_digits(abs_value); + writer.write_int(num_digits, get_prefix(), spec, + dec_writer{abs_value, num_digits}); + } + + struct hex_writer { + int_writer &self; + int num_digits; + + template <typename It> + void operator()(It &&it) const { + it = internal::format_uint<4, char_type>( + it, self.abs_value, num_digits, self.spec.type != 'x'); + } + }; + + void on_hex() { + if (spec.has(HASH_FLAG)) { + prefix[prefix_size++] = '0'; + prefix[prefix_size++] = static_cast<char>(spec.type); + } + int num_digits = count_digits<4>(); + writer.write_int(num_digits, get_prefix(), spec, + hex_writer{*this, num_digits}); + } + + template <int BITS> + struct bin_writer { + unsigned_type abs_value; + int num_digits; + + template <typename It> + void operator()(It &&it) const { + it = internal::format_uint<BITS, char_type>(it, abs_value, num_digits); + } + }; + + void on_bin() { + if (spec.has(HASH_FLAG)) { + prefix[prefix_size++] = '0'; + prefix[prefix_size++] = static_cast<char>(spec.type); + } + int num_digits = count_digits<1>(); + writer.write_int(num_digits, get_prefix(), spec, + bin_writer<1>{abs_value, num_digits}); + } + + void on_oct() { + int num_digits = count_digits<3>(); + if (spec.has(HASH_FLAG) && + spec.precision <= num_digits) { + // Octal prefix '0' is counted as a digit, so only add it if precision + // is not greater than the number of digits. + prefix[prefix_size++] = '0'; + } + writer.write_int(num_digits, get_prefix(), spec, + bin_writer<3>{abs_value, num_digits}); + } + + enum { SEP_SIZE = 1 }; + + struct num_writer { + unsigned_type abs_value; + int size; + char_type sep; + + template <typename It> + void operator()(It &&it) const { + basic_string_view<char_type> s(&sep, SEP_SIZE); + it = internal::format_decimal<char_type>( + it, abs_value, size, internal::add_thousands_sep<char_type>(s)); + } + }; + + void on_num() { + int num_digits = internal::count_digits(abs_value); + char_type sep = internal::thousands_sep<char_type>(writer.locale_); + int size = num_digits + SEP_SIZE * ((num_digits - 1) / 3); + writer.write_int(size, get_prefix(), spec, + num_writer{abs_value, size, sep}); + } + + void on_error() { + FMT_THROW(format_error("invalid type specifier")); + } + }; + + // Writes a formatted integer. + template <typename T, typename Spec> + void write_int(T value, const Spec &spec) { + internal::handle_int_type_spec(spec.type, + int_writer<T, Spec>(*this, value, spec)); + } + + enum {INF_SIZE = 3}; // This is an enum to workaround a bug in MSVC. + + struct inf_or_nan_writer { + char sign; + const char *str; + + size_t size() const { + return static_cast<std::size_t>(INF_SIZE + (sign ? 1 : 0)); + } + size_t width() const { return size(); } + + template <typename It> + void operator()(It &&it) const { + if (sign) + *it++ = static_cast<char_type>(sign); + it = internal::copy_str<char_type>( + str, str + static_cast<std::size_t>(INF_SIZE), it); + } + }; + + struct double_writer { + size_t n; + char sign; + internal::buffer &buffer; + + size_t size() const { return buffer.size() + (sign ? 1 : 0); } + size_t width() const { return size(); } + + template <typename It> + void operator()(It &&it) { + if (sign) { + *it++ = static_cast<char_type>(sign); + --n; + } + it = internal::copy_str<char_type>(buffer.begin(), buffer.end(), it); + } + }; + + // Formats a floating-point number (double or long double). + template <typename T> + void write_double(T value, const format_specs &spec); + + template <typename Char> + struct str_writer { + const Char *s; + size_t size_; + + size_t size() const { return size_; } + size_t width() const { + return internal::count_code_points(basic_string_view<Char>(s, size_)); + } + + template <typename It> + void operator()(It &&it) const { + it = internal::copy_str<char_type>(s, s + size_, it); + } + }; + + template <typename Char> + friend class internal::arg_formatter_base; + + public: + /** Constructs a ``basic_writer`` object. */ + explicit basic_writer( + Range out, internal::locale_ref loc = internal::locale_ref()) + : out_(out.begin()), locale_(loc) {} + + iterator out() const { return out_; } + + void write(int value) { write_decimal(value); } + void write(long value) { write_decimal(value); } + void write(long long value) { write_decimal(value); } + + void write(unsigned value) { write_decimal(value); } + void write(unsigned long value) { write_decimal(value); } + void write(unsigned long long value) { write_decimal(value); } + + /** + \rst + Formats *value* and writes it to the buffer. + \endrst + */ + template <typename T, typename FormatSpec, typename... FormatSpecs> + typename std::enable_if<std::is_integral<T>::value, void>::type + write(T value, FormatSpec spec, FormatSpecs... specs) { + format_specs s(spec, specs...); + s.align_ = ALIGN_RIGHT; + write_int(value, s); + } + + void write(double value) { + write_double(value, format_specs()); + } + + /** + \rst + Formats *value* using the general format for floating-point numbers + (``'g'``) and writes it to the buffer. + \endrst + */ + void write(long double value) { + write_double(value, format_specs()); + } + + /** Writes a character to the buffer. */ + void write(char value) { + *reserve(1) = value; + } + void write(wchar_t value) { + static_assert(std::is_same<char_type, wchar_t>::value, ""); + *reserve(1) = value; + } + + /** + \rst + Writes *value* to the buffer. + \endrst + */ + void write(string_view value) { + auto &&it = reserve(value.size()); + it = internal::copy_str<char_type>(value.begin(), value.end(), it); + } + void write(wstring_view value) { + static_assert(std::is_same<char_type, wchar_t>::value, ""); + auto &&it = reserve(value.size()); + it = std::copy(value.begin(), value.end(), it); + } + + // Writes a formatted string. + template <typename Char> + void write(const Char *s, std::size_t size, const align_spec &spec) { + write_padded(spec, str_writer<Char>{s, size}); + } + + template <typename Char> + void write(basic_string_view<Char> s, + const format_specs &spec = format_specs()) { + const Char *data = s.data(); + std::size_t size = s.size(); + if (spec.precision >= 0 && internal::to_unsigned(spec.precision) < size) + size = internal::to_unsigned(spec.precision); + write(data, size, spec); + } + + template <typename T> + typename std::enable_if<std::is_same<T, void>::value>::type + write(const T *p) { + format_specs specs; + specs.flags = HASH_FLAG; + specs.type = 'x'; + write_int(reinterpret_cast<uintptr_t>(p), specs); + } +}; + +struct float_spec_handler { + char type; + bool upper; + + explicit float_spec_handler(char t) : type(t), upper(false) {} + + void on_general() { + if (type == 'G') + upper = true; + else + type = 'g'; + } + + void on_exp() { + if (type == 'E') + upper = true; + } + + void on_fixed() { + if (type == 'F') { + upper = true; +#if FMT_MSC_VER + // MSVC's printf doesn't support 'F'. + type = 'f'; +#endif + } + } + + void on_hex() { + if (type == 'A') + upper = true; + } + + void on_error() { + FMT_THROW(format_error("invalid type specifier")); + } +}; + +template <typename Range> +template <typename T> +void basic_writer<Range>::write_double(T value, const format_specs &spec) { + // Check type. + float_spec_handler handler(static_cast<char>(spec.type)); + internal::handle_float_type_spec(handler.type, handler); + + char sign = 0; + // Use signbit instead of value < 0 because the latter is always + // false for NaN. + if (std::signbit(value)) { + sign = '-'; + value = -value; + } else if (spec.has(SIGN_FLAG)) { + sign = spec.has(PLUS_FLAG) ? '+' : ' '; + } + + struct write_inf_or_nan_t { + basic_writer &writer; + format_specs spec; + char sign; + void operator()(const char *str) const { + writer.write_padded(spec, inf_or_nan_writer{sign, str}); + } + } write_inf_or_nan = {*this, spec, sign}; + + // Format NaN and ininity ourselves because sprintf's output is not consistent + // across platforms. + if (internal::fputil::isnotanumber(value)) + return write_inf_or_nan(handler.upper ? "NAN" : "nan"); + if (internal::fputil::isinfinity(value)) + return write_inf_or_nan(handler.upper ? "INF" : "inf"); + + memory_buffer buffer; + bool use_grisu = FMT_USE_GRISU && sizeof(T) <= sizeof(double) && + spec.type != 'a' && spec.type != 'A' && + internal::grisu2_format(static_cast<double>(value), buffer, spec); + if (!use_grisu) { + format_specs normalized_spec(spec); + normalized_spec.type = handler.type; + internal::sprintf_format(value, buffer, normalized_spec); + } + size_t n = buffer.size(); + align_spec as = spec; + if (spec.align() == ALIGN_NUMERIC) { + if (sign) { + auto &&it = reserve(1); + *it++ = static_cast<char_type>(sign); + sign = 0; + if (as.width_) + --as.width_; + } + as.align_ = ALIGN_RIGHT; + } else { + if (spec.align() == ALIGN_DEFAULT) + as.align_ = ALIGN_RIGHT; + if (sign) + ++n; + } + write_padded(as, double_writer{n, sign, buffer}); +} + +// Reports a system error without throwing an exception. +// Can be used to report errors from destructors. +FMT_API void report_system_error(int error_code, + string_view message) FMT_NOEXCEPT; + +#if FMT_USE_WINDOWS_H + +/** A Windows error. */ +class windows_error : public system_error { + private: + FMT_API void init(int error_code, string_view format_str, format_args args); + + public: + /** + \rst + Constructs a :class:`fmt::windows_error` object with the description + of the form + + .. parsed-literal:: + *<message>*: *<system-message>* + + where *<message>* is the formatted message and *<system-message>* is the + system message corresponding to the error code. + *error_code* is a Windows error code as given by ``GetLastError``. + If *error_code* is not a valid error code such as -1, the system message + will look like "error -1". + + **Example**:: + + // This throws a windows_error with the description + // cannot open file 'madeup': The system cannot find the file specified. + // or similar (system message may vary). + const char *filename = "madeup"; + LPOFSTRUCT of = LPOFSTRUCT(); + HFILE file = OpenFile(filename, &of, OF_READ); + if (file == HFILE_ERROR) { + throw fmt::windows_error(GetLastError(), + "cannot open file '{}'", filename); + } + \endrst + */ + template <typename... Args> + windows_error(int error_code, string_view message, const Args &... args) { + init(error_code, message, make_format_args(args...)); + } +}; + +// Reports a Windows error without throwing an exception. +// Can be used to report errors from destructors. +FMT_API void report_windows_error(int error_code, + string_view message) FMT_NOEXCEPT; + +#endif + +/** Fast integer formatter. */ +class format_int { + private: + // Buffer should be large enough to hold all digits (digits10 + 1), + // a sign and a null character. + enum {BUFFER_SIZE = std::numeric_limits<unsigned long long>::digits10 + 3}; + mutable char buffer_[BUFFER_SIZE]; + char *str_; + + // Formats value in reverse and returns a pointer to the beginning. + char *format_decimal(unsigned long long value) { + char *ptr = buffer_ + (BUFFER_SIZE - 1); // Parens to workaround MSVC bug. + while (value >= 100) { + // Integer division is slow so do it for a group of two digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + unsigned index = static_cast<unsigned>((value % 100) * 2); + value /= 100; + *--ptr = internal::data::DIGITS[index + 1]; + *--ptr = internal::data::DIGITS[index]; + } + if (value < 10) { + *--ptr = static_cast<char>('0' + value); + return ptr; + } + unsigned index = static_cast<unsigned>(value * 2); + *--ptr = internal::data::DIGITS[index + 1]; + *--ptr = internal::data::DIGITS[index]; + return ptr; + } + + void format_signed(long long value) { + unsigned long long abs_value = static_cast<unsigned long long>(value); + bool negative = value < 0; + if (negative) + abs_value = 0 - abs_value; + str_ = format_decimal(abs_value); + if (negative) + *--str_ = '-'; + } + + public: + explicit format_int(int value) { format_signed(value); } + explicit format_int(long value) { format_signed(value); } + explicit format_int(long long value) { format_signed(value); } + explicit format_int(unsigned value) : str_(format_decimal(value)) {} + explicit format_int(unsigned long value) : str_(format_decimal(value)) {} + explicit format_int(unsigned long long value) : str_(format_decimal(value)) {} + + /** Returns the number of characters written to the output buffer. */ + std::size_t size() const { + return internal::to_unsigned(buffer_ - str_ + BUFFER_SIZE - 1); + } + + /** + Returns a pointer to the output buffer content. No terminating null + character is appended. + */ + const char *data() const { return str_; } + + /** + Returns a pointer to the output buffer content with terminating null + character appended. + */ + const char *c_str() const { + buffer_[BUFFER_SIZE - 1] = '\0'; + return str_; + } + + /** + \rst + Returns the content of the output buffer as an ``std::string``. + \endrst + */ + std::string str() const { return std::string(str_, size()); } +}; + +// DEPRECATED! +// Formats a decimal integer value writing into buffer and returns +// a pointer to the end of the formatted string. This function doesn't +// write a terminating null character. +template <typename T> +inline void format_decimal(char *&buffer, T value) { + typedef typename internal::int_traits<T>::main_type main_type; + main_type abs_value = static_cast<main_type>(value); + if (internal::is_negative(value)) { + *buffer++ = '-'; + abs_value = 0 - abs_value; + } + if (abs_value < 100) { + if (abs_value < 10) { + *buffer++ = static_cast<char>('0' + abs_value); + return; + } + unsigned index = static_cast<unsigned>(abs_value * 2); + *buffer++ = internal::data::DIGITS[index]; + *buffer++ = internal::data::DIGITS[index + 1]; + return; + } + int num_digits = internal::count_digits(abs_value); + internal::format_decimal<char>( + internal::make_checked(buffer, internal::to_unsigned(num_digits)), abs_value, num_digits); + buffer += num_digits; +} + +// Formatter of objects of type T. +template <typename T, typename Char> +struct formatter< + T, Char, + typename std::enable_if<internal::format_type< + typename buffer_context<Char>::type, T>::value>::type> { + + // Parses format specifiers stopping either at the end of the range or at the + // terminating '}'. + template <typename ParseContext> + FMT_CONSTEXPR typename ParseContext::iterator parse(ParseContext &ctx) { + typedef internal::dynamic_specs_handler<ParseContext> handler_type; + auto type = internal::get_type< + typename buffer_context<Char>::type, T>::value; + internal::specs_checker<handler_type> + handler(handler_type(specs_, ctx), type); + auto it = parse_format_specs(ctx.begin(), ctx.end(), handler); + auto type_spec = specs_.type; + auto eh = ctx.error_handler(); + switch (type) { + case internal::none_type: + case internal::named_arg_type: + FMT_ASSERT(false, "invalid argument type"); + break; + case internal::int_type: + case internal::uint_type: + case internal::long_long_type: + case internal::ulong_long_type: + case internal::bool_type: + handle_int_type_spec( + type_spec, internal::int_type_checker<decltype(eh)>(eh)); + break; + case internal::char_type: + handle_char_specs( + &specs_, + internal::char_specs_checker<decltype(eh)>(type_spec, eh)); + break; + case internal::double_type: + case internal::long_double_type: + handle_float_type_spec( + type_spec, internal::float_type_checker<decltype(eh)>(eh)); + break; + case internal::cstring_type: + internal::handle_cstring_type_spec( + type_spec, internal::cstring_type_checker<decltype(eh)>(eh)); + break; + case internal::string_type: + internal::check_string_type_spec(type_spec, eh); + break; + case internal::pointer_type: + internal::check_pointer_type_spec(type_spec, eh); + break; + case internal::custom_type: + // Custom format specifiers should be checked in parse functions of + // formatter specializations. + break; + } + return it; + } + + template <typename FormatContext> + auto format(const T &val, FormatContext &ctx) -> decltype(ctx.out()) { + internal::handle_dynamic_spec<internal::width_checker>( + specs_.width_, specs_.width_ref, ctx); + internal::handle_dynamic_spec<internal::precision_checker>( + specs_.precision, specs_.precision_ref, ctx); + typedef output_range<typename FormatContext::iterator, + typename FormatContext::char_type> range_type; + return visit_format_arg(arg_formatter<range_type>(ctx, &specs_), + internal::make_arg<FormatContext>(val)); + } + + private: + internal::dynamic_format_specs<Char> specs_; +}; + +// A formatter for types known only at run time such as variant alternatives. +// +// Usage: +// typedef std::variant<int, std::string> variant; +// template <> +// struct formatter<variant>: dynamic_formatter<> { +// void format(buffer &buf, const variant &v, context &ctx) { +// visit([&](const auto &val) { format(buf, val, ctx); }, v); +// } +// }; +template <typename Char = char> +class dynamic_formatter { + private: + struct null_handler: internal::error_handler { + void on_align(alignment) {} + void on_plus() {} + void on_minus() {} + void on_space() {} + void on_hash() {} + }; + + public: + template <typename ParseContext> + auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + // Checks are deferred to formatting time when the argument type is known. + internal::dynamic_specs_handler<ParseContext> handler(specs_, ctx); + return parse_format_specs(ctx.begin(), ctx.end(), handler); + } + + template <typename T, typename FormatContext> + auto format(const T &val, FormatContext &ctx) -> decltype(ctx.out()) { + handle_specs(ctx); + internal::specs_checker<null_handler> + checker(null_handler(), internal::get_type<FormatContext, T>::value); + checker.on_align(specs_.align()); + if (specs_.flags == 0); // Do nothing. + else if (specs_.has(SIGN_FLAG)) + specs_.has(PLUS_FLAG) ? checker.on_plus() : checker.on_space(); + else if (specs_.has(MINUS_FLAG)) + checker.on_minus(); + else if (specs_.has(HASH_FLAG)) + checker.on_hash(); + if (specs_.precision != -1) + checker.end_precision(); + typedef output_range<typename FormatContext::iterator, + typename FormatContext::char_type> range; + visit_format_arg(arg_formatter<range>(ctx, &specs_), + internal::make_arg<FormatContext>(val)); + return ctx.out(); + } + + private: + template <typename Context> + void handle_specs(Context &ctx) { + internal::handle_dynamic_spec<internal::width_checker>( + specs_.width_, specs_.width_ref, ctx); + internal::handle_dynamic_spec<internal::precision_checker>( + specs_.precision, specs_.precision_ref, ctx); + } + + internal::dynamic_format_specs<Char> specs_; +}; + +template <typename Range, typename Char> +typename basic_format_context<Range, Char>::format_arg + basic_format_context<Range, Char>::get_arg( + basic_string_view<char_type> name) { + map_.init(this->args()); + format_arg arg = map_.find(name); + if (arg.type() == internal::none_type) + this->on_error("argument not found"); + return arg; +} + +template <typename ArgFormatter, typename Char, typename Context> +struct format_handler : internal::error_handler { + typedef typename ArgFormatter::range range; + + format_handler(range r, basic_string_view<Char> str, + basic_format_args<Context> format_args, + internal::locale_ref loc) + : context(r.begin(), str, format_args, loc) {} + + void on_text(const Char *begin, const Char *end) { + auto size = internal::to_unsigned(end - begin); + auto out = context.out(); + auto &&it = internal::reserve(out, size); + it = std::copy_n(begin, size, it); + context.advance_to(out); + } + + void on_arg_id() { arg = context.next_arg(); } + void on_arg_id(unsigned id) { + context.parse_context().check_arg_id(id); + arg = context.get_arg(id); + } + void on_arg_id(basic_string_view<Char> id) { + arg = context.get_arg(id); + } + + void on_replacement_field(const Char *p) { + context.parse_context().advance_to(p); + internal::custom_formatter<Char, Context> f(context); + if (!visit_format_arg(f, arg)) + context.advance_to(visit_format_arg(ArgFormatter(context), arg)); + } + + const Char *on_format_specs(const Char *begin, const Char *end) { + auto &parse_ctx = context.parse_context(); + parse_ctx.advance_to(begin); + internal::custom_formatter<Char, Context> f(context); + if (visit_format_arg(f, arg)) + return parse_ctx.begin(); + basic_format_specs<Char> specs; + using internal::specs_handler; + internal::specs_checker<specs_handler<Context>> + handler(specs_handler<Context>(specs, context), arg.type()); + begin = parse_format_specs(begin, end, handler); + if (begin == end || *begin != '}') + on_error("missing '}' in format string"); + parse_ctx.advance_to(begin); + context.advance_to(visit_format_arg(ArgFormatter(context, &specs), arg)); + return begin; + } + + Context context; + basic_format_arg<Context> arg; +}; + +/** Formats arguments and writes the output to the range. */ +template <typename ArgFormatter, typename Char, typename Context> +typename Context::iterator vformat_to( + typename ArgFormatter::range out, + basic_string_view<Char> format_str, + basic_format_args<Context> args, + internal::locale_ref loc = internal::locale_ref()) { + format_handler<ArgFormatter, Char, Context> h(out, format_str, args, loc); + internal::parse_format_string<false>(format_str, h); + return h.context.out(); +} + +// Casts ``p`` to ``const void*`` for pointer formatting. +// Example: +// auto s = format("{}", ptr(p)); +template <typename T> +inline const void *ptr(const T *p) { return p; } + +template <typename It, typename Char> +struct arg_join { + It begin; + It end; + basic_string_view<Char> sep; + + arg_join(It begin, It end, basic_string_view<Char> sep) + : begin(begin), end(end), sep(sep) {} +}; + +template <typename It, typename Char> +struct formatter<arg_join<It, Char>, Char>: + formatter<typename std::iterator_traits<It>::value_type, Char> { + template <typename FormatContext> + auto format(const arg_join<It, Char> &value, FormatContext &ctx) + -> decltype(ctx.out()) { + typedef formatter<typename std::iterator_traits<It>::value_type, Char> base; + auto it = value.begin; + auto out = ctx.out(); + if (it != value.end) { + out = base::format(*it++, ctx); + while (it != value.end) { + out = std::copy(value.sep.begin(), value.sep.end(), out); + ctx.advance_to(out); + out = base::format(*it++, ctx); + } + } + return out; + } +}; + +template <typename It> +arg_join<It, char> join(It begin, It end, string_view sep) { + return arg_join<It, char>(begin, end, sep); +} + +template <typename It> +arg_join<It, wchar_t> join(It begin, It end, wstring_view sep) { + return arg_join<It, wchar_t>(begin, end, sep); +} + +// The following causes ICE in gcc 4.4. +#if FMT_USE_TRAILING_RETURN && (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 405) +template <typename Range> +auto join(const Range &range, string_view sep) + -> arg_join<decltype(internal::begin(range)), char> { + return join(internal::begin(range), internal::end(range), sep); +} + +template <typename Range> +auto join(const Range &range, wstring_view sep) + -> arg_join<decltype(internal::begin(range)), wchar_t> { + return join(internal::begin(range), internal::end(range), sep); +} +#endif + +/** + \rst + Converts *value* to ``std::string`` using the default format for type *T*. + It doesn't support user-defined types with custom formatters. + + **Example**:: + + #include <fmt/format.h> + + std::string answer = fmt::to_string(42); + \endrst + */ +template <typename T> +std::string to_string(const T &value) { + std::string str; + internal::container_buffer<std::string> buf(str); + writer(buf).write(value); + return str; +} + +/** + Converts *value* to ``std::wstring`` using the default format for type *T*. + */ +template <typename T> +std::wstring to_wstring(const T &value) { + std::wstring str; + internal::container_buffer<std::wstring> buf(str); + wwriter(buf).write(value); + return str; +} + +template <typename Char, std::size_t SIZE> +std::basic_string<Char> to_string(const basic_memory_buffer<Char, SIZE> &buf) { + return std::basic_string<Char>(buf.data(), buf.size()); +} + +template <typename Char> +typename buffer_context<Char>::type::iterator internal::vformat_to( + internal::basic_buffer<Char> &buf, basic_string_view<Char> format_str, + basic_format_args<typename buffer_context<Char>::type> args) { + typedef back_insert_range<internal::basic_buffer<Char> > range; + return vformat_to<arg_formatter<range>>( + buf, to_string_view(format_str), args); +} + +template <typename S, typename Char = FMT_CHAR(S)> +inline typename buffer_context<Char>::type::iterator vformat_to( + internal::basic_buffer<Char> &buf, const S &format_str, + basic_format_args<typename buffer_context<Char>::type> args) { + return internal::vformat_to(buf, to_string_view(format_str), args); +} + +template < + typename S, typename... Args, + std::size_t SIZE = inline_buffer_size, + typename Char = typename internal::char_t<S>::type> +inline typename buffer_context<Char>::type::iterator format_to( + basic_memory_buffer<Char, SIZE> &buf, const S &format_str, + const Args &... args) { + internal::check_format_string<Args...>(format_str); + typedef typename buffer_context<Char>::type context; + format_arg_store<context, Args...> as{args...}; + return internal::vformat_to(buf, to_string_view(format_str), + basic_format_args<context>(as)); +} + +namespace internal { + +// Detect the iterator category of *any* given type in a SFINAE-friendly way. +// Unfortunately, older implementations of std::iterator_traits are not safe +// for use in a SFINAE-context. + +// the gist of C++17's void_t magic +template<typename... Ts> +struct void_ { typedef void type; }; + +template <typename T, typename Enable = void> +struct it_category : std::false_type {}; + +template <typename T> +struct it_category<T*> { typedef std::random_access_iterator_tag type; }; + +template <typename T> +struct it_category<T, typename void_<typename T::iterator_category>::type> { + typedef typename T::iterator_category type; +}; + +// Detect if *any* given type models the OutputIterator concept. +template <typename It> +class is_output_iterator { + // Check for mutability because all iterator categories derived from + // std::input_iterator_tag *may* also meet the requirements of an + // OutputIterator, thereby falling into the category of 'mutable iterators' + // [iterator.requirements.general] clause 4. + // The compiler reveals this property only at the point of *actually + // dereferencing* the iterator! + template <typename U> + static decltype(*(internal::declval<U>())) test(std::input_iterator_tag); + template <typename U> + static char& test(std::output_iterator_tag); + template <typename U> + static const char& test(...); + + typedef decltype(test<It>(typename it_category<It>::type{})) type; + typedef typename std::remove_reference<type>::type result; + public: + static const bool value = !std::is_const<result>::value; +}; +} // internal + +template <typename OutputIt, typename Char = char> +//using format_context_t = basic_format_context<OutputIt, Char>; +struct format_context_t { typedef basic_format_context<OutputIt, Char> type; }; + +template <typename OutputIt, typename Char = char> +//using format_args_t = basic_format_args<format_context_t<OutputIt, Char>>; +struct format_args_t { + typedef basic_format_args< + typename format_context_t<OutputIt, Char>::type> type; +}; + +template <typename String, typename OutputIt, typename... Args> +inline typename std::enable_if<internal::is_output_iterator<OutputIt>::value, + OutputIt>::type + vformat_to(OutputIt out, const String &format_str, + typename format_args_t<OutputIt, FMT_CHAR(String)>::type args) { + typedef output_range<OutputIt, FMT_CHAR(String)> range; + return vformat_to<arg_formatter<range>>(range(out), + to_string_view(format_str), args); +} + +/** + \rst + Formats arguments, writes the result to the output iterator ``out`` and returns + the iterator past the end of the output range. + + **Example**:: + + std::vector<char> out; + fmt::format_to(std::back_inserter(out), "{}", 42); + \endrst + */ +template <typename OutputIt, typename S, typename... Args> +inline FMT_ENABLE_IF_T( + internal::is_string<S>::value && + internal::is_output_iterator<OutputIt>::value, OutputIt) + format_to(OutputIt out, const S &format_str, const Args &... args) { + internal::check_format_string<Args...>(format_str); + typedef typename format_context_t<OutputIt, FMT_CHAR(S)>::type context; + format_arg_store<context, Args...> as{args...}; + return vformat_to(out, to_string_view(format_str), + basic_format_args<context>(as)); +} + +template <typename OutputIt> +struct format_to_n_result { + /** Iterator past the end of the output range. */ + OutputIt out; + /** Total (not truncated) output size. */ + std::size_t size; +}; + +template <typename OutputIt, typename Char = typename OutputIt::value_type> +struct format_to_n_context : + format_context_t<fmt::internal::truncating_iterator<OutputIt>, Char> {}; + +template <typename OutputIt, typename Char = typename OutputIt::value_type> +struct format_to_n_args { + typedef basic_format_args< + typename format_to_n_context<OutputIt, Char>::type> type; +}; + +template <typename OutputIt, typename Char, typename ...Args> +inline format_arg_store< + typename format_to_n_context<OutputIt, Char>::type, Args...> + make_format_to_n_args(const Args &... args) { + return format_arg_store< + typename format_to_n_context<OutputIt, Char>::type, Args...>(args...); +} + +template <typename OutputIt, typename Char, typename... Args> +inline typename std::enable_if< + internal::is_output_iterator<OutputIt>::value, + format_to_n_result<OutputIt>>::type vformat_to_n( + OutputIt out, std::size_t n, basic_string_view<Char> format_str, + typename format_to_n_args<OutputIt, Char>::type args) { + typedef internal::truncating_iterator<OutputIt> It; + auto it = vformat_to(It(out, n), format_str, args); + return {it.base(), it.count()}; +} + +/** + \rst + Formats arguments, writes up to ``n`` characters of the result to the output + iterator ``out`` and returns the total output size and the iterator past the + end of the output range. + \endrst + */ +template <typename OutputIt, typename S, typename... Args> +inline FMT_ENABLE_IF_T( + internal::is_string<S>::value && + internal::is_output_iterator<OutputIt>::value, + format_to_n_result<OutputIt>) + format_to_n(OutputIt out, std::size_t n, const S &format_str, + const Args &... args) { + internal::check_format_string<Args...>(format_str); + typedef FMT_CHAR(S) Char; + format_arg_store< + typename format_to_n_context<OutputIt, Char>::type, Args...> as(args...); + return vformat_to_n(out, n, to_string_view(format_str), + typename format_to_n_args<OutputIt, Char>::type(as)); +} + +template <typename Char> +inline std::basic_string<Char> internal::vformat( + basic_string_view<Char> format_str, + basic_format_args<typename buffer_context<Char>::type> args) { + basic_memory_buffer<Char> buffer; + internal::vformat_to(buffer, format_str, args); + return fmt::to_string(buffer); +} + +/** + Returns the number of characters in the output of + ``format(format_str, args...)``. + */ +template <typename... Args> +inline std::size_t formatted_size(string_view format_str, + const Args &... args) { + auto it = format_to(internal::counting_iterator<char>(), format_str, args...); + return it.count(); +} + +#if FMT_USE_USER_DEFINED_LITERALS +namespace internal { + +# if FMT_UDL_TEMPLATE +template <typename Char, Char... CHARS> +class udl_formatter { + public: + template <typename... Args> + std::basic_string<Char> operator()(const Args &... args) const { + FMT_CONSTEXPR_DECL Char s[] = {CHARS..., '\0'}; + FMT_CONSTEXPR_DECL bool invalid_format = + do_check_format_string<Char, error_handler, Args...>( + basic_string_view<Char>(s, sizeof...(CHARS))); + (void)invalid_format; + return format(s, args...); + } +}; +# else +template <typename Char> +struct udl_formatter { + const Char *str; + + template <typename... Args> + auto operator()(Args &&... args) const + -> decltype(format(str, std::forward<Args>(args)...)) { + return format(str, std::forward<Args>(args)...); + } +}; +# endif // FMT_UDL_TEMPLATE + +template <typename Char> +struct udl_arg { + const Char *str; + + template <typename T> + named_arg<T, Char> operator=(T &&value) const { + return {str, std::forward<T>(value)}; + } +}; + +} // namespace internal + +inline namespace literals { + +# if FMT_UDL_TEMPLATE +template <typename Char, Char... CHARS> +FMT_CONSTEXPR internal::udl_formatter<Char, CHARS...> operator""_format() { + return {}; +} +# else +/** + \rst + User-defined literal equivalent of :func:`fmt::format`. + + **Example**:: + + using namespace fmt::literals; + std::string message = "The answer is {}"_format(42); + \endrst + */ +inline internal::udl_formatter<char> +operator"" _format(const char *s, std::size_t) { return {s}; } +inline internal::udl_formatter<wchar_t> +operator"" _format(const wchar_t *s, std::size_t) { return {s}; } +# endif // FMT_UDL_TEMPLATE + +/** + \rst + User-defined literal equivalent of :func:`fmt::arg`. + + **Example**:: + + using namespace fmt::literals; + fmt::print("Elapsed time: {s:.2f} seconds", "s"_a=1.23); + \endrst + */ +inline internal::udl_arg<char> +operator"" _a(const char *s, std::size_t) { return {s}; } +inline internal::udl_arg<wchar_t> +operator"" _a(const wchar_t *s, std::size_t) { return {s}; } +} // inline namespace literals +#endif // FMT_USE_USER_DEFINED_LITERALS +FMT_END_NAMESPACE + +#define FMT_STRING(s) [] { \ + typedef typename std::remove_cv<std::remove_pointer< \ + typename std::decay<decltype(s)>::type>::type>::type ct; \ + struct str : fmt::compile_string { \ + typedef ct char_type; \ + FMT_CONSTEXPR operator fmt::basic_string_view<ct>() const { \ + return {s, sizeof(s) / sizeof(ct) - 1}; \ + } \ + }; \ + return str{}; \ + }() + +#if defined(FMT_STRING_ALIAS) && FMT_STRING_ALIAS +/** + \rst + Constructs a compile-time format string. This macro is disabled by default to + prevent potential name collisions. To enable it define ``FMT_STRING_ALIAS`` to + 1 before including ``fmt/format.h``. + + **Example**:: + + #define FMT_STRING_ALIAS 1 + #include <fmt/format.h> + // A compile-time error because 'd' is an invalid specifier for strings. + std::string s = format(fmt("{:d}"), "foo"); + \endrst + */ +# define fmt(s) FMT_STRING(s) +#endif + +#ifdef FMT_HEADER_ONLY +# define FMT_FUNC inline +# include "format-inl.h" +#else +# define FMT_FUNC +#endif + +// Restore warnings. +#if FMT_GCC_VERSION >= 406 || FMT_CLANG_VERSION +# pragma GCC diagnostic pop +#endif + +#endif // FMT_FORMAT_H_ diff --git a/matching/include/spdlog/fmt/bundled/locale.h b/matching/include/spdlog/fmt/bundled/locale.h new file mode 100644 index 0000000..8e021bc --- /dev/null +++ b/matching/include/spdlog/fmt/bundled/locale.h @@ -0,0 +1,77 @@ +// Formatting library for C++ - std::locale support +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_LOCALE_H_ +#define FMT_LOCALE_H_ + +#include "format.h" +#include <locale> + +FMT_BEGIN_NAMESPACE + +namespace internal { +template <typename Char> +typename buffer_context<Char>::type::iterator vformat_to( + const std::locale &loc, basic_buffer<Char> &buf, + basic_string_view<Char> format_str, + basic_format_args<typename buffer_context<Char>::type> args) { + typedef back_insert_range<basic_buffer<Char> > range; + return vformat_to<arg_formatter<range>>( + buf, to_string_view(format_str), args, internal::locale_ref(loc)); +} + +template <typename Char> +std::basic_string<Char> vformat( + const std::locale &loc, basic_string_view<Char> format_str, + basic_format_args<typename buffer_context<Char>::type> args) { + basic_memory_buffer<Char> buffer; + internal::vformat_to(loc, buffer, format_str, args); + return fmt::to_string(buffer); +} +} + +template <typename S, typename Char = FMT_CHAR(S)> +inline std::basic_string<Char> vformat( + const std::locale &loc, const S &format_str, + basic_format_args<typename buffer_context<Char>::type> args) { + return internal::vformat(loc, to_string_view(format_str), args); +} + +template <typename S, typename... Args> +inline std::basic_string<FMT_CHAR(S)> format( + const std::locale &loc, const S &format_str, const Args &... args) { + return internal::vformat( + loc, to_string_view(format_str), + *internal::checked_args<S, Args...>(format_str, args...)); +} + +template <typename String, typename OutputIt, typename... Args> +inline typename std::enable_if<internal::is_output_iterator<OutputIt>::value, + OutputIt>::type + vformat_to(OutputIt out, const std::locale &loc, const String &format_str, + typename format_args_t<OutputIt, FMT_CHAR(String)>::type args) { + typedef output_range<OutputIt, FMT_CHAR(String)> range; + return vformat_to<arg_formatter<range>>( + range(out), to_string_view(format_str), args, internal::locale_ref(loc)); +} + +template <typename OutputIt, typename S, typename... Args> +inline typename std::enable_if< + internal::is_string<S>::value && + internal::is_output_iterator<OutputIt>::value, OutputIt>::type + format_to(OutputIt out, const std::locale &loc, const S &format_str, + const Args &... args) { + internal::check_format_string<Args...>(format_str); + typedef typename format_context_t<OutputIt, FMT_CHAR(S)>::type context; + format_arg_store<context, Args...> as{args...}; + return vformat_to(out, loc, to_string_view(format_str), + basic_format_args<context>(as)); +} + +FMT_END_NAMESPACE + +#endif // FMT_LOCALE_H_ diff --git a/matching/include/spdlog/fmt/bundled/ostream.h b/matching/include/spdlog/fmt/bundled/ostream.h new file mode 100644 index 0000000..84b31cc --- /dev/null +++ b/matching/include/spdlog/fmt/bundled/ostream.h @@ -0,0 +1,153 @@ +// Formatting library for C++ - std::ostream support +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_OSTREAM_H_ +#define FMT_OSTREAM_H_ + +#include "format.h" +#include <ostream> + +FMT_BEGIN_NAMESPACE +namespace internal { + +template <class Char> +class formatbuf : public std::basic_streambuf<Char> { + private: + typedef typename std::basic_streambuf<Char>::int_type int_type; + typedef typename std::basic_streambuf<Char>::traits_type traits_type; + + basic_buffer<Char> &buffer_; + + public: + formatbuf(basic_buffer<Char> &buffer) : buffer_(buffer) {} + + protected: + // The put-area is actually always empty. This makes the implementation + // simpler and has the advantage that the streambuf and the buffer are always + // in sync and sputc never writes into uninitialized memory. The obvious + // disadvantage is that each call to sputc always results in a (virtual) call + // to overflow. There is no disadvantage here for sputn since this always + // results in a call to xsputn. + + int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE { + if (!traits_type::eq_int_type(ch, traits_type::eof())) + buffer_.push_back(static_cast<Char>(ch)); + return ch; + } + + std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE { + buffer_.append(s, s + count); + return count; + } +}; + +template <typename Char> +struct test_stream : std::basic_ostream<Char> { + private: + struct null; + // Hide all operator<< from std::basic_ostream<Char>. + void operator<<(null); +}; + +// Checks if T has a user-defined operator<< (e.g. not a member of std::ostream). +template <typename T, typename Char> +class is_streamable { + private: + template <typename U> + static decltype( + internal::declval<test_stream<Char>&>() + << internal::declval<U>(), std::true_type()) test(int); + + template <typename> + static std::false_type test(...); + + typedef decltype(test<T>(0)) result; + + public: + static const bool value = result::value; +}; + +// Write the content of buf to os. +template <typename Char> +void write(std::basic_ostream<Char> &os, basic_buffer<Char> &buf) { + const Char *data = buf.data(); + typedef std::make_unsigned<std::streamsize>::type UnsignedStreamSize; + UnsignedStreamSize size = buf.size(); + UnsignedStreamSize max_size = + internal::to_unsigned((std::numeric_limits<std::streamsize>::max)()); + do { + UnsignedStreamSize n = size <= max_size ? size : max_size; + os.write(data, static_cast<std::streamsize>(n)); + data += n; + size -= n; + } while (size != 0); +} + +template <typename Char, typename T> +void format_value(basic_buffer<Char> &buffer, const T &value) { + internal::formatbuf<Char> format_buf(buffer); + std::basic_ostream<Char> output(&format_buf); + output.exceptions(std::ios_base::failbit | std::ios_base::badbit); + output << value; + buffer.resize(buffer.size()); +} +} // namespace internal + +// Disable conversion to int if T has an overloaded operator<< which is a free +// function (not a member of std::ostream). +template <typename T, typename Char> +struct convert_to_int<T, Char, void> { + static const bool value = + convert_to_int<T, Char, int>::value && + !internal::is_streamable<T, Char>::value; +}; + +// Formats an object of type T that has an overloaded ostream operator<<. +template <typename T, typename Char> +struct formatter<T, Char, + typename std::enable_if< + internal::is_streamable<T, Char>::value && + !internal::format_type< + typename buffer_context<Char>::type, T>::value>::type> + : formatter<basic_string_view<Char>, Char> { + + template <typename Context> + auto format(const T &value, Context &ctx) -> decltype(ctx.out()) { + basic_memory_buffer<Char> buffer; + internal::format_value(buffer, value); + basic_string_view<Char> str(buffer.data(), buffer.size()); + return formatter<basic_string_view<Char>, Char>::format(str, ctx); + } +}; + +template <typename Char> +inline void vprint(std::basic_ostream<Char> &os, + basic_string_view<Char> format_str, + basic_format_args<typename buffer_context<Char>::type> args) { + basic_memory_buffer<Char> buffer; + internal::vformat_to(buffer, format_str, args); + internal::write(os, buffer); +} +/** + \rst + Prints formatted data to the stream *os*. + + **Example**:: + + fmt::print(cerr, "Don't {}!", "panic"); + \endrst + */ +template <typename S, typename... Args> +inline typename std::enable_if<internal::is_string<S>::value>::type +print(std::basic_ostream<FMT_CHAR(S)> &os, const S &format_str, + const Args & ... args) { + internal::checked_args<S, Args...> ca(format_str, args...); + vprint(os, to_string_view(format_str), *ca); +} +FMT_END_NAMESPACE + +#endif // FMT_OSTREAM_H_ diff --git a/matching/include/spdlog/fmt/bundled/posix.h b/matching/include/spdlog/fmt/bundled/posix.h new file mode 100644 index 0000000..f4e3fad --- /dev/null +++ b/matching/include/spdlog/fmt/bundled/posix.h @@ -0,0 +1,324 @@ +// A C++ interface to POSIX functions. +// +// Copyright (c) 2012 - 2016, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_POSIX_H_ +#define FMT_POSIX_H_ + +#if defined(__MINGW32__) || defined(__CYGWIN__) +// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/. +# undef __STRICT_ANSI__ +#endif + +#include <errno.h> +#include <fcntl.h> // for O_RDONLY +#include <locale.h> // for locale_t +#include <stdio.h> +#include <stdlib.h> // for strtod_l + +#include <cstddef> + +#if defined __APPLE__ || defined(__FreeBSD__) +# include <xlocale.h> // for LC_NUMERIC_MASK on OS X +#endif + +#include "format.h" + +#ifndef FMT_POSIX +# if defined(_WIN32) && !defined(__MINGW32__) +// Fix warnings about deprecated symbols. +# define FMT_POSIX(call) _##call +# else +# define FMT_POSIX(call) call +# endif +#endif + +// Calls to system functions are wrapped in FMT_SYSTEM for testability. +#ifdef FMT_SYSTEM +# define FMT_POSIX_CALL(call) FMT_SYSTEM(call) +#else +# define FMT_SYSTEM(call) call +# ifdef _WIN32 +// Fix warnings about deprecated symbols. +# define FMT_POSIX_CALL(call) ::_##call +# else +# define FMT_POSIX_CALL(call) ::call +# endif +#endif + +// Retries the expression while it evaluates to error_result and errno +// equals to EINTR. +#ifndef _WIN32 +# define FMT_RETRY_VAL(result, expression, error_result) \ + do { \ + result = (expression); \ + } while (result == error_result && errno == EINTR) +#else +# define FMT_RETRY_VAL(result, expression, error_result) result = (expression) +#endif + +#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) + +FMT_BEGIN_NAMESPACE + +/** + \rst + A reference to a null-terminated string. It can be constructed from a C + string or ``std::string``. + + You can use one of the following typedefs for common character types: + + +---------------+-----------------------------+ + | Type | Definition | + +===============+=============================+ + | cstring_view | basic_cstring_view<char> | + +---------------+-----------------------------+ + | wcstring_view | basic_cstring_view<wchar_t> | + +---------------+-----------------------------+ + + This class is most useful as a parameter type to allow passing + different types of strings to a function, for example:: + + template <typename... Args> + std::string format(cstring_view format_str, const Args & ... args); + + format("{}", 42); + format(std::string("{}"), 42); + \endrst + */ +template <typename Char> +class basic_cstring_view { + private: + const Char *data_; + + public: + /** Constructs a string reference object from a C string. */ + basic_cstring_view(const Char *s) : data_(s) {} + + /** + \rst + Constructs a string reference from an ``std::string`` object. + \endrst + */ + basic_cstring_view(const std::basic_string<Char> &s) : data_(s.c_str()) {} + + /** Returns the pointer to a C string. */ + const Char *c_str() const { return data_; } +}; + +typedef basic_cstring_view<char> cstring_view; +typedef basic_cstring_view<wchar_t> wcstring_view; + +// An error code. +class error_code { + private: + int value_; + + public: + explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {} + + int get() const FMT_NOEXCEPT { return value_; } +}; + +// A buffered file. +class buffered_file { + private: + FILE *file_; + + friend class file; + + explicit buffered_file(FILE *f) : file_(f) {} + + public: + // Constructs a buffered_file object which doesn't represent any file. + buffered_file() FMT_NOEXCEPT : file_(FMT_NULL) {} + + // Destroys the object closing the file it represents if any. + FMT_API ~buffered_file() FMT_NOEXCEPT; + + private: + buffered_file(const buffered_file &) = delete; + void operator=(const buffered_file &) = delete; + + + public: + buffered_file(buffered_file &&other) FMT_NOEXCEPT : file_(other.file_) { + other.file_ = FMT_NULL; + } + + buffered_file& operator=(buffered_file &&other) { + close(); + file_ = other.file_; + other.file_ = FMT_NULL; + return *this; + } + + // Opens a file. + FMT_API buffered_file(cstring_view filename, cstring_view mode); + + // Closes the file. + FMT_API void close(); + + // Returns the pointer to a FILE object representing this file. + FILE *get() const FMT_NOEXCEPT { return file_; } + + // We place parentheses around fileno to workaround a bug in some versions + // of MinGW that define fileno as a macro. + FMT_API int (fileno)() const; + + void vprint(string_view format_str, format_args args) { + fmt::vprint(file_, format_str, args); + } + + template <typename... Args> + inline void print(string_view format_str, const Args & ... args) { + vprint(format_str, make_format_args(args...)); + } +}; + +// A file. Closed file is represented by a file object with descriptor -1. +// Methods that are not declared with FMT_NOEXCEPT may throw +// fmt::system_error in case of failure. Note that some errors such as +// closing the file multiple times will cause a crash on Windows rather +// than an exception. You can get standard behavior by overriding the +// invalid parameter handler with _set_invalid_parameter_handler. +class file { + private: + int fd_; // File descriptor. + + // Constructs a file object with a given descriptor. + explicit file(int fd) : fd_(fd) {} + + public: + // Possible values for the oflag argument to the constructor. + enum { + RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only. + WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only. + RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing. + }; + + // Constructs a file object which doesn't represent any file. + file() FMT_NOEXCEPT : fd_(-1) {} + + // Opens a file and constructs a file object representing this file. + FMT_API file(cstring_view path, int oflag); + + private: + file(const file &) = delete; + void operator=(const file &) = delete; + + public: + file(file &&other) FMT_NOEXCEPT : fd_(other.fd_) { + other.fd_ = -1; + } + + file& operator=(file &&other) { + close(); + fd_ = other.fd_; + other.fd_ = -1; + return *this; + } + + // Destroys the object closing the file it represents if any. + FMT_API ~file() FMT_NOEXCEPT; + + // Returns the file descriptor. + int descriptor() const FMT_NOEXCEPT { return fd_; } + + // Closes the file. + FMT_API void close(); + + // Returns the file size. The size has signed type for consistency with + // stat::st_size. + FMT_API long long size() const; + + // Attempts to read count bytes from the file into the specified buffer. + FMT_API std::size_t read(void *buffer, std::size_t count); + + // Attempts to write count bytes from the specified buffer to the file. + FMT_API std::size_t write(const void *buffer, std::size_t count); + + // Duplicates a file descriptor with the dup function and returns + // the duplicate as a file object. + FMT_API static file dup(int fd); + + // Makes fd be the copy of this file descriptor, closing fd first if + // necessary. + FMT_API void dup2(int fd); + + // Makes fd be the copy of this file descriptor, closing fd first if + // necessary. + FMT_API void dup2(int fd, error_code &ec) FMT_NOEXCEPT; + + // Creates a pipe setting up read_end and write_end file objects for reading + // and writing respectively. + FMT_API static void pipe(file &read_end, file &write_end); + + // Creates a buffered_file object associated with this file and detaches + // this file object from the file. + FMT_API buffered_file fdopen(const char *mode); +}; + +// Returns the memory page size. +long getpagesize(); + +#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \ + !defined(__ANDROID__) && !defined(__CYGWIN__) && !defined(__OpenBSD__) && \ + !defined(__NEWLIB_H__) +# define FMT_LOCALE +#endif + +#ifdef FMT_LOCALE +// A "C" numeric locale. +class Locale { + private: +# ifdef _MSC_VER + typedef _locale_t locale_t; + + enum { LC_NUMERIC_MASK = LC_NUMERIC }; + + static locale_t newlocale(int category_mask, const char *locale, locale_t) { + return _create_locale(category_mask, locale); + } + + static void freelocale(locale_t locale) { + _free_locale(locale); + } + + static double strtod_l(const char *nptr, char **endptr, _locale_t locale) { + return _strtod_l(nptr, endptr, locale); + } +# endif + + locale_t locale_; + + Locale(const Locale &) = delete; + void operator=(const Locale &) = delete; + + public: + typedef locale_t Type; + + Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) { + if (!locale_) + FMT_THROW(system_error(errno, "cannot create locale")); + } + ~Locale() { freelocale(locale_); } + + Type get() const { return locale_; } + + // Converts string to floating-point number and advances str past the end + // of the parsed input. + double strtod(const char *&str) const { + char *end = FMT_NULL; + double result = strtod_l(str, &end, locale_); + str = end; + return result; + } +}; +#endif // FMT_LOCALE +FMT_END_NAMESPACE + +#endif // FMT_POSIX_H_ diff --git a/matching/include/spdlog/fmt/bundled/printf.h b/matching/include/spdlog/fmt/bundled/printf.h new file mode 100644 index 0000000..6f2715d --- /dev/null +++ b/matching/include/spdlog/fmt/bundled/printf.h @@ -0,0 +1,855 @@ +// Formatting library for C++ +// +// Copyright (c) 2012 - 2016, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_PRINTF_H_ +#define FMT_PRINTF_H_ + +#include <algorithm> // std::fill_n +#include <limits> // std::numeric_limits + +#include "ostream.h" + +FMT_BEGIN_NAMESPACE +namespace internal { + +// An iterator that produces a null terminator on *end. This simplifies parsing +// and allows comparing the performance of processing a null-terminated string +// vs string_view. +template <typename Char> +class null_terminating_iterator { + public: + typedef std::ptrdiff_t difference_type; + typedef Char value_type; + typedef const Char* pointer; + typedef const Char& reference; + typedef std::random_access_iterator_tag iterator_category; + + null_terminating_iterator() : ptr_(0), end_(0) {} + + FMT_CONSTEXPR null_terminating_iterator(const Char *ptr, const Char *end) + : ptr_(ptr), end_(end) {} + + template <typename Range> + FMT_CONSTEXPR explicit null_terminating_iterator(const Range &r) + : ptr_(r.begin()), end_(r.end()) {} + + FMT_CONSTEXPR null_terminating_iterator &operator=(const Char *ptr) { + assert(ptr <= end_); + ptr_ = ptr; + return *this; + } + + FMT_CONSTEXPR Char operator*() const { + return ptr_ != end_ ? *ptr_ : Char(); + } + + FMT_CONSTEXPR null_terminating_iterator operator++() { + ++ptr_; + return *this; + } + + FMT_CONSTEXPR null_terminating_iterator operator++(int) { + null_terminating_iterator result(*this); + ++ptr_; + return result; + } + + FMT_CONSTEXPR null_terminating_iterator operator--() { + --ptr_; + return *this; + } + + FMT_CONSTEXPR null_terminating_iterator operator+(difference_type n) { + return null_terminating_iterator(ptr_ + n, end_); + } + + FMT_CONSTEXPR null_terminating_iterator operator-(difference_type n) { + return null_terminating_iterator(ptr_ - n, end_); + } + + FMT_CONSTEXPR null_terminating_iterator operator+=(difference_type n) { + ptr_ += n; + return *this; + } + + FMT_CONSTEXPR difference_type operator-( + null_terminating_iterator other) const { + return ptr_ - other.ptr_; + } + + FMT_CONSTEXPR bool operator!=(null_terminating_iterator other) const { + return ptr_ != other.ptr_; + } + + bool operator>=(null_terminating_iterator other) const { + return ptr_ >= other.ptr_; + } + + // This should be a friend specialization pointer_from<Char> but the latter + // doesn't compile by gcc 5.1 due to a compiler bug. + template <typename CharT> + friend FMT_CONSTEXPR_DECL const CharT *pointer_from( + null_terminating_iterator<CharT> it); + + private: + const Char *ptr_; + const Char *end_; +}; + +template <typename T> +FMT_CONSTEXPR const T *pointer_from(const T *p) { return p; } + +template <typename Char> +FMT_CONSTEXPR const Char *pointer_from(null_terminating_iterator<Char> it) { + return it.ptr_; +} + +// DEPRECATED: Parses the input as an unsigned integer. This function assumes +// that the first character is a digit and presence of a non-digit character at +// the end. +// it: an iterator pointing to the beginning of the input range. +template <typename Iterator, typename ErrorHandler> +FMT_CONSTEXPR unsigned parse_nonnegative_int(Iterator &it, ErrorHandler &&eh) { + assert('0' <= *it && *it <= '9'); + if (*it == '0') { + ++it; + return 0; + } + unsigned value = 0; + // Convert to unsigned to prevent a warning. + unsigned max_int = (std::numeric_limits<int>::max)(); + unsigned big = max_int / 10; + do { + // Check for overflow. + if (value > big) { + value = max_int + 1; + break; + } + value = value * 10 + unsigned(*it - '0'); + // Workaround for MSVC "setup_exception stack overflow" error: + auto next = it; + ++next; + it = next; + } while ('0' <= *it && *it <= '9'); + if (value > max_int) + eh.on_error("number is too big"); + return value; +} + +// Checks if a value fits in int - used to avoid warnings about comparing +// signed and unsigned integers. +template <bool IsSigned> +struct int_checker { + template <typename T> + static bool fits_in_int(T value) { + unsigned max = std::numeric_limits<int>::max(); + return value <= max; + } + static bool fits_in_int(bool) { return true; } +}; + +template <> +struct int_checker<true> { + template <typename T> + static bool fits_in_int(T value) { + return value >= std::numeric_limits<int>::min() && + value <= std::numeric_limits<int>::max(); + } + static bool fits_in_int(int) { return true; } +}; + +class printf_precision_handler: public function<int> { + public: + template <typename T> + typename std::enable_if<std::is_integral<T>::value, int>::type + operator()(T value) { + if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value)) + FMT_THROW(format_error("number is too big")); + return static_cast<int>(value); + } + + template <typename T> + typename std::enable_if<!std::is_integral<T>::value, int>::type operator()(T) { + FMT_THROW(format_error("precision is not integer")); + return 0; + } +}; + +// An argument visitor that returns true iff arg is a zero integer. +class is_zero_int: public function<bool> { + public: + template <typename T> + typename std::enable_if<std::is_integral<T>::value, bool>::type + operator()(T value) { return value == 0; } + + template <typename T> + typename std::enable_if<!std::is_integral<T>::value, bool>::type + operator()(T) { return false; } +}; + +template <typename T> +struct make_unsigned_or_bool : std::make_unsigned<T> {}; + +template <> +struct make_unsigned_or_bool<bool> { + typedef bool type; +}; + +template <typename T, typename Context> +class arg_converter: public function<void> { + private: + typedef typename Context::char_type Char; + + basic_format_arg<Context> &arg_; + typename Context::char_type type_; + + public: + arg_converter(basic_format_arg<Context> &arg, Char type) + : arg_(arg), type_(type) {} + + void operator()(bool value) { + if (type_ != 's') + operator()<bool>(value); + } + + template <typename U> + typename std::enable_if<std::is_integral<U>::value>::type + operator()(U value) { + bool is_signed = type_ == 'd' || type_ == 'i'; + typedef typename std::conditional< + std::is_same<T, void>::value, U, T>::type TargetType; + if (const_check(sizeof(TargetType) <= sizeof(int))) { + // Extra casts are used to silence warnings. + if (is_signed) { + arg_ = internal::make_arg<Context>( + static_cast<int>(static_cast<TargetType>(value))); + } else { + typedef typename make_unsigned_or_bool<TargetType>::type Unsigned; + arg_ = internal::make_arg<Context>( + static_cast<unsigned>(static_cast<Unsigned>(value))); + } + } else { + if (is_signed) { + // glibc's printf doesn't sign extend arguments of smaller types: + // std::printf("%lld", -42); // prints "4294967254" + // but we don't have to do the same because it's a UB. + arg_ = internal::make_arg<Context>(static_cast<long long>(value)); + } else { + arg_ = internal::make_arg<Context>( + static_cast<typename make_unsigned_or_bool<U>::type>(value)); + } + } + } + + template <typename U> + typename std::enable_if<!std::is_integral<U>::value>::type operator()(U) { + // No coversion needed for non-integral types. + } +}; + +// Converts an integer argument to T for printf, if T is an integral type. +// If T is void, the argument is converted to corresponding signed or unsigned +// type depending on the type specifier: 'd' and 'i' - signed, other - +// unsigned). +template <typename T, typename Context, typename Char> +void convert_arg(basic_format_arg<Context> &arg, Char type) { + visit_format_arg(arg_converter<T, Context>(arg, type), arg); +} + +// Converts an integer argument to char for printf. +template <typename Context> +class char_converter: public function<void> { + private: + basic_format_arg<Context> &arg_; + + public: + explicit char_converter(basic_format_arg<Context> &arg) : arg_(arg) {} + + template <typename T> + typename std::enable_if<std::is_integral<T>::value>::type + operator()(T value) { + typedef typename Context::char_type Char; + arg_ = internal::make_arg<Context>(static_cast<Char>(value)); + } + + template <typename T> + typename std::enable_if<!std::is_integral<T>::value>::type operator()(T) { + // No coversion needed for non-integral types. + } +}; + +// Checks if an argument is a valid printf width specifier and sets +// left alignment if it is negative. +template <typename Char> +class printf_width_handler: public function<unsigned> { + private: + typedef basic_format_specs<Char> format_specs; + + format_specs &spec_; + + public: + explicit printf_width_handler(format_specs &spec) : spec_(spec) {} + + template <typename T> + typename std::enable_if<std::is_integral<T>::value, unsigned>::type + operator()(T value) { + typedef typename internal::int_traits<T>::main_type UnsignedType; + UnsignedType width = static_cast<UnsignedType>(value); + if (internal::is_negative(value)) { + spec_.align_ = ALIGN_LEFT; + width = 0 - width; + } + unsigned int_max = std::numeric_limits<int>::max(); + if (width > int_max) + FMT_THROW(format_error("number is too big")); + return static_cast<unsigned>(width); + } + + template <typename T> + typename std::enable_if<!std::is_integral<T>::value, unsigned>::type + operator()(T) { + FMT_THROW(format_error("width is not integer")); + return 0; + } +}; + +template <typename Char, typename Context> +void printf(basic_buffer<Char> &buf, basic_string_view<Char> format, + basic_format_args<Context> args) { + Context(std::back_inserter(buf), format, args).format(); +} +} // namespace internal + +using internal::printf; // For printing into memory_buffer. + +template <typename Range> +class printf_arg_formatter; + +template < + typename OutputIt, typename Char, + typename ArgFormatter = + printf_arg_formatter<back_insert_range<internal::basic_buffer<Char>>>> +class basic_printf_context; + +/** + \rst + The ``printf`` argument formatter. + \endrst + */ +template <typename Range> +class printf_arg_formatter: + public internal::function< + typename internal::arg_formatter_base<Range>::iterator>, + public internal::arg_formatter_base<Range> { + private: + typedef typename Range::value_type char_type; + typedef decltype(internal::declval<Range>().begin()) iterator; + typedef internal::arg_formatter_base<Range> base; + typedef basic_printf_context<iterator, char_type> context_type; + + context_type &context_; + + void write_null_pointer(char) { + this->spec()->type = 0; + this->write("(nil)"); + } + + void write_null_pointer(wchar_t) { + this->spec()->type = 0; + this->write(L"(nil)"); + } + + public: + typedef typename base::format_specs format_specs; + + /** + \rst + Constructs an argument formatter object. + *buffer* is a reference to the output buffer and *spec* contains format + specifier information for standard argument types. + \endrst + */ + printf_arg_formatter(internal::basic_buffer<char_type> &buffer, + format_specs &spec, context_type &ctx) + : base(back_insert_range<internal::basic_buffer<char_type>>(buffer), &spec, + ctx.locale()), + context_(ctx) {} + + template <typename T> + typename std::enable_if<std::is_integral<T>::value, iterator>::type + operator()(T value) { + // MSVC2013 fails to compile separate overloads for bool and char_type so + // use std::is_same instead. + if (std::is_same<T, bool>::value) { + format_specs &fmt_spec = *this->spec(); + if (fmt_spec.type != 's') + return base::operator()(value ? 1 : 0); + fmt_spec.type = 0; + this->write(value != 0); + } else if (std::is_same<T, char_type>::value) { + format_specs &fmt_spec = *this->spec(); + if (fmt_spec.type && fmt_spec.type != 'c') + return (*this)(static_cast<int>(value)); + fmt_spec.flags = 0; + fmt_spec.align_ = ALIGN_RIGHT; + return base::operator()(value); + } else { + return base::operator()(value); + } + return this->out(); + } + + template <typename T> + typename std::enable_if<std::is_floating_point<T>::value, iterator>::type + operator()(T value) { + return base::operator()(value); + } + + /** Formats a null-terminated C string. */ + iterator operator()(const char *value) { + if (value) + base::operator()(value); + else if (this->spec()->type == 'p') + write_null_pointer(char_type()); + else + this->write("(null)"); + return this->out(); + } + + /** Formats a null-terminated wide C string. */ + iterator operator()(const wchar_t *value) { + if (value) + base::operator()(value); + else if (this->spec()->type == 'p') + write_null_pointer(char_type()); + else + this->write(L"(null)"); + return this->out(); + } + + iterator operator()(basic_string_view<char_type> value) { + return base::operator()(value); + } + + iterator operator()(monostate value) { + return base::operator()(value); + } + + /** Formats a pointer. */ + iterator operator()(const void *value) { + if (value) + return base::operator()(value); + this->spec()->type = 0; + write_null_pointer(char_type()); + return this->out(); + } + + /** Formats an argument of a custom (user-defined) type. */ + iterator operator()(typename basic_format_arg<context_type>::handle handle) { + handle.format(context_); + return this->out(); + } +}; + +template <typename T> +struct printf_formatter { + template <typename ParseContext> + auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { return ctx.begin(); } + + template <typename FormatContext> + auto format(const T &value, FormatContext &ctx) -> decltype(ctx.out()) { + internal::format_value(internal::get_container(ctx.out()), value); + return ctx.out(); + } +}; + +/** This template formats data and writes the output to a writer. */ +template <typename OutputIt, typename Char, typename ArgFormatter> +class basic_printf_context : + // Inherit publicly as a workaround for the icc bug + // https://software.intel.com/en-us/forums/intel-c-compiler/topic/783476. + public internal::context_base< + OutputIt, basic_printf_context<OutputIt, Char, ArgFormatter>, Char> { + public: + /** The character type for the output. */ + typedef Char char_type; + + template <typename T> + struct formatter_type { typedef printf_formatter<T> type; }; + + private: + typedef internal::context_base<OutputIt, basic_printf_context, Char> base; + typedef typename base::format_arg format_arg; + typedef basic_format_specs<char_type> format_specs; + typedef internal::null_terminating_iterator<char_type> iterator; + + void parse_flags(format_specs &spec, iterator &it); + + // Returns the argument with specified index or, if arg_index is equal + // to the maximum unsigned value, the next argument. + format_arg get_arg( + iterator it, + unsigned arg_index = (std::numeric_limits<unsigned>::max)()); + + // Parses argument index, flags and width and returns the argument index. + unsigned parse_header(iterator &it, format_specs &spec); + + public: + /** + \rst + Constructs a ``printf_context`` object. References to the arguments and + the writer are stored in the context object so make sure they have + appropriate lifetimes. + \endrst + */ + basic_printf_context(OutputIt out, basic_string_view<char_type> format_str, + basic_format_args<basic_printf_context> args) + : base(out, format_str, args) {} + + using base::parse_context; + using base::out; + using base::advance_to; + + /** Formats stored arguments and writes the output to the range. */ + void format(); +}; + +template <typename OutputIt, typename Char, typename AF> +void basic_printf_context<OutputIt, Char, AF>::parse_flags( + format_specs &spec, iterator &it) { + for (;;) { + switch (*it++) { + case '-': + spec.align_ = ALIGN_LEFT; + break; + case '+': + spec.flags |= SIGN_FLAG | PLUS_FLAG; + break; + case '0': + spec.fill_ = '0'; + break; + case ' ': + spec.flags |= SIGN_FLAG; + break; + case '#': + spec.flags |= HASH_FLAG; + break; + default: + --it; + return; + } + } +} + +template <typename OutputIt, typename Char, typename AF> +typename basic_printf_context<OutputIt, Char, AF>::format_arg + basic_printf_context<OutputIt, Char, AF>::get_arg( + iterator it, unsigned arg_index) { + (void)it; + if (arg_index == std::numeric_limits<unsigned>::max()) + return this->do_get_arg(this->parse_context().next_arg_id()); + return base::get_arg(arg_index - 1); +} + +template <typename OutputIt, typename Char, typename AF> +unsigned basic_printf_context<OutputIt, Char, AF>::parse_header( + iterator &it, format_specs &spec) { + unsigned arg_index = std::numeric_limits<unsigned>::max(); + char_type c = *it; + if (c >= '0' && c <= '9') { + // Parse an argument index (if followed by '$') or a width possibly + // preceded with '0' flag(s). + internal::error_handler eh; + unsigned value = parse_nonnegative_int(it, eh); + if (*it == '$') { // value is an argument index + ++it; + arg_index = value; + } else { + if (c == '0') + spec.fill_ = '0'; + if (value != 0) { + // Nonzero value means that we parsed width and don't need to + // parse it or flags again, so return now. + spec.width_ = value; + return arg_index; + } + } + } + parse_flags(spec, it); + // Parse width. + if (*it >= '0' && *it <= '9') { + internal::error_handler eh; + spec.width_ = parse_nonnegative_int(it, eh); + } else if (*it == '*') { + ++it; + spec.width_ = visit_format_arg( + internal::printf_width_handler<char_type>(spec), get_arg(it)); + } + return arg_index; +} + +template <typename OutputIt, typename Char, typename AF> +void basic_printf_context<OutputIt, Char, AF>::format() { + auto &buffer = internal::get_container(this->out()); + auto start = iterator(this->parse_context()); + auto it = start; + using internal::pointer_from; + while (*it) { + char_type c = *it++; + if (c != '%') continue; + if (*it == c) { + buffer.append(pointer_from(start), pointer_from(it)); + start = ++it; + continue; + } + buffer.append(pointer_from(start), pointer_from(it) - 1); + + format_specs spec; + spec.align_ = ALIGN_RIGHT; + + // Parse argument index, flags and width. + unsigned arg_index = parse_header(it, spec); + + // Parse precision. + if (*it == '.') { + ++it; + if ('0' <= *it && *it <= '9') { + internal::error_handler eh; + spec.precision = static_cast<int>(parse_nonnegative_int(it, eh)); + } else if (*it == '*') { + ++it; + spec.precision = + visit_format_arg(internal::printf_precision_handler(), get_arg(it)); + } else { + spec.precision = 0; + } + } + + format_arg arg = get_arg(it, arg_index); + if (spec.has(HASH_FLAG) && visit_format_arg(internal::is_zero_int(), arg)) + spec.flags = static_cast<uint_least8_t>(spec.flags & (~internal::to_unsigned<int>(HASH_FLAG))); + if (spec.fill_ == '0') { + if (arg.is_arithmetic()) + spec.align_ = ALIGN_NUMERIC; + else + spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. + } + + // Parse length and convert the argument to the required type. + using internal::convert_arg; + switch (*it++) { + case 'h': + if (*it == 'h') + convert_arg<signed char>(arg, *++it); + else + convert_arg<short>(arg, *it); + break; + case 'l': + if (*it == 'l') + convert_arg<long long>(arg, *++it); + else + convert_arg<long>(arg, *it); + break; + case 'j': + convert_arg<intmax_t>(arg, *it); + break; + case 'z': + convert_arg<std::size_t>(arg, *it); + break; + case 't': + convert_arg<std::ptrdiff_t>(arg, *it); + break; + case 'L': + // printf produces garbage when 'L' is omitted for long double, no + // need to do the same. + break; + default: + --it; + convert_arg<void>(arg, *it); + } + + // Parse type. + if (!*it) + FMT_THROW(format_error("invalid format string")); + spec.type = static_cast<char>(*it++); + if (arg.is_integral()) { + // Normalize type. + switch (spec.type) { + case 'i': case 'u': + spec.type = 'd'; + break; + case 'c': + // TODO: handle wchar_t better? + visit_format_arg( + internal::char_converter<basic_printf_context>(arg), arg); + break; + } + } + + start = it; + + // Format argument. + visit_format_arg(AF(buffer, spec, *this), arg); + } + buffer.append(pointer_from(start), pointer_from(it)); +} + +template <typename Buffer> +struct basic_printf_context_t { + typedef basic_printf_context< + std::back_insert_iterator<Buffer>, typename Buffer::value_type> type; +}; + +typedef basic_printf_context_t<internal::buffer>::type printf_context; +typedef basic_printf_context_t<internal::wbuffer>::type wprintf_context; + +typedef basic_format_args<printf_context> printf_args; +typedef basic_format_args<wprintf_context> wprintf_args; + +/** + \rst + Constructs an `~fmt::format_arg_store` object that contains references to + arguments and can be implicitly converted to `~fmt::printf_args`. + \endrst + */ +template<typename... Args> +inline format_arg_store<printf_context, Args...> + make_printf_args(const Args &... args) { return {args...}; } + +/** + \rst + Constructs an `~fmt::format_arg_store` object that contains references to + arguments and can be implicitly converted to `~fmt::wprintf_args`. + \endrst + */ +template<typename... Args> +inline format_arg_store<wprintf_context, Args...> + make_wprintf_args(const Args &... args) { return {args...}; } + +template <typename S, typename Char = FMT_CHAR(S)> +inline std::basic_string<Char> +vsprintf(const S &format, + basic_format_args<typename basic_printf_context_t< + internal::basic_buffer<Char>>::type> args) { + basic_memory_buffer<Char> buffer; + printf(buffer, to_string_view(format), args); + return to_string(buffer); +} + +/** + \rst + Formats arguments and returns the result as a string. + + **Example**:: + + std::string message = fmt::sprintf("The answer is %d", 42); + \endrst +*/ +template <typename S, typename... Args> +inline FMT_ENABLE_IF_T( + internal::is_string<S>::value, std::basic_string<FMT_CHAR(S)>) + sprintf(const S &format, const Args & ... args) { + internal::check_format_string<Args...>(format); + typedef internal::basic_buffer<FMT_CHAR(S)> buffer; + typedef typename basic_printf_context_t<buffer>::type context; + format_arg_store<context, Args...> as{ args... }; + return vsprintf(to_string_view(format), + basic_format_args<context>(as)); +} + +template <typename S, typename Char = FMT_CHAR(S)> +inline int vfprintf(std::FILE *f, const S &format, + basic_format_args<typename basic_printf_context_t< + internal::basic_buffer<Char>>::type> args) { + basic_memory_buffer<Char> buffer; + printf(buffer, to_string_view(format), args); + std::size_t size = buffer.size(); + return std::fwrite( + buffer.data(), sizeof(Char), size, f) < size ? -1 : static_cast<int>(size); +} + +/** + \rst + Prints formatted data to the file *f*. + + **Example**:: + + fmt::fprintf(stderr, "Don't %s!", "panic"); + \endrst + */ +template <typename S, typename... Args> +inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int) + fprintf(std::FILE *f, const S &format, const Args & ... args) { + internal::check_format_string<Args...>(format); + typedef internal::basic_buffer<FMT_CHAR(S)> buffer; + typedef typename basic_printf_context_t<buffer>::type context; + format_arg_store<context, Args...> as{ args... }; + return vfprintf(f, to_string_view(format), + basic_format_args<context>(as)); +} + +template <typename S, typename Char = FMT_CHAR(S)> +inline int vprintf(const S &format, + basic_format_args<typename basic_printf_context_t< + internal::basic_buffer<Char>>::type> args) { + return vfprintf(stdout, to_string_view(format), args); +} + +/** + \rst + Prints formatted data to ``stdout``. + + **Example**:: + + fmt::printf("Elapsed time: %.2f seconds", 1.23); + \endrst + */ +template <typename S, typename... Args> +inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int) + printf(const S &format_str, const Args & ... args) { + internal::check_format_string<Args...>(format_str); + typedef internal::basic_buffer<FMT_CHAR(S)> buffer; + typedef typename basic_printf_context_t<buffer>::type context; + format_arg_store<context, Args...> as{ args... }; + return vprintf(to_string_view(format_str), + basic_format_args<context>(as)); +} + +template <typename S, typename Char = FMT_CHAR(S)> +inline int vfprintf(std::basic_ostream<Char> &os, + const S &format, + basic_format_args<typename basic_printf_context_t< + internal::basic_buffer<Char>>::type> args) { + basic_memory_buffer<Char> buffer; + printf(buffer, to_string_view(format), args); + internal::write(os, buffer); + return static_cast<int>(buffer.size()); +} + +/** + \rst + Prints formatted data to the stream *os*. + + **Example**:: + + fmt::fprintf(cerr, "Don't %s!", "panic"); + \endrst + */ +template <typename S, typename... Args> +inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int) + fprintf(std::basic_ostream<FMT_CHAR(S)> &os, + const S &format_str, const Args & ... args) { + internal::check_format_string<Args...>(format_str); + typedef internal::basic_buffer<FMT_CHAR(S)> buffer; + typedef typename basic_printf_context_t<buffer>::type context; + format_arg_store<context, Args...> as{ args... }; + return vfprintf(os, to_string_view(format_str), + basic_format_args<context>(as)); +} +FMT_END_NAMESPACE + +#endif // FMT_PRINTF_H_ diff --git a/matching/include/spdlog/fmt/bundled/ranges.h b/matching/include/spdlog/fmt/bundled/ranges.h new file mode 100644 index 0000000..3672d4c --- /dev/null +++ b/matching/include/spdlog/fmt/bundled/ranges.h @@ -0,0 +1,308 @@ +// Formatting library for C++ - the core API +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. +// +// Copyright (c) 2018 - present, Remotion (Igor Schulz) +// All Rights Reserved +// {fmt} support for ranges, containers and types tuple interface. + +#ifndef FMT_RANGES_H_ +#define FMT_RANGES_H_ + +#include "format.h" +#include <type_traits> + +// output only up to N items from the range. +#ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT +# define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256 +#endif + +FMT_BEGIN_NAMESPACE + +template <typename Char> +struct formatting_base { + template <typename ParseContext> + FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } +}; + +template <typename Char, typename Enable = void> +struct formatting_range : formatting_base<Char> { + static FMT_CONSTEXPR_DECL const std::size_t range_length_limit = + FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the range. + Char prefix; + Char delimiter; + Char postfix; + formatting_range() : prefix('{'), delimiter(','), postfix('}') {} + static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true; + static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false; +}; + +template <typename Char, typename Enable = void> +struct formatting_tuple : formatting_base<Char> { + Char prefix; + Char delimiter; + Char postfix; + formatting_tuple() : prefix('('), delimiter(','), postfix(')') {} + static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true; + static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false; +}; + +namespace internal { + +template <typename RangeT, typename OutputIterator> +void copy(const RangeT &range, OutputIterator out) { + for (auto it = range.begin(), end = range.end(); it != end; ++it) + *out++ = *it; +} + +template <typename OutputIterator> +void copy(const char *str, OutputIterator out) { + const char *p_curr = str; + while (*p_curr) { + *out++ = *p_curr++; + } +} + +template <typename OutputIterator> +void copy(char ch, OutputIterator out) { + *out++ = ch; +} + +/// Return true value if T has std::string interface, like std::string_view. +template <typename T> +class is_like_std_string { + template <typename U> + static auto check(U *p) -> + decltype(p->find('a'), p->length(), p->data(), int()); + template <typename> + static void check(...); + + public: + static FMT_CONSTEXPR_DECL const bool value = + !std::is_void<decltype(check<T>(FMT_NULL))>::value; +}; + +template <typename Char> +struct is_like_std_string<fmt::basic_string_view<Char>> : std::true_type {}; + +template <typename... Ts> +struct conditional_helper {}; + +template <typename T, typename _ = void> +struct is_range_ : std::false_type {}; + +#if !FMT_MSC_VER || FMT_MSC_VER > 1800 +template <typename T> +struct is_range_<T, typename std::conditional< + false, + conditional_helper<decltype(internal::declval<T>().begin()), + decltype(internal::declval<T>().end())>, + void>::type> : std::true_type {}; +#endif + +/// tuple_size and tuple_element check. +template <typename T> +class is_tuple_like_ { + template <typename U> + static auto check(U *p) -> + decltype(std::tuple_size<U>::value, + internal::declval<typename std::tuple_element<0, U>::type>(), int()); + template <typename> + static void check(...); + + public: + static FMT_CONSTEXPR_DECL const bool value = + !std::is_void<decltype(check<T>(FMT_NULL))>::value; +}; + +// Check for integer_sequence +#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900 +template <typename T, T... N> +using integer_sequence = std::integer_sequence<T, N...>; +template <std::size_t... N> +using index_sequence = std::index_sequence<N...>; +template <std::size_t N> +using make_index_sequence = std::make_index_sequence<N>; +#else +template <typename T, T... N> +struct integer_sequence { + typedef T value_type; + + static FMT_CONSTEXPR std::size_t size() { + return sizeof...(N); + } +}; + +template <std::size_t... N> +using index_sequence = integer_sequence<std::size_t, N...>; + +template <typename T, std::size_t N, T... Ns> +struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {}; +template <typename T, T... Ns> +struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {}; + +template <std::size_t N> +using make_index_sequence = make_integer_sequence<std::size_t, N>; +#endif + +template <class Tuple, class F, size_t... Is> +void for_each(index_sequence<Is...>, Tuple &&tup, F &&f) FMT_NOEXCEPT { + using std::get; + // using free function get<I>(T) now. + const int _[] = {0, ((void)f(get<Is>(tup)), 0)...}; + (void)_; // blocks warnings +} + +template <class T> +FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> +get_indexes(T const &) { return {}; } + +template <class Tuple, class F> +void for_each(Tuple &&tup, F &&f) { + const auto indexes = get_indexes(tup); + for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f)); +} + +template<typename Arg> +FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&, + typename std::enable_if< + !is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) { + return add_space ? " {}" : "{}"; +} + +template<typename Arg> +FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&, + typename std::enable_if< + is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) { + return add_space ? " \"{}\"" : "\"{}\""; +} + +FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char*) { + return add_space ? " \"{}\"" : "\"{}\""; +} +FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t*) { + return add_space ? L" \"{}\"" : L"\"{}\""; +} + +FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) { + return add_space ? " '{}'" : "'{}'"; +} +FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) { + return add_space ? L" '{}'" : L"'{}'"; +} + +} // namespace internal + +template <typename T> +struct is_tuple_like { + static FMT_CONSTEXPR_DECL const bool value = + internal::is_tuple_like_<T>::value && !internal::is_range_<T>::value; +}; + +template <typename TupleT, typename Char> +struct formatter<TupleT, Char, + typename std::enable_if<fmt::is_tuple_like<TupleT>::value>::type> { +private: + // C++11 generic lambda for format() + template <typename FormatContext> + struct format_each { + template <typename T> + void operator()(const T& v) { + if (i > 0) { + if (formatting.add_prepostfix_space) { + *out++ = ' '; + } + internal::copy(formatting.delimiter, out); + } + format_to(out, + internal::format_str_quoted( + (formatting.add_delimiter_spaces && i > 0), v), + v); + ++i; + } + + formatting_tuple<Char>& formatting; + std::size_t& i; + typename std::add_lvalue_reference<decltype(std::declval<FormatContext>().out())>::type out; + }; + +public: + formatting_tuple<Char> formatting; + + template <typename ParseContext> + FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + return formatting.parse(ctx); + } + + template <typename FormatContext = format_context> + auto format(const TupleT &values, FormatContext &ctx) -> decltype(ctx.out()) { + auto out = ctx.out(); + std::size_t i = 0; + internal::copy(formatting.prefix, out); + + internal::for_each(values, format_each<FormatContext>{formatting, i, out}); + if (formatting.add_prepostfix_space) { + *out++ = ' '; + } + internal::copy(formatting.postfix, out); + + return ctx.out(); + } +}; + +template <typename T> +struct is_range { + static FMT_CONSTEXPR_DECL const bool value = + internal::is_range_<T>::value && !internal::is_like_std_string<T>::value; +}; + +template <typename RangeT, typename Char> +struct formatter<RangeT, Char, + typename std::enable_if<fmt::is_range<RangeT>::value>::type> { + + formatting_range<Char> formatting; + + template <typename ParseContext> + FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + return formatting.parse(ctx); + } + + template <typename FormatContext> + typename FormatContext::iterator format( + const RangeT &values, FormatContext &ctx) { + auto out = ctx.out(); + internal::copy(formatting.prefix, out); + std::size_t i = 0; + for (auto it = values.begin(), end = values.end(); it != end; ++it) { + if (i > 0) { + if (formatting.add_prepostfix_space) { + *out++ = ' '; + } + internal::copy(formatting.delimiter, out); + } + format_to(out, + internal::format_str_quoted( + (formatting.add_delimiter_spaces && i > 0), *it), + *it); + if (++i > formatting.range_length_limit) { + format_to(out, " ... <other elements>"); + break; + } + } + if (formatting.add_prepostfix_space) { + *out++ = ' '; + } + internal::copy(formatting.postfix, out); + return ctx.out(); + } +}; + +FMT_END_NAMESPACE + +#endif // FMT_RANGES_H_ + diff --git a/matching/include/spdlog/fmt/bundled/time.h b/matching/include/spdlog/fmt/bundled/time.h new file mode 100644 index 0000000..fe79891 --- /dev/null +++ b/matching/include/spdlog/fmt/bundled/time.h @@ -0,0 +1,160 @@ +// Formatting library for C++ - time formatting +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_TIME_H_ +#define FMT_TIME_H_ + +#include "format.h" +#include <ctime> +#include <locale> + +FMT_BEGIN_NAMESPACE + +// Prevents expansion of a preceding token as a function-style macro. +// Usage: f FMT_NOMACRO() +#define FMT_NOMACRO + +namespace internal{ +inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); } +inline null<> localtime_s(...) { return null<>(); } +inline null<> gmtime_r(...) { return null<>(); } +inline null<> gmtime_s(...) { return null<>(); } +} // namespace internal + +// Thread-safe replacement for std::localtime +inline std::tm localtime(std::time_t time) { + struct dispatcher { + std::time_t time_; + std::tm tm_; + + dispatcher(std::time_t t): time_(t) {} + + bool run() { + using namespace fmt::internal; + return handle(localtime_r(&time_, &tm_)); + } + + bool handle(std::tm *tm) { return tm != FMT_NULL; } + + bool handle(internal::null<>) { + using namespace fmt::internal; + return fallback(localtime_s(&tm_, &time_)); + } + + bool fallback(int res) { return res == 0; } + +#if !FMT_MSC_VER + bool fallback(internal::null<>) { + using namespace fmt::internal; + std::tm *tm = std::localtime(&time_); + if (tm) tm_ = *tm; + return tm != FMT_NULL; + } +#endif + }; + dispatcher lt(time); + // Too big time values may be unsupported. + if (!lt.run()) + FMT_THROW(format_error("time_t value out of range")); + return lt.tm_; +} + +// Thread-safe replacement for std::gmtime +inline std::tm gmtime(std::time_t time) { + struct dispatcher { + std::time_t time_; + std::tm tm_; + + dispatcher(std::time_t t): time_(t) {} + + bool run() { + using namespace fmt::internal; + return handle(gmtime_r(&time_, &tm_)); + } + + bool handle(std::tm *tm) { return tm != FMT_NULL; } + + bool handle(internal::null<>) { + using namespace fmt::internal; + return fallback(gmtime_s(&tm_, &time_)); + } + + bool fallback(int res) { return res == 0; } + +#if !FMT_MSC_VER + bool fallback(internal::null<>) { + std::tm *tm = std::gmtime(&time_); + if (tm) tm_ = *tm; + return tm != FMT_NULL; + } +#endif + }; + dispatcher gt(time); + // Too big time values may be unsupported. + if (!gt.run()) + FMT_THROW(format_error("time_t value out of range")); + return gt.tm_; +} + +namespace internal { +inline std::size_t strftime(char *str, std::size_t count, const char *format, + const std::tm *time) { + return std::strftime(str, count, format, time); +} + +inline std::size_t strftime(wchar_t *str, std::size_t count, + const wchar_t *format, const std::tm *time) { + return std::wcsftime(str, count, format, time); +} +} + +template <typename Char> +struct formatter<std::tm, Char> { + template <typename ParseContext> + auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + auto it = ctx.begin(); + if (it != ctx.end() && *it == ':') + ++it; + auto end = it; + while (end != ctx.end() && *end != '}') + ++end; + tm_format.reserve(internal::to_unsigned(end - it + 1)); + tm_format.append(it, end); + tm_format.push_back('\0'); + return end; + } + + template <typename FormatContext> + auto format(const std::tm &tm, FormatContext &ctx) -> decltype(ctx.out()) { + basic_memory_buffer<Char> buf; + std::size_t start = buf.size(); + for (;;) { + std::size_t size = buf.capacity() - start; + std::size_t count = + internal::strftime(&buf[start], size, &tm_format[0], &tm); + if (count != 0) { + buf.resize(start + count); + break; + } + if (size >= tm_format.size() * 256) { + // If the buffer is 256 times larger than the format string, assume + // that `strftime` gives an empty result. There doesn't seem to be a + // better way to distinguish the two cases: + // https://github.com/fmtlib/fmt/issues/367 + break; + } + const std::size_t MIN_GROWTH = 10; + buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); + } + return std::copy(buf.begin(), buf.end(), ctx.out()); + } + + basic_memory_buffer<Char> tm_format; +}; +FMT_END_NAMESPACE + +#endif // FMT_TIME_H_ diff --git a/matching/include/spdlog/fmt/fmt.h b/matching/include/spdlog/fmt/fmt.h new file mode 100644 index 0000000..616af0c --- /dev/null +++ b/matching/include/spdlog/fmt/fmt.h @@ -0,0 +1,25 @@ +// +// Copyright(c) 2016-2018 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +// +// Include a bundled header-only copy of fmtlib or an external one. +// By default spdlog include its own copy. +// + +#if !defined(SPDLOG_FMT_EXTERNAL) +#ifndef FMT_HEADER_ONLY +#define FMT_HEADER_ONLY +#endif +#ifndef FMT_USE_WINDOWS_H +#define FMT_USE_WINDOWS_H 0 +#endif +#include "bundled/core.h" +#include "bundled/format.h" +#else // external fmtlib +#include <fmt/core.h> +#include <fmt/format.h> +#endif diff --git a/matching/include/spdlog/fmt/ostr.h b/matching/include/spdlog/fmt/ostr.h new file mode 100644 index 0000000..9902898 --- /dev/null +++ b/matching/include/spdlog/fmt/ostr.h @@ -0,0 +1,18 @@ +// +// Copyright(c) 2016 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once +// +// include bundled or external copy of fmtlib's ostream support +// +#if !defined(SPDLOG_FMT_EXTERNAL) +#ifndef FMT_HEADER_ONLY +#define FMT_HEADER_ONLY +#endif +#include "bundled/ostream.h" +#include "fmt.h" +#else +#include <fmt/ostream.h> +#endif diff --git a/matching/include/spdlog/formatter.h b/matching/include/spdlog/formatter.h new file mode 100644 index 0000000..a7ef6b8 --- /dev/null +++ b/matching/include/spdlog/formatter.h @@ -0,0 +1,20 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#include "fmt/fmt.h" +#include "spdlog/details/log_msg.h" + +namespace spdlog { + +class formatter +{ +public: + virtual ~formatter() = default; + virtual void format(const details::log_msg &msg, fmt::memory_buffer &dest) = 0; + virtual std::unique_ptr<formatter> clone() const = 0; +}; +} // namespace spdlog diff --git a/matching/include/spdlog/logger.h b/matching/include/spdlog/logger.h new file mode 100644 index 0000000..3dbaaa6 --- /dev/null +++ b/matching/include/spdlog/logger.h @@ -0,0 +1,188 @@ +// +// Copyright(c) 2015-2108 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +// Thread safe logger (except for set_pattern(..), set_formatter(..) and +// set_error_handler()) +// Has name, log level, vector of std::shared sink pointers and formatter +// Upon each log write the logger: +// 1. Checks if its log level is enough to log the message and if yes: +// 2. Call the underlying sinks to do the job. +// 3. Each sink use its own private copy of a formatter to format the message +// and send to its destination. +// +// The use of private formatter per sink provides the opportunity to cache some +// formatted data, +// and support customize format per each sink. + +#include "spdlog/common.h" +#include "spdlog/formatter.h" +#include "spdlog/sinks/sink.h" + +#include <memory> +#include <string> +#include <vector> + +namespace spdlog { + +class logger +{ +public: + logger(std::string name, sink_ptr single_sink); + logger(std::string name, sinks_init_list sinks); + + template<typename It> + logger(std::string name, It begin, It end); + + virtual ~logger(); + + logger(const logger &) = delete; + logger &operator=(const logger &) = delete; + + template<typename... Args> + void log(level::level_enum lvl, const char *fmt, const Args &... args); + + template<typename... Args> + void log(source_loc loc, level::level_enum lvl, const char *fmt, const Args &... args); + + void log(level::level_enum lvl, const char *msg); + + void log(source_loc loc, level::level_enum lvl, const char *msg); + + template<typename... Args> + void trace(const char *fmt, const Args &... args); + + template<typename... Args> + void debug(const char *fmt, const Args &... args); + + template<typename... Args> + void info(const char *fmt, const Args &... args); + + template<typename... Args> + void warn(const char *fmt, const Args &... args); + + template<typename... Args> + void error(const char *fmt, const Args &... args); + + template<typename... Args> + void critical(const char *fmt, const Args &... args); + +#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT +#ifndef _WIN32 +#error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows +#else + template<typename... Args> + void log(level::level_enum lvl, const wchar_t *fmt, const Args &... args); + + template<typename... Args> + void log(source_loc source, level::level_enum lvl, const wchar_t *fmt, const Args &... args); + + template<typename... Args> + void trace(const wchar_t *fmt, const Args &... args); + + template<typename... Args> + void debug(const wchar_t *fmt, const Args &... args); + + template<typename... Args> + void info(const wchar_t *fmt, const Args &... args); + + template<typename... Args> + void warn(const wchar_t *fmt, const Args &... args); + + template<typename... Args> + void error(const wchar_t *fmt, const Args &... args); + + template<typename... Args> + void critical(const wchar_t *fmt, const Args &... args); +#endif // _WIN32 +#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT + + // T can be statically converted to string_view + template<class T, typename std::enable_if<std::is_convertible<T, spdlog::string_view_t>::value, T>::type * = nullptr> + void log(level::level_enum lvl, const T &); + + // T can be statically converted to string_view + template<class T, typename std::enable_if<std::is_convertible<T, spdlog::string_view_t>::value, T>::type * = nullptr> + void log(source_loc loc, level::level_enum lvl, const T &); + + // T cannot be statically converted to string_view + template<class T, typename std::enable_if<!std::is_convertible<T, spdlog::string_view_t>::value, T>::type * = nullptr> + void log(level::level_enum lvl, const T &); + + // T cannot be statically converted to string_view + template<class T, typename std::enable_if<!std::is_convertible<T, spdlog::string_view_t>::value, T>::type * = nullptr> + void log(source_loc loc, level::level_enum lvl, const T &); + + template<typename T> + void trace(const T &msg); + + template<typename T> + void debug(const T &msg); + + template<typename T> + void info(const T &msg); + + template<typename T> + void warn(const T &msg); + + template<typename T> + void error(const T &msg); + + template<typename T> + void critical(const T &msg); + + bool should_log(level::level_enum msg_level) const; + void set_level(level::level_enum log_level); + + static level::level_enum default_level(); + level::level_enum level() const; + const std::string &name() const; + + // set formatting for the sinks in this logger. + // each sink will get a seperate instance of the formatter object. + void set_formatter(std::unique_ptr<formatter> formatter); + void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local); + + // flush functions + void flush(); + void flush_on(level::level_enum log_level); + level::level_enum flush_level() const; + + // sinks + const std::vector<sink_ptr> &sinks() const; + std::vector<sink_ptr> &sinks(); + + // error handler + void set_error_handler(log_err_handler err_handler); + log_err_handler error_handler() const; + + // create new logger with same sinks and configuration. + virtual std::shared_ptr<logger> clone(std::string logger_name); + +protected: + virtual void sink_it_(details::log_msg &msg); + virtual void flush_(); + + bool should_flush_(const details::log_msg &msg); + + // default error handler. + // print the error to stderr with the max rate of 1 message/minute. + void default_err_handler_(const std::string &msg); + + // increment the message count (only if defined(SPDLOG_ENABLE_MESSAGE_COUNTER)) + void incr_msg_counter_(details::log_msg &msg); + + const std::string name_; + std::vector<sink_ptr> sinks_; + spdlog::level_t level_{spdlog::logger::default_level()}; + spdlog::level_t flush_level_{level::off}; + log_err_handler err_handler_{[this](const std::string &msg) { this->default_err_handler_(msg); }}; + std::atomic<time_t> last_err_time_{0}; + std::atomic<size_t> msg_counter_{1}; +}; +} // namespace spdlog + +#include "details/logger_impl.h" diff --git a/matching/include/spdlog/sinks/android_sink.h b/matching/include/spdlog/sinks/android_sink.h new file mode 100644 index 0000000..ae7f773 --- /dev/null +++ b/matching/include/spdlog/sinks/android_sink.h @@ -0,0 +1,121 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#ifndef SPDLOG_H +#include "spdlog/spdlog.h" +#endif + +#include "spdlog/details/fmt_helper.h" +#include "spdlog/details/null_mutex.h" +#include "spdlog/details/os.h" +#include "spdlog/sinks/base_sink.h" + +#include <android/log.h> +#include <chrono> +#include <mutex> +#include <string> +#include <thread> + +#if !defined(SPDLOG_ANDROID_RETRIES) +#define SPDLOG_ANDROID_RETRIES 2 +#endif + +namespace spdlog { +namespace sinks { + +/* + * Android sink (logging using __android_log_write) + */ +template<typename Mutex> +class android_sink final : public base_sink<Mutex> +{ +public: + explicit android_sink(std::string tag = "spdlog", bool use_raw_msg = false) + : tag_(std::move(tag)) + , use_raw_msg_(use_raw_msg) + { + } + +protected: + void sink_it_(const details::log_msg &msg) override + { + const android_LogPriority priority = convert_to_android_(msg.level); + fmt::memory_buffer formatted; + if (use_raw_msg_) + { + details::fmt_helper::append_string_view(msg.payload, formatted); + } + else + { + sink::formatter_->format(msg, formatted); + } + formatted.push_back('\0'); + const char *msg_output = formatted.data(); + + // See system/core/liblog/logger_write.c for explanation of return value + int ret = __android_log_write(priority, tag_.c_str(), msg_output); + int retry_count = 0; + while ((ret == -11 /*EAGAIN*/) && (retry_count < SPDLOG_ANDROID_RETRIES)) + { + details::os::sleep_for_millis(5); + ret = __android_log_write(priority, tag_.c_str(), msg_output); + retry_count++; + } + + if (ret < 0) + { + throw spdlog_ex("__android_log_write() failed", ret); + } + } + + void flush_() override {} + +private: + static android_LogPriority convert_to_android_(spdlog::level::level_enum level) + { + switch (level) + { + case spdlog::level::trace: + return ANDROID_LOG_VERBOSE; + case spdlog::level::debug: + return ANDROID_LOG_DEBUG; + case spdlog::level::info: + return ANDROID_LOG_INFO; + case spdlog::level::warn: + return ANDROID_LOG_WARN; + case spdlog::level::err: + return ANDROID_LOG_ERROR; + case spdlog::level::critical: + return ANDROID_LOG_FATAL; + default: + return ANDROID_LOG_DEFAULT; + } + } + + std::string tag_; + bool use_raw_msg_; +}; + +using android_sink_mt = android_sink<std::mutex>; +using android_sink_st = android_sink<details::null_mutex>; +} // namespace sinks + +// Create and register android syslog logger + +template<typename Factory = default_factory> +inline std::shared_ptr<logger> android_logger_mt(const std::string &logger_name, const std::string &tag = "spdlog") +{ + return Factory::template create<sinks::android_sink_mt>(logger_name, tag); +} + +template<typename Factory = default_factory> +inline std::shared_ptr<logger> android_logger_st(const std::string &logger_name, const std::string &tag = "spdlog") +{ + return Factory::template create<sinks::android_sink_st>(logger_name, tag); +} + +} // namespace spdlog diff --git a/matching/include/spdlog/sinks/ansicolor_sink.h b/matching/include/spdlog/sinks/ansicolor_sink.h new file mode 100644 index 0000000..7c5e353 --- /dev/null +++ b/matching/include/spdlog/sinks/ansicolor_sink.h @@ -0,0 +1,161 @@ +// +// Copyright(c) 2017 spdlog authors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#ifndef SPDLOG_H +#include "spdlog/spdlog.h" +#endif + +#include "spdlog/details/console_globals.h" +#include "spdlog/details/null_mutex.h" +#include "spdlog/details/os.h" +#include "spdlog/sinks/sink.h" + +#include <memory> +#include <mutex> +#include <string> +#include <unordered_map> + +namespace spdlog { +namespace sinks { + +/** + * This sink prefixes the output with an ANSI escape sequence color code + * depending on the severity + * of the message. + * If no color terminal detected, omit the escape codes. + */ +template<typename TargetStream, class ConsoleMutex> +class ansicolor_sink final : public sink +{ +public: + using mutex_t = typename ConsoleMutex::mutex_t; + ansicolor_sink() + : target_file_(TargetStream::stream()) + , mutex_(ConsoleMutex::mutex()) + + { + should_do_colors_ = details::os::in_terminal(target_file_) && details::os::is_color_terminal(); + colors_[level::trace] = white; + colors_[level::debug] = cyan; + colors_[level::info] = green; + colors_[level::warn] = yellow + bold; + colors_[level::err] = red + bold; + colors_[level::critical] = bold + on_red; + colors_[level::off] = reset; + } + + ~ansicolor_sink() override = default; + + ansicolor_sink(const ansicolor_sink &other) = delete; + ansicolor_sink &operator=(const ansicolor_sink &other) = delete; + + void set_color(level::level_enum color_level, const std::string &color) + { + std::lock_guard<mutex_t> lock(mutex_); + colors_[color_level] = color; + } + + /// Formatting codes + const std::string reset = "\033[m"; + const std::string bold = "\033[1m"; + const std::string dark = "\033[2m"; + const std::string underline = "\033[4m"; + const std::string blink = "\033[5m"; + const std::string reverse = "\033[7m"; + const std::string concealed = "\033[8m"; + const std::string clear_line = "\033[K"; + + // Foreground colors + const std::string black = "\033[30m"; + const std::string red = "\033[31m"; + const std::string green = "\033[32m"; + const std::string yellow = "\033[33m"; + const std::string blue = "\033[34m"; + const std::string magenta = "\033[35m"; + const std::string cyan = "\033[36m"; + const std::string white = "\033[37m"; + + /// Background colors + const std::string on_black = "\033[40m"; + const std::string on_red = "\033[41m"; + const std::string on_green = "\033[42m"; + const std::string on_yellow = "\033[43m"; + const std::string on_blue = "\033[44m"; + const std::string on_magenta = "\033[45m"; + const std::string on_cyan = "\033[46m"; + const std::string on_white = "\033[47m"; + + void log(const details::log_msg &msg) override + { + // Wrap the originally formatted message in color codes. + // If color is not supported in the terminal, log as is instead. + std::lock_guard<mutex_t> lock(mutex_); + + fmt::memory_buffer formatted; + formatter_->format(msg, formatted); + if (should_do_colors_ && msg.color_range_end > msg.color_range_start) + { + // before color range + print_range_(formatted, 0, msg.color_range_start); + // in color range + print_ccode_(colors_[msg.level]); + print_range_(formatted, msg.color_range_start, msg.color_range_end); + print_ccode_(reset); + // after color range + print_range_(formatted, msg.color_range_end, formatted.size()); + } + else // no color + { + print_range_(formatted, 0, formatted.size()); + } + fflush(target_file_); + } + + void flush() override + { + std::lock_guard<mutex_t> lock(mutex_); + fflush(target_file_); + } + + void set_pattern(const std::string &pattern) final + { + std::lock_guard<mutex_t> lock(mutex_); + formatter_ = std::unique_ptr<spdlog::formatter>(new pattern_formatter(pattern)); + } + + void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) override + { + std::lock_guard<mutex_t> lock(mutex_); + formatter_ = std::move(sink_formatter); + } + +private: + void print_ccode_(const std::string &color_code) + { + fwrite(color_code.data(), sizeof(char), color_code.size(), target_file_); + } + void print_range_(const fmt::memory_buffer &formatted, size_t start, size_t end) + { + fwrite(formatted.data() + start, sizeof(char), end - start, target_file_); + } + + FILE *target_file_; + mutex_t &mutex_; + + bool should_do_colors_; + std::unordered_map<level::level_enum, std::string, level::level_hasher> colors_; +}; + +using ansicolor_stdout_sink_mt = ansicolor_sink<details::console_stdout, details::console_mutex>; +using ansicolor_stdout_sink_st = ansicolor_sink<details::console_stdout, details::console_nullmutex>; + +using ansicolor_stderr_sink_mt = ansicolor_sink<details::console_stderr, details::console_mutex>; +using ansicolor_stderr_sink_st = ansicolor_sink<details::console_stderr, details::console_nullmutex>; + +} // namespace sinks + +} // namespace spdlog diff --git a/matching/include/spdlog/sinks/base_sink.h b/matching/include/spdlog/sinks/base_sink.h new file mode 100644 index 0000000..2259518 --- /dev/null +++ b/matching/include/spdlog/sinks/base_sink.h @@ -0,0 +1,69 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once +// +// base sink templated over a mutex (either dummy or real) +// concrete implementation should override the sink_it_() and flush_() methods. +// locking is taken care of in this class - no locking needed by the +// implementers.. +// + +#include "spdlog/common.h" +#include "spdlog/details/log_msg.h" +#include "spdlog/formatter.h" +#include "spdlog/sinks/sink.h" + +namespace spdlog { +namespace sinks { +template<typename Mutex> +class base_sink : public sink +{ +public: + base_sink() = default; + base_sink(const base_sink &) = delete; + base_sink &operator=(const base_sink &) = delete; + + void log(const details::log_msg &msg) final + { + std::lock_guard<Mutex> lock(mutex_); + sink_it_(msg); + } + + void flush() final + { + std::lock_guard<Mutex> lock(mutex_); + flush_(); + } + + void set_pattern(const std::string &pattern) final + { + std::lock_guard<Mutex> lock(mutex_); + set_pattern_(pattern); + } + + void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) final + { + std::lock_guard<Mutex> lock(mutex_); + set_formatter_(std::move(sink_formatter)); + } + +protected: + virtual void sink_it_(const details::log_msg &msg) = 0; + virtual void flush_() = 0; + + virtual void set_pattern_(const std::string &pattern) + { + set_formatter_(details::make_unique<spdlog::pattern_formatter>(pattern)); + } + + virtual void set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter) + { + formatter_ = std::move(sink_formatter); + } + Mutex mutex_; +}; +} // namespace sinks +} // namespace spdlog diff --git a/matching/include/spdlog/sinks/basic_file_sink.h b/matching/include/spdlog/sinks/basic_file_sink.h new file mode 100644 index 0000000..facc720 --- /dev/null +++ b/matching/include/spdlog/sinks/basic_file_sink.h @@ -0,0 +1,75 @@ +// +// Copyright(c) 2015-2018 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#ifndef SPDLOG_H +#include "spdlog/spdlog.h" +#endif + +#include "spdlog/details/file_helper.h" +#include "spdlog/details/null_mutex.h" +#include "spdlog/sinks/base_sink.h" + +#include <mutex> +#include <string> + +namespace spdlog { +namespace sinks { +/* + * Trivial file sink with single file as target + */ +template<typename Mutex> +class basic_file_sink final : public base_sink<Mutex> +{ +public: + explicit basic_file_sink(const filename_t &filename, bool truncate = false) + { + file_helper_.open(filename, truncate); + } + + const filename_t &filename() const + { + return file_helper_.filename(); + } + +protected: + void sink_it_(const details::log_msg &msg) override + { + fmt::memory_buffer formatted; + sink::formatter_->format(msg, formatted); + file_helper_.write(formatted); + } + + void flush_() override + { + file_helper_.flush(); + } + +private: + details::file_helper file_helper_; +}; + +using basic_file_sink_mt = basic_file_sink<std::mutex>; +using basic_file_sink_st = basic_file_sink<details::null_mutex>; + +} // namespace sinks + +// +// factory functions +// +template<typename Factory = default_factory> +inline std::shared_ptr<logger> basic_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false) +{ + return Factory::template create<sinks::basic_file_sink_mt>(logger_name, filename, truncate); +} + +template<typename Factory = default_factory> +inline std::shared_ptr<logger> basic_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false) +{ + return Factory::template create<sinks::basic_file_sink_st>(logger_name, filename, truncate); +} + +} // namespace spdlog diff --git a/matching/include/spdlog/sinks/daily_file_sink.h b/matching/include/spdlog/sinks/daily_file_sink.h new file mode 100644 index 0000000..08392c1 --- /dev/null +++ b/matching/include/spdlog/sinks/daily_file_sink.h @@ -0,0 +1,141 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#ifndef SPDLOG_H +#include "spdlog/spdlog.h" +#endif + +#include "spdlog/details/file_helper.h" +#include "spdlog/details/null_mutex.h" +#include "spdlog/fmt/fmt.h" +#include "spdlog/sinks/base_sink.h" + +#include <chrono> +#include <cstdio> +#include <ctime> +#include <mutex> +#include <string> + +namespace spdlog { +namespace sinks { + +/* + * Generator of daily log file names in format basename.YYYY-MM-DD.ext + */ +struct daily_filename_calculator +{ + // Create filename for the form basename.YYYY-MM-DD + static filename_t calc_filename(const filename_t &filename, const tm &now_tm) + { + filename_t basename, ext; + std::tie(basename, ext) = details::file_helper::split_by_extension(filename); + std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::memory_buffer, fmt::wmemory_buffer>::type w; + fmt::format_to( + w, SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday, ext); + return fmt::to_string(w); + } +}; + +/* + * Rotating file sink based on date. rotates at midnight + */ +template<typename Mutex, typename FileNameCalc = daily_filename_calculator> +class daily_file_sink final : public base_sink<Mutex> +{ +public: + // create daily file sink which rotates on given time + daily_file_sink(filename_t base_filename, int rotation_hour, int rotation_minute, bool truncate = false) + : base_filename_(std::move(base_filename)) + , rotation_h_(rotation_hour) + , rotation_m_(rotation_minute) + , truncate_(truncate) + { + if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59) + { + throw spdlog_ex("daily_file_sink: Invalid rotation time in ctor"); + } + auto now = log_clock::now(); + file_helper_.open(FileNameCalc::calc_filename(base_filename_, now_tm(now)), truncate_); + rotation_tp_ = next_rotation_tp_(); + } + + const filename_t &filename() const + { + return file_helper_.filename(); + } + +protected: + void sink_it_(const details::log_msg &msg) override + { + + if (msg.time >= rotation_tp_) + { + file_helper_.open(FileNameCalc::calc_filename(base_filename_, now_tm(msg.time)), truncate_); + rotation_tp_ = next_rotation_tp_(); + } + fmt::memory_buffer formatted; + sink::formatter_->format(msg, formatted); + file_helper_.write(formatted); + } + + void flush_() override + { + file_helper_.flush(); + } + +private: + tm now_tm(log_clock::time_point tp) + { + time_t tnow = log_clock::to_time_t(tp); + return spdlog::details::os::localtime(tnow); + } + + log_clock::time_point next_rotation_tp_() + { + auto now = log_clock::now(); + tm date = now_tm(now); + date.tm_hour = rotation_h_; + date.tm_min = rotation_m_; + date.tm_sec = 0; + auto rotation_time = log_clock::from_time_t(std::mktime(&date)); + if (rotation_time > now) + { + return rotation_time; + } + return {rotation_time + std::chrono::hours(24)}; + } + + filename_t base_filename_; + int rotation_h_; + int rotation_m_; + log_clock::time_point rotation_tp_; + details::file_helper file_helper_; + bool truncate_; +}; + +using daily_file_sink_mt = daily_file_sink<std::mutex>; +using daily_file_sink_st = daily_file_sink<details::null_mutex>; + +} // namespace sinks + +// +// factory functions +// +template<typename Factory = default_factory> +inline std::shared_ptr<logger> daily_logger_mt( + const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false) +{ + return Factory::template create<sinks::daily_file_sink_mt>(logger_name, filename, hour, minute, truncate); +} + +template<typename Factory = default_factory> +inline std::shared_ptr<logger> daily_logger_st( + const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false) +{ + return Factory::template create<sinks::daily_file_sink_st>(logger_name, filename, hour, minute, truncate); +} +} // namespace spdlog diff --git a/matching/include/spdlog/sinks/dist_sink.h b/matching/include/spdlog/sinks/dist_sink.h new file mode 100644 index 0000000..44de391 --- /dev/null +++ b/matching/include/spdlog/sinks/dist_sink.h @@ -0,0 +1,94 @@ +// +// Copyright (c) 2015 David Schury, Gabi Melman +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#ifndef SPDLOG_H +#include "spdlog/spdlog.h" +#endif + +#include "base_sink.h" +#include "spdlog/details/log_msg.h" +#include "spdlog/details/null_mutex.h" + +#include <algorithm> +#include <memory> +#include <mutex> +#include <vector> + +// Distribution sink (mux). Stores a vector of sinks which get called when log +// is called + +namespace spdlog { +namespace sinks { + +template<typename Mutex> +class dist_sink : public base_sink<Mutex> +{ +public: + dist_sink() = default; + dist_sink(const dist_sink &) = delete; + dist_sink &operator=(const dist_sink &) = delete; + + void add_sink(std::shared_ptr<sink> sink) + { + std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_); + sinks_.push_back(sink); + } + + void remove_sink(std::shared_ptr<sink> sink) + { + std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_); + sinks_.erase(std::remove(sinks_.begin(), sinks_.end(), sink), sinks_.end()); + } + + void set_sinks(std::vector<std::shared_ptr<sink>> sinks) + { + std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_); + sinks_ = std::move(sinks); + } + +protected: + void sink_it_(const details::log_msg &msg) override + { + + for (auto &sink : sinks_) + { + if (sink->should_log(msg.level)) + { + sink->log(msg); + } + } + } + + void flush_() override + { + for (auto &sink : sinks_) + { + sink->flush(); + } + } + + void set_pattern_(const std::string &pattern) override + { + set_formatter_(details::make_unique<spdlog::pattern_formatter>(pattern)); + } + + void set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter) override + { + base_sink<Mutex>::formatter_ = std::move(sink_formatter); + for (auto &sink : sinks_) + { + sink->set_formatter(base_sink<Mutex>::formatter_->clone()); + } + } + std::vector<std::shared_ptr<sink>> sinks_; +}; + +using dist_sink_mt = dist_sink<std::mutex>; +using dist_sink_st = dist_sink<details::null_mutex>; + +} // namespace sinks +} // namespace spdlog diff --git a/matching/include/spdlog/sinks/msvc_sink.h b/matching/include/spdlog/sinks/msvc_sink.h new file mode 100644 index 0000000..f06c16c --- /dev/null +++ b/matching/include/spdlog/sinks/msvc_sink.h @@ -0,0 +1,54 @@ +// +// Copyright(c) 2016 Alexander Dalshov. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#ifndef SPDLOG_H +#include "spdlog/spdlog.h" +#endif + +#if defined(_WIN32) + +#include "spdlog/details/null_mutex.h" +#include "spdlog/sinks/base_sink.h" + +#include <winbase.h> + +#include <mutex> +#include <string> + +namespace spdlog { +namespace sinks { +/* + * MSVC sink (logging using OutputDebugStringA) + */ +template<typename Mutex> +class msvc_sink : public base_sink<Mutex> +{ +public: + explicit msvc_sink() {} + +protected: + void sink_it_(const details::log_msg &msg) override + { + + fmt::memory_buffer formatted; + sink::formatter_->format(msg, formatted); + OutputDebugStringA(fmt::to_string(formatted).c_str()); + } + + void flush_() override {} +}; + +using msvc_sink_mt = msvc_sink<std::mutex>; +using msvc_sink_st = msvc_sink<details::null_mutex>; + +using windebug_sink_mt = msvc_sink_mt; +using windebug_sink_st = msvc_sink_st; + +} // namespace sinks +} // namespace spdlog + +#endif diff --git a/matching/include/spdlog/sinks/null_sink.h b/matching/include/spdlog/sinks/null_sink.h new file mode 100644 index 0000000..54f322c --- /dev/null +++ b/matching/include/spdlog/sinks/null_sink.h @@ -0,0 +1,49 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#ifndef SPDLOG_H +#include "spdlog/spdlog.h" +#endif + +#include "spdlog/details/null_mutex.h" +#include "spdlog/sinks/base_sink.h" + +#include <mutex> + +namespace spdlog { +namespace sinks { + +template<typename Mutex> +class null_sink : public base_sink<Mutex> +{ +protected: + void sink_it_(const details::log_msg &) override {} + void flush_() override {} +}; + +using null_sink_mt = null_sink<std::mutex>; +using null_sink_st = null_sink<details::null_mutex>; + +} // namespace sinks + +template<typename Factory = default_factory> +inline std::shared_ptr<logger> null_logger_mt(const std::string &logger_name) +{ + auto null_logger = Factory::template create<sinks::null_sink_mt>(logger_name); + null_logger->set_level(level::off); + return null_logger; +} + +template<typename Factory = default_factory> +inline std::shared_ptr<logger> null_logger_st(const std::string &logger_name) +{ + auto null_logger = Factory::template create<sinks::null_sink_st>(logger_name); + null_logger->set_level(level::off); + return null_logger; +} + +} // namespace spdlog diff --git a/matching/include/spdlog/sinks/ostream_sink.h b/matching/include/spdlog/sinks/ostream_sink.h new file mode 100644 index 0000000..22e377b --- /dev/null +++ b/matching/include/spdlog/sinks/ostream_sink.h @@ -0,0 +1,57 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#ifndef SPDLOG_H +#include "spdlog/spdlog.h" +#endif + +#include "spdlog/details/null_mutex.h" +#include "spdlog/sinks/base_sink.h" + +#include <mutex> +#include <ostream> + +namespace spdlog { +namespace sinks { +template<typename Mutex> +class ostream_sink final : public base_sink<Mutex> +{ +public: + explicit ostream_sink(std::ostream &os, bool force_flush = false) + : ostream_(os) + , force_flush_(force_flush) + { + } + ostream_sink(const ostream_sink &) = delete; + ostream_sink &operator=(const ostream_sink &) = delete; + +protected: + void sink_it_(const details::log_msg &msg) override + { + fmt::memory_buffer formatted; + sink::formatter_->format(msg, formatted); + ostream_.write(formatted.data(), static_cast<std::streamsize>(formatted.size())); + if (force_flush_) + { + ostream_.flush(); + } + } + + void flush_() override + { + ostream_.flush(); + } + + std::ostream &ostream_; + bool force_flush_; +}; + +using ostream_sink_mt = ostream_sink<std::mutex>; +using ostream_sink_st = ostream_sink<details::null_mutex>; + +} // namespace sinks +} // namespace spdlog diff --git a/matching/include/spdlog/sinks/rotating_file_sink.h b/matching/include/spdlog/sinks/rotating_file_sink.h new file mode 100644 index 0000000..ae0f70f --- /dev/null +++ b/matching/include/spdlog/sinks/rotating_file_sink.h @@ -0,0 +1,164 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#ifndef SPDLOG_H +#include "spdlog/spdlog.h" +#endif + +#include "spdlog/details/file_helper.h" +#include "spdlog/details/null_mutex.h" +#include "spdlog/fmt/fmt.h" +#include "spdlog/sinks/base_sink.h" + +#include <cerrno> +#include <chrono> +#include <ctime> +#include <mutex> +#include <string> +#include <tuple> + +namespace spdlog { +namespace sinks { + +// +// Rotating file sink based on size +// +template<typename Mutex> +class rotating_file_sink final : public base_sink<Mutex> +{ +public: + rotating_file_sink(filename_t base_filename, std::size_t max_size, std::size_t max_files, bool rotate_on_open=false) + : base_filename_(std::move(base_filename)) + , max_size_(max_size) + , max_files_(max_files) + { + file_helper_.open(calc_filename(base_filename_, 0)); + current_size_ = file_helper_.size(); // expensive. called only once + if (rotate_on_open && current_size_ > 0) + { + rotate_(); + } + } + + // calc filename according to index and file extension if exists. + // e.g. calc_filename("logs/mylog.txt, 3) => "logs/mylog.3.txt". + static filename_t calc_filename(const filename_t &filename, std::size_t index) + { + typename std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::memory_buffer, fmt::wmemory_buffer>::type w; + if (index != 0u) + { + filename_t basename, ext; + std::tie(basename, ext) = details::file_helper::split_by_extension(filename); + fmt::format_to(w, SPDLOG_FILENAME_T("{}.{}{}"), basename, index, ext); + } + else + { + fmt::format_to(w, SPDLOG_FILENAME_T("{}"), filename); + } + return fmt::to_string(w); + } + + const filename_t &filename() const + { + return file_helper_.filename(); + } + +protected: + void sink_it_(const details::log_msg &msg) override + { + fmt::memory_buffer formatted; + sink::formatter_->format(msg, formatted); + current_size_ += formatted.size(); + if (current_size_ > max_size_) + { + rotate_(); + current_size_ = formatted.size(); + } + file_helper_.write(formatted); + } + + void flush_() override + { + file_helper_.flush(); + } + +private: + // Rotate files: + // log.txt -> log.1.txt + // log.1.txt -> log.2.txt + // log.2.txt -> log.3.txt + // log.3.txt -> delete + void rotate_() + { + using details::os::filename_to_str; + file_helper_.close(); + for (auto i = max_files_; i > 0; --i) + { + filename_t src = calc_filename(base_filename_, i - 1); + if (!details::file_helper::file_exists(src)) + { + continue; + } + filename_t target = calc_filename(base_filename_, i); + + if (!rename_file(src, target)) + { + // if failed try again after a small delay. + // this is a workaround to a windows issue, where very high rotation + // rates can cause the rename to fail with permission denied (because of antivirus?). + details::os::sleep_for_millis(100); + if (!rename_file(src, target)) + { + file_helper_.reopen(true); // truncate the log file anyway to prevent it to grow beyond its limit! + current_size_ = 0; + throw spdlog_ex( + "rotating_file_sink: failed renaming " + filename_to_str(src) + " to " + filename_to_str(target), errno); + } + } + } + file_helper_.reopen(true); + } + + // delete the target if exists, and rename the src file to target + // return true on success, false otherwise. + bool rename_file(const filename_t &src_filename, const filename_t &target_filename) + { + // try to delete the target file in case it already exists. + (void)details::os::remove(target_filename); + return details::os::rename(src_filename, target_filename) == 0; + } + + filename_t base_filename_; + std::size_t max_size_; + std::size_t max_files_; + std::size_t current_size_; + details::file_helper file_helper_; +}; + +using rotating_file_sink_mt = rotating_file_sink<std::mutex>; +using rotating_file_sink_st = rotating_file_sink<details::null_mutex>; + +} // namespace sinks + +// +// factory functions +// + +template<typename Factory = default_factory> +inline std::shared_ptr<logger> rotating_logger_mt( + const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files, bool rotate_on_open=false) +{ + return Factory::template create<sinks::rotating_file_sink_mt>(logger_name, filename, max_file_size, max_files, rotate_on_open); +} + +template<typename Factory = default_factory> +inline std::shared_ptr<logger> rotating_logger_st( + const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files, bool rotate_on_open = false) +{ + return Factory::template create<sinks::rotating_file_sink_st>(logger_name, filename, max_file_size, max_files, rotate_on_open); +} +} // namespace spdlog diff --git a/matching/include/spdlog/sinks/sink.h b/matching/include/spdlog/sinks/sink.h new file mode 100644 index 0000000..2f1adc1 --- /dev/null +++ b/matching/include/spdlog/sinks/sink.h @@ -0,0 +1,59 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#include "spdlog/details/log_msg.h" +#include "spdlog/details/pattern_formatter.h" +#include "spdlog/formatter.h" + +namespace spdlog { +namespace sinks { +class sink +{ +public: + sink() + : level_(level::trace) + , formatter_(new pattern_formatter()) + { + } + + explicit sink(std::unique_ptr<spdlog::pattern_formatter> formatter) + : level_(level::trace) + , formatter_(std::move(formatter)) + { + } + + virtual ~sink() = default; + virtual void log(const details::log_msg &msg) = 0; + virtual void flush() = 0; + virtual void set_pattern(const std::string &pattern) = 0; + virtual void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) = 0; + + bool should_log(level::level_enum msg_level) const + { + return msg_level >= level_.load(std::memory_order_relaxed); + } + + void set_level(level::level_enum log_level) + { + level_.store(log_level); + } + + level::level_enum level() const + { + return static_cast<spdlog::level::level_enum>(level_.load(std::memory_order_relaxed)); + } + +protected: + // sink log level - default is all + level_t level_; + + // sink formatter - default is full format + std::unique_ptr<spdlog::formatter> formatter_; +}; + +} // namespace sinks +} // namespace spdlog diff --git a/matching/include/spdlog/sinks/stdout_color_sinks.h b/matching/include/spdlog/sinks/stdout_color_sinks.h new file mode 100644 index 0000000..74bfceb --- /dev/null +++ b/matching/include/spdlog/sinks/stdout_color_sinks.h @@ -0,0 +1,56 @@ +// +// Copyright(c) 2018 spdlog +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#ifndef SPDLOG_H +#include "spdlog/spdlog.h" +#endif + +#ifdef _WIN32 +#include "spdlog/sinks/wincolor_sink.h" +#else +#include "spdlog/sinks/ansicolor_sink.h" +#endif + +namespace spdlog { +namespace sinks { +#ifdef _WIN32 +using stdout_color_sink_mt = wincolor_stdout_sink_mt; +using stdout_color_sink_st = wincolor_stdout_sink_st; +using stderr_color_sink_mt = wincolor_stderr_sink_mt; +using stderr_color_sink_st = wincolor_stderr_sink_st; +#else +using stdout_color_sink_mt = ansicolor_stdout_sink_mt; +using stdout_color_sink_st = ansicolor_stdout_sink_st; +using stderr_color_sink_mt = ansicolor_stderr_sink_mt; +using stderr_color_sink_st = ansicolor_stderr_sink_st; +#endif +} // namespace sinks + +template<typename Factory = default_factory> +inline std::shared_ptr<logger> stdout_color_mt(const std::string &logger_name) +{ + return Factory::template create<sinks::stdout_color_sink_mt>(logger_name); +} + +template<typename Factory = default_factory> +inline std::shared_ptr<logger> stdout_color_st(const std::string &logger_name) +{ + return Factory::template create<sinks::stdout_color_sink_st>(logger_name); +} + +template<typename Factory = default_factory> +inline std::shared_ptr<logger> stderr_color_mt(const std::string &logger_name) +{ + return Factory::template create<sinks::stderr_color_sink_mt>(logger_name); +} + +template<typename Factory = default_factory> +inline std::shared_ptr<logger> stderr_color_st(const std::string &logger_name) +{ + return Factory::template create<sinks::stderr_color_sink_mt>(logger_name); +} +} // namespace spdlog diff --git a/matching/include/spdlog/sinks/stdout_sinks.h b/matching/include/spdlog/sinks/stdout_sinks.h new file mode 100644 index 0000000..bf8e979 --- /dev/null +++ b/matching/include/spdlog/sinks/stdout_sinks.h @@ -0,0 +1,102 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#ifndef SPDLOG_H +#include "spdlog/spdlog.h" +#endif + +#include "spdlog/details/console_globals.h" +#include "spdlog/details/null_mutex.h" + +#include <cstdio> +#include <memory> +#include <mutex> + +namespace spdlog { + +namespace sinks { + +template<typename TargetStream, typename ConsoleMutex> +class stdout_sink final : public sink +{ +public: + using mutex_t = typename ConsoleMutex::mutex_t; + stdout_sink() + : mutex_(ConsoleMutex::mutex()) + , file_(TargetStream::stream()) + { + } + ~stdout_sink() override = default; + + stdout_sink(const stdout_sink &other) = delete; + stdout_sink &operator=(const stdout_sink &other) = delete; + + void log(const details::log_msg &msg) override + { + std::lock_guard<mutex_t> lock(mutex_); + fmt::memory_buffer formatted; + formatter_->format(msg, formatted); + fwrite(formatted.data(), sizeof(char), formatted.size(), file_); + fflush(TargetStream::stream()); + } + + void flush() override + { + std::lock_guard<mutex_t> lock(mutex_); + fflush(file_); + } + + void set_pattern(const std::string &pattern) override + { + std::lock_guard<mutex_t> lock(mutex_); + formatter_ = std::unique_ptr<spdlog::formatter>(new pattern_formatter(pattern)); + } + + void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) override + { + std::lock_guard<mutex_t> lock(mutex_); + formatter_ = std::move(sink_formatter); + } + +private: + mutex_t &mutex_; + FILE *file_; +}; + +using stdout_sink_mt = stdout_sink<details::console_stdout, details::console_mutex>; +using stdout_sink_st = stdout_sink<details::console_stdout, details::console_nullmutex>; + +using stderr_sink_mt = stdout_sink<details::console_stderr, details::console_mutex>; +using stderr_sink_st = stdout_sink<details::console_stderr, details::console_nullmutex>; + +} // namespace sinks + +// factory methods +template<typename Factory = default_factory> +inline std::shared_ptr<logger> stdout_logger_mt(const std::string &logger_name) +{ + return Factory::template create<sinks::stdout_sink_mt>(logger_name); +} + +template<typename Factory = default_factory> +inline std::shared_ptr<logger> stdout_logger_st(const std::string &logger_name) +{ + return Factory::template create<sinks::stdout_sink_st>(logger_name); +} + +template<typename Factory = default_factory> +inline std::shared_ptr<logger> stderr_logger_mt(const std::string &logger_name) +{ + return Factory::template create<sinks::stderr_sink_mt>(logger_name); +} + +template<typename Factory = default_factory> +inline std::shared_ptr<logger> stderr_logger_st(const std::string &logger_name) +{ + return Factory::template create<sinks::stderr_sink_st>(logger_name); +} +} // namespace spdlog diff --git a/matching/include/spdlog/sinks/syslog_sink.h b/matching/include/spdlog/sinks/syslog_sink.h new file mode 100644 index 0000000..c3bcd84 --- /dev/null +++ b/matching/include/spdlog/sinks/syslog_sink.h @@ -0,0 +1,94 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#ifndef SPDLOG_H +#include "spdlog/spdlog.h" +#endif + +#include "spdlog/sinks/base_sink.h" + +#include <array> +#include <string> +#include <syslog.h> + +namespace spdlog { +namespace sinks { +/** + * Sink that write to syslog using the `syscall()` library call. + * + * Locking is not needed, as `syslog()` itself is thread-safe. + */ +template<typename Mutex> +class syslog_sink : public base_sink<Mutex> +{ +public: + // + explicit syslog_sink(std::string ident = "", int syslog_option = 0, int syslog_facility = LOG_USER) + : ident_(std::move(ident)) + { + priorities_[static_cast<size_t>(level::trace)] = LOG_DEBUG; + priorities_[static_cast<size_t>(level::debug)] = LOG_DEBUG; + priorities_[static_cast<size_t>(level::info)] = LOG_INFO; + priorities_[static_cast<size_t>(level::warn)] = LOG_WARNING; + priorities_[static_cast<size_t>(level::err)] = LOG_ERR; + priorities_[static_cast<size_t>(level::critical)] = LOG_CRIT; + priorities_[static_cast<size_t>(level::off)] = LOG_INFO; + + // set ident to be program name if empty + ::openlog(ident_.empty() ? nullptr : ident_.c_str(), syslog_option, syslog_facility); + } + + ~syslog_sink() override + { + ::closelog(); + } + + syslog_sink(const syslog_sink &) = delete; + syslog_sink &operator=(const syslog_sink &) = delete; + +protected: + void sink_it_(const details::log_msg &msg) override + { + ::syslog(syslog_prio_from_level(msg), "%s", fmt::to_string(msg.payload).c_str()); + } + + void flush_() override {} + +private: + std::array<int, 7> priorities_; + // must store the ident because the man says openlog might use the pointer as + // is and not a string copy + const std::string ident_; + + // + // Simply maps spdlog's log level to syslog priority level. + // + int syslog_prio_from_level(const details::log_msg &msg) const + { + return priorities_[static_cast<size_t>(msg.level)]; + } +}; + +using syslog_sink_mt = syslog_sink<std::mutex>; +using syslog_sink_st = syslog_sink<details::null_mutex>; +} // namespace sinks + +// Create and register a syslog logger +template<typename Factory = default_factory> +inline std::shared_ptr<logger> syslog_logger_mt( + const std::string &logger_name, const std::string &syslog_ident = "", int syslog_option = 0, int syslog_facility = (1 << 3)) +{ + return Factory::template create<sinks::syslog_sink_mt>(logger_name, syslog_ident, syslog_option, syslog_facility); +} + +template<typename Factory = default_factory> +inline std::shared_ptr<logger> syslog_logger_st( + const std::string &logger_name, const std::string &syslog_ident = "", int syslog_option = 0, int syslog_facility = (1 << 3)) +{ + return Factory::template create<sinks::syslog_sink_st>(logger_name, syslog_ident, syslog_option, syslog_facility); +} +} // namespace spdlog diff --git a/matching/include/spdlog/sinks/wincolor_sink.h b/matching/include/spdlog/sinks/wincolor_sink.h new file mode 100644 index 0000000..1fdf8c5 --- /dev/null +++ b/matching/include/spdlog/sinks/wincolor_sink.h @@ -0,0 +1,143 @@ +// +// Copyright(c) 2016 spdlog +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#ifndef SPDLOG_H +#include "spdlog/spdlog.h" +#endif + +#include "spdlog/common.h" +#include "spdlog/details/console_globals.h" +#include "spdlog/details/null_mutex.h" +#include "spdlog/sinks/sink.h" + +#include <memory> +#include <mutex> +#include <string> +#include <unordered_map> +#include <wincon.h> + +namespace spdlog { +namespace sinks { +/* + * Windows color console sink. Uses WriteConsoleA to write to the console with + * colors + */ +template<typename OutHandle, typename ConsoleMutex> +class wincolor_sink : public sink +{ +public: + const WORD BOLD = FOREGROUND_INTENSITY; + const WORD RED = FOREGROUND_RED; + const WORD GREEN = FOREGROUND_GREEN; + const WORD CYAN = FOREGROUND_GREEN | FOREGROUND_BLUE; + const WORD WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + const WORD YELLOW = FOREGROUND_RED | FOREGROUND_GREEN; + + wincolor_sink() + : out_handle_(OutHandle::handle()) + , mutex_(ConsoleMutex::mutex()) + { + colors_[level::trace] = WHITE; + colors_[level::debug] = CYAN; + colors_[level::info] = GREEN; + colors_[level::warn] = YELLOW | BOLD; + colors_[level::err] = RED | BOLD; // red bold + colors_[level::critical] = BACKGROUND_RED | WHITE | BOLD; // white bold on red background + colors_[level::off] = 0; + } + + ~wincolor_sink() override + { + this->flush(); + } + + wincolor_sink(const wincolor_sink &other) = delete; + wincolor_sink &operator=(const wincolor_sink &other) = delete; + + // change the color for the given level + void set_color(level::level_enum level, WORD color) + { + std::lock_guard<mutex_t> lock(mutex_); + colors_[level] = color; + } + + void log(const details::log_msg &msg) final override + { + std::lock_guard<mutex_t> lock(mutex_); + fmt::memory_buffer formatted; + formatter_->format(msg, formatted); + if (msg.color_range_end > msg.color_range_start) + { + // before color range + print_range_(formatted, 0, msg.color_range_start); + + // in color range + auto orig_attribs = set_console_attribs(colors_[msg.level]); + print_range_(formatted, msg.color_range_start, msg.color_range_end); + ::SetConsoleTextAttribute(out_handle_, + orig_attribs); // reset to orig colors + // after color range + print_range_(formatted, msg.color_range_end, formatted.size()); + } + else // print without colors if color range is invalid + { + print_range_(formatted, 0, formatted.size()); + } + } + + void flush() final override + { + // windows console always flushed? + } + + void set_pattern(const std::string &pattern) override final + { + std::lock_guard<mutex_t> lock(mutex_); + formatter_ = std::unique_ptr<spdlog::formatter>(new pattern_formatter(pattern)); + } + + void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) override final + { + std::lock_guard<mutex_t> lock(mutex_); + formatter_ = std::move(sink_formatter); + } + +private: + using mutex_t = typename ConsoleMutex::mutex_t; + // set color and return the orig console attributes (for resetting later) + WORD set_console_attribs(WORD attribs) + { + CONSOLE_SCREEN_BUFFER_INFO orig_buffer_info; + ::GetConsoleScreenBufferInfo(out_handle_, &orig_buffer_info); + WORD back_color = orig_buffer_info.wAttributes; + // retrieve the current background color + back_color &= static_cast<WORD>(~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY)); + // keep the background color unchanged + ::SetConsoleTextAttribute(out_handle_, attribs | back_color); + return orig_buffer_info.wAttributes; // return orig attribs + } + + // print a range of formatted message to console + void print_range_(const fmt::memory_buffer &formatted, size_t start, size_t end) + { + auto size = static_cast<DWORD>(end - start); + ::WriteConsoleA(out_handle_, formatted.data() + start, size, nullptr, nullptr); + } + + HANDLE out_handle_; + mutex_t &mutex_; + std::unordered_map<level::level_enum, WORD, level::level_hasher> colors_; +}; + +using wincolor_stdout_sink_mt = wincolor_sink<details::console_stdout, details::console_mutex>; +using wincolor_stdout_sink_st = wincolor_sink<details::console_stdout, details::console_nullmutex>; + +using wincolor_stderr_sink_mt = wincolor_sink<details::console_stderr, details::console_mutex>; +using wincolor_stderr_sink_st = wincolor_sink<details::console_stderr, details::console_nullmutex>; + +} // namespace sinks +} // namespace spdlog diff --git a/matching/include/spdlog/spdlog.h b/matching/include/spdlog/spdlog.h new file mode 100644 index 0000000..20ff24b --- /dev/null +++ b/matching/include/spdlog/spdlog.h @@ -0,0 +1,366 @@ +// +// Copyright(c) 2015-2018 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// +// spdlog main header file. +// see example.cpp for usage example + +#ifndef SPDLOG_H +#define SPDLOG_H +#pragma once + +#include "spdlog/common.h" +#include "spdlog/details/registry.h" +#include "spdlog/logger.h" +#include "spdlog/version.h" + +#include <chrono> +#include <functional> +#include <memory> +#include <string> + +namespace spdlog { + +// Default logger factory- creates synchronous loggers +struct synchronous_factory +{ + template<typename Sink, typename... SinkArgs> + static std::shared_ptr<spdlog::logger> create(std::string logger_name, SinkArgs &&... args) + { + auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...); + auto new_logger = std::make_shared<logger>(std::move(logger_name), std::move(sink)); + details::registry::instance().initialize_logger(new_logger); + return new_logger; + } +}; + +using default_factory = synchronous_factory; + +// Create and register a logger with a templated sink type +// The logger's level, formatter and flush level will be set according the +// global settings. +// Example: +// spdlog::create<daily_file_sink_st>("logger_name", "dailylog_filename", 11, 59); +template<typename Sink, typename... SinkArgs> +inline std::shared_ptr<spdlog::logger> create(std::string logger_name, SinkArgs &&... sink_args) +{ + return default_factory::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...); +} + +// Return an existing logger or nullptr if a logger with such name doesn't +// exist. +// example: spdlog::get("my_logger")->info("hello {}", "world"); +inline std::shared_ptr<logger> get(const std::string &name) +{ + return details::registry::instance().get(name); +} + +// Set global formatter. Each sink in each logger will get a clone of this object +inline void set_formatter(std::unique_ptr<spdlog::formatter> formatter) +{ + details::registry::instance().set_formatter(std::move(formatter)); +} + +// Set global format string. +// example: spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l : %v"); +inline void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local) +{ + set_formatter(std::unique_ptr<spdlog::formatter>(new pattern_formatter(std::move(pattern), time_type))); +} + +// Set global logging level +inline void set_level(level::level_enum log_level) +{ + details::registry::instance().set_level(log_level); +} + +// Set global flush level +inline void flush_on(level::level_enum log_level) +{ + details::registry::instance().flush_on(log_level); +} + +// Start/Restart a periodic flusher thread +// Warning: Use only if all your loggers are thread safe! +inline void flush_every(std::chrono::seconds interval) +{ + details::registry::instance().flush_every(interval); +} + +// Set global error handler +inline void set_error_handler(log_err_handler handler) +{ + details::registry::instance().set_error_handler(std::move(handler)); +} + +// Register the given logger with the given name +inline void register_logger(std::shared_ptr<logger> logger) +{ + details::registry::instance().register_logger(std::move(logger)); +} + +// Apply a user defined function on all registered loggers +// Example: +// spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) {l->flush();}); +inline void apply_all(const std::function<void(std::shared_ptr<logger>)> &fun) +{ + details::registry::instance().apply_all(fun); +} + +// Drop the reference to the given logger +inline void drop(const std::string &name) +{ + details::registry::instance().drop(name); +} + +// Drop all references from the registry +inline void drop_all() +{ + details::registry::instance().drop_all(); +} + +// stop any running threads started by spdlog and clean registry loggers +inline void shutdown() +{ + details::registry::instance().shutdown(); +} + +// Automatic registration of loggers when using spdlog::create() or spdlog::create_async +inline void set_automatic_registration(bool automatic_registation) +{ + details::registry::instance().set_automatic_registration(automatic_registation); +} + +// API for using default logger (stdout_color_mt), +// e.g: spdlog::info("Message {}", 1); +// +// The default logger object can be accessed using the spdlog::default_logger(): +// For example, to add another sink to it: +// spdlog::default_logger()->sinks()->push_back(some_sink); +// +// The default logger can replaced using spdlog::set_default_logger(new_logger). +// For example, to replace it with a file logger. +// +// IMPORTANT: +// The default API is thread safe (for _mt loggers), but: +// set_default_logger() *should not* be used concurrently with the default API. +// e.g do not call set_default_logger() from one thread while calling spdlog::info() from another. + +inline std::shared_ptr<spdlog::logger> default_logger() +{ + return details::registry::instance().default_logger(); +} + +inline spdlog::logger *default_logger_raw() +{ + return details::registry::instance().get_default_raw(); +} + +inline void set_default_logger(std::shared_ptr<spdlog::logger> default_logger) +{ + details::registry::instance().set_default_logger(std::move(default_logger)); +} + +template<typename... Args> +inline void log(source_loc source, level::level_enum lvl, const char *fmt, const Args &... args) +{ + default_logger_raw()->log(source, lvl, fmt, args...); +} + +template<typename... Args> +inline void log(level::level_enum lvl, const char *fmt, const Args &... args) +{ + default_logger_raw()->log(source_loc{}, lvl, fmt, args...); +} + +template<typename... Args> +inline void trace(const char *fmt, const Args &... args) +{ + default_logger_raw()->trace(fmt, args...); +} + +template<typename... Args> +inline void debug(const char *fmt, const Args &... args) +{ + default_logger_raw()->debug(fmt, args...); +} + +template<typename... Args> +inline void info(const char *fmt, const Args &... args) +{ + default_logger_raw()->info(fmt, args...); +} + +template<typename... Args> +inline void warn(const char *fmt, const Args &... args) +{ + default_logger_raw()->warn(fmt, args...); +} + +template<typename... Args> +inline void error(const char *fmt, const Args &... args) +{ + default_logger_raw()->error(fmt, args...); +} + +template<typename... Args> +inline void critical(const char *fmt, const Args &... args) +{ + default_logger_raw()->critical(fmt, args...); +} + +template<typename T> +inline void log(level::level_enum lvl, const T &msg) +{ + default_logger_raw()->log(lvl, msg); +} + +template<typename T> +inline void trace(const T &msg) +{ + default_logger_raw()->trace(msg); +} + +template<typename T> +inline void debug(const T &msg) +{ + default_logger_raw()->debug(msg); +} + +template<typename T> +inline void info(const T &msg) +{ + default_logger_raw()->info(msg); +} + +template<typename T> +inline void warn(const T &msg) +{ + default_logger_raw()->warn(msg); +} + +template<typename T> +inline void error(const T &msg) +{ + default_logger_raw()->error(msg); +} + +template<typename T> +inline void critical(const T &msg) +{ + default_logger_raw()->critical(msg); +} + +#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT +template<typename... Args> +inline void log(level::level_enum lvl, const wchar_t *fmt, const Args &... args) +{ + default_logger_raw()->log(lvl, fmt, args...); +} + +template<typename... Args> +inline void trace(const wchar_t *fmt, const Args &... args) +{ + default_logger_raw()->trace(fmt, args...); +} + +template<typename... Args> +inline void debug(const wchar_t *fmt, const Args &... args) +{ + default_logger_raw()->debug(fmt, args...); +} + +template<typename... Args> +inline void info(const wchar_t *fmt, const Args &... args) +{ + default_logger_raw()->info(fmt, args...); +} + +template<typename... Args> +inline void warn(const wchar_t *fmt, const Args &... args) +{ + default_logger_raw()->warn(fmt, args...); +} + +template<typename... Args> +inline void error(const wchar_t *fmt, const Args &... args) +{ + default_logger_raw()->error(fmt, args...); +} + +template<typename... Args> +inline void critical(const wchar_t *fmt, const Args &... args) +{ + default_logger_raw()->critical(fmt, args...); +} + +#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT + +} // namespace spdlog + +// +// enable/disable log calls at compile time according to global level. +// +// define SPDLOG_ACTIVE_LEVEL to one of those (before including spdlog.h): +// SPDLOG_LEVEL_TRACE, +// SPDLOG_LEVEL_DEBUG, +// SPDLOG_LEVEL_INFO, +// SPDLOG_LEVEL_WARN, +// SPDLOG_LEVEL_ERROR, +// SPDLOG_LEVEL_CRITICAL, +// SPDLOG_LEVEL_OFF +// + +#define SPDLOG_LOGGER_CALL(logger, level, ...) \ + if (logger->should_log(level)) \ + logger->log(spdlog::source_loc{SPDLOG_FILE_BASENAME(__FILE__), __LINE__, SPDLOG_FUNCTION}, level, __VA_ARGS__) + +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_TRACE +#define SPDLOG_LOGGER_TRACE(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::trace, __VA_ARGS__) +#define SPDLOG_TRACE(...) SPDLOG_LOGGER_TRACE(spdlog::default_logger_raw(), __VA_ARGS__) +#else +#define SPDLOG_LOGGER_TRACE(logger, ...) (void)0 +#define SPDLOG_TRACE(...) (void)0 +#endif + +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_DEBUG +#define SPDLOG_LOGGER_DEBUG(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::debug, __VA_ARGS__) +#define SPDLOG_DEBUG(...) SPDLOG_LOGGER_DEBUG(spdlog::default_logger_raw(), __VA_ARGS__) +#else +#define SPDLOG_LOGGER_DEBUG(logger, ...) (void)0 +#define SPDLOG_DEBUG(...) (void)0 +#endif + +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_INFO +#define SPDLOG_LOGGER_INFO(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::info, __VA_ARGS__) +#define SPDLOG_INFO(...) SPDLOG_LOGGER_INFO(spdlog::default_logger_raw(), __VA_ARGS__) +#else +#define SPDLOG_LOGGER_INFO(logger, ...) (void)0 +#define SPDLOG_INFO(...) (void)0 +#endif + +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_WARN +#define SPDLOG_LOGGER_WARN(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::warn, __VA_ARGS__) +#define SPDLOG_WARN(...) SPDLOG_LOGGER_WARN(spdlog::default_logger_raw(), __VA_ARGS__) +#else +#define SPDLOG_LOGGER_WARN(logger, ...) (void)0 +#define SPDLOG_WARN(...) (void)0 +#endif + +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_ERROR +#define SPDLOG_LOGGER_ERROR(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::err, __VA_ARGS__) +#define SPDLOG_ERROR(...) SPDLOG_LOGGER_ERROR(spdlog::default_logger_raw(), __VA_ARGS__) +#else +#define SPDLOG_LOGGER_ERROR(logger, ...) (void)0 +#define SPDLOG_ERROR(...) (void)0 +#endif + +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_CRITICAL +#define SPDLOG_LOGGER_CRITICAL(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::critical, __VA_ARGS__) +#define SPDLOG_CRITICAL(...) SPDLOG_LOGGER_CRITICAL(spdlog::default_logger_raw(), __VA_ARGS__) +#else +#define SPDLOG_LOGGER_CRITICAL(logger, ...) (void)0 +#define SPDLOG_CRITICAL(...) (void)0 +#endif + +#endif // SPDLOG_H diff --git a/matching/include/spdlog/tweakme.h b/matching/include/spdlog/tweakme.h new file mode 100644 index 0000000..b3b71e4 --- /dev/null +++ b/matching/include/spdlog/tweakme.h @@ -0,0 +1,145 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +/////////////////////////////////////////////////////////////////////////////// +// +// Edit this file to squeeze more performance, and to customize supported +// features +// +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Under Linux, the much faster CLOCK_REALTIME_COARSE clock can be used. +// This clock is less accurate - can be off by dozens of millis - depending on +// the kernel HZ. +// Uncomment to use it instead of the regular clock. +// +// #define SPDLOG_CLOCK_COARSE +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment if date/time logging is not needed and never appear in the log +// pattern. +// This will prevent spdlog from querying the clock on each log call. +// +// WARNING: If the log pattern contains any date/time while this flag is on, the +// result is undefined. +// You must set new pattern(spdlog::set_pattern(..") without any +// date/time in it +// +// #define SPDLOG_NO_DATETIME +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment if thread id logging is not needed (i.e. no %t in the log pattern). +// This will prevent spdlog from querying the thread id on each log call. +// +// WARNING: If the log pattern contains thread id (i.e, %t) while this flag is +// on, the result is undefined. +// +// #define SPDLOG_NO_THREAD_ID +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to prevent spdlog from using thread local storage. +// +// WARNING: if your program forks, UNCOMMENT this flag to prevent undefined +// thread ids in the children logs. +// +// #define SPDLOG_NO_TLS +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment if logger name logging is not needed. +// This will prevent spdlog from copying the logger name on each log call. +// +// #define SPDLOG_NO_NAME +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to enable the SPDLOG_DEBUG/SPDLOG_TRACE macros. +// +// #define SPDLOG_DEBUG_ON +// #define SPDLOG_TRACE_ON +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to avoid spdlog's usage of atomic log levels +// Use only if your code never modifies a logger's log levels concurrently by +// different threads. +// +// #define SPDLOG_NO_ATOMIC_LEVELS +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to enable usage of wchar_t for file names on Windows. +// +// #define SPDLOG_WCHAR_FILENAMES +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to override default eol ("\n" or "\r\n" under Linux/Windows) +// +// #define SPDLOG_EOL ";-)\n" +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to use your own copy of the fmt library instead of spdlog's copy. +// In this case spdlog will try to include <fmt/format.h> so set your -I flag +// accordingly. +// +// #define SPDLOG_FMT_EXTERNAL +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to enable wchar_t support (convert to utf8) +// +// #define SPDLOG_WCHAR_TO_UTF8_SUPPORT +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to prevent child processes from inheriting log file descriptors +// +// #define SPDLOG_PREVENT_CHILD_FD +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to enable message counting feature. +// Use the %i in the logger pattern to display log message sequence id. +// +// #define SPDLOG_ENABLE_MESSAGE_COUNTER +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to customize level names (e.g. "MT TRACE") +// +// #define SPDLOG_LEVEL_NAMES { "MY TRACE", "MY DEBUG", "MY INFO", "MY WARNING", +// "MY ERROR", "MY CRITICAL", "OFF" } +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to disable default logger creation. +// This might save some (very) small initialization time if no default logger is needed. +// +// #define SPDLOG_DISABLE_DEFAULT_LOGGER +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment and set to compile time level with zero cost (default is INFO). +// Macros like SPDLOG_DEBUG(..), SPDLOG_INFO(..) will expand to empty statements if not enabled +// +// #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment (and change if desired) macro to use for function names. +// This is compiler dependent. +// __PRETTY_FUNCTION__ might be nicer in clang/gcc, and __FUNCTION__ in msvc. +// Defaults to __FUNCTION__ (should work on all compilers) if not defined. +// +// #define SPDLOG_FUNCTION __PRETTY_FUNCTION__ +///////////////////////////////////////////////////////////////////////////////
\ No newline at end of file diff --git a/matching/include/spdlog/version.h b/matching/include/spdlog/version.h new file mode 100644 index 0000000..87a68bd --- /dev/null +++ b/matching/include/spdlog/version.h @@ -0,0 +1,12 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#define SPDLOG_VER_MAJOR 1 +#define SPDLOG_VER_MINOR 3 +#define SPDLOG_VER_PATCH 1 + +#define SPDLOG_VERSION (SPDLOG_VER_MAJOR * 10000 + SPDLOG_VER_MINOR * 100 + SPDLOG_VER_PATCH) diff --git a/matching/tests/prism_1.bif b/matching/tests/prism_1.bif new file mode 100644 index 0000000..b37e807 --- /dev/null +++ b/matching/tests/prism_1.bif @@ -0,0 +1,28 @@ +bifiltration_phat_like +26 +0 0 0 +0 0 0 +0 0 0 +0 0 0 +0 0 0 +0 0 0 +1 1 0 1 0 +1 1 0 2 1 +1 0 0 3 1 +1 0 1 5 4 +1 0 0 4 1 +1 0 0 3 0 +1 0 0 5 0 +1 0 0 4 2 +1 0 0 5 2 +1 0 1 4 3 +1 1 0 2 0 +1 0 1 5 3 +2 1 1 13 10 7 +2 1 1 9 14 13 +2 1 1 8 11 6 +2 1 1 15 10 8 +2 1 1 14 12 16 +2 1 1 17 12 11 +2 4 0 7 16 6 +2 0 4 9 17 15 diff --git a/matching/tests/prism_2.bif b/matching/tests/prism_2.bif new file mode 100644 index 0000000..49885e6 --- /dev/null +++ b/matching/tests/prism_2.bif @@ -0,0 +1,29 @@ +bifiltration_phat_like +27 +0 0 0 +0 0 0 +0 0 0 +0 0 0 +0 0 0 +0 0 0 +1 0 0 2 1 +1 0 0 1 0 +1 0 0 5 3 +1 0 0 3 1 +1 0 0 5 4 +1 0 0 2 0 +1 0 0 4 1 +1 0 0 3 2 +1 0 0 5 2 +1 0 0 4 3 +1 0 0 4 2 +1 0 0 3 0 +2 0 0 16 12 6 +2 0 0 10 14 16 +2 0 0 9 17 7 +2 0 0 15 12 9 +2 0 0 13 17 11 +2 0 0 8 14 13 +2 4 0 6 11 7 +2 0 4 10 8 15 +2 3 3 15 16 13 diff --git a/matching/tests/test_bifiltration.cpp b/matching/tests/test_bifiltration.cpp new file mode 100644 index 0000000..742dab8 --- /dev/null +++ b/matching/tests/test_bifiltration.cpp @@ -0,0 +1,36 @@ +#include "catch/catch.hpp" + +#include <sstream> +#include <iostream> + +#include "common_util.h" +#include "box.h" +#include "bifiltration.h" + +using namespace md; + +//TEST_CASE("Small check", "[bifiltration][dim2]") +//{ +// Bifiltration bif("/home/narn/code/matching_distance/code/src/tests/test_bifiltration_full_triangle_phat_like.txt", BifiltrationFormat::phat_like); +// auto simplices = bif.simplices(); +// bif.sanity_check(); +// +// REQUIRE( simplices.size() == 7 ); +// +// REQUIRE( simplices[0].dim() == 0 ); +// REQUIRE( simplices[1].dim() == 0 ); +// REQUIRE( simplices[2].dim() == 0 ); +// REQUIRE( simplices[3].dim() == 1 ); +// REQUIRE( simplices[4].dim() == 1 ); +// REQUIRE( simplices[5].dim() == 1 ); +// REQUIRE( simplices[6].dim() == 2); +// +// REQUIRE( simplices[0].position() == Point(0, 0)); +// REQUIRE( simplices[1].position() == Point(0, 0)); +// REQUIRE( simplices[2].position() == Point(0, 0)); +// REQUIRE( simplices[3].position() == Point(3, 1)); +// REQUIRE( simplices[6].position() == Point(30, 40)); +// +// Line line_1(Line::pi / 2.0, 0.0); +// auto dgm = bif.slice_diagram(line_1); +//} diff --git a/matching/tests/test_bifiltration_1.txt b/matching/tests/test_bifiltration_1.txt new file mode 120000 index 0000000..ddd23e9 --- /dev/null +++ b/matching/tests/test_bifiltration_1.txt @@ -0,0 +1 @@ +../../data/test_bifiltration_1.txt
\ No newline at end of file diff --git a/matching/tests/test_bifiltration_full_triangle_rene.txt b/matching/tests/test_bifiltration_full_triangle_rene.txt new file mode 120000 index 0000000..47f49fd --- /dev/null +++ b/matching/tests/test_bifiltration_full_triangle_rene.txt @@ -0,0 +1 @@ +../../data/test_bifiltration_full_triangle_rene.txt
\ No newline at end of file diff --git a/matching/tests/test_common.cpp b/matching/tests/test_common.cpp new file mode 100644 index 0000000..9079a56 --- /dev/null +++ b/matching/tests/test_common.cpp @@ -0,0 +1,156 @@ +#include "catch/catch.hpp" + +#include <sstream> +#include <iostream> +#include <string> + +#include "common_util.h" +#include "simplex.h" +#include "matching_distance.h" + +//using namespace md; +using Real = double; +using Point = md::Point<Real>; +using Bifiltration = md::Bifiltration<Real>; +using BifiltrationProxy = md::BifiltrationProxy<Real>; +using CalculationParams = md::CalculationParams<Real>; +using CellWithValue = md::CellWithValue<Real>; +using DualPoint = md::DualPoint<Real>; +using DualBox = md::DualBox<Real>; +using Simplex = md::Simplex<Real>; +using AbstractSimplex = md::AbstractSimplex; +using BoundStrategy = md::BoundStrategy; +using TraverseStrategy = md::TraverseStrategy; +using AxisType = md::AxisType; +using AngleType = md::AngleType; +using ValuePoint = md::ValuePoint; +using Column = md::Column; + + +TEST_CASE("AbstractSimplex", "[abstract_simplex]") +{ + AbstractSimplex as; + REQUIRE(as.dim() == -1); + + as.push_back(1); + REQUIRE(as.dim() == 0); + REQUIRE(as.facets().size() == 0); + + as.push_back(0); + REQUIRE(as.dim() == 1); + REQUIRE(as.facets().size() == 2); + REQUIRE(as.facets()[0].dim() == 0); + REQUIRE(as.facets()[1].dim() == 0); + +} + +TEST_CASE("Vertical line", "[vertical_line]") +{ + // line x = 1 + DualPoint l_vertical(AxisType::x_type, AngleType::steep, 0, 1); + + REQUIRE(l_vertical.is_vertical()); + REQUIRE(l_vertical.is_steep()); + + Point p_1(0.5, 0.5); + Point p_2(1.5, 0.5); + Point p_3(1.5, 1.5); + Point p_4(0.5, 1.5); + Point p_5(1, 10); + + REQUIRE(l_vertical.x_from_y(10) == 1); + REQUIRE(l_vertical.x_from_y(-10) == 1); + REQUIRE(l_vertical.x_from_y(0) == 1); + + REQUIRE(not l_vertical.contains(p_1)); + REQUIRE(not l_vertical.contains(p_2)); + REQUIRE(not l_vertical.contains(p_3)); + REQUIRE(not l_vertical.contains(p_4)); + REQUIRE(l_vertical.contains(p_5)); + + REQUIRE(l_vertical.goes_below(p_1)); + REQUIRE(not l_vertical.goes_below(p_2)); + REQUIRE(not l_vertical.goes_below(p_3)); + REQUIRE(l_vertical.goes_below(p_4)); + + REQUIRE(not l_vertical.goes_above(p_1)); + REQUIRE(l_vertical.goes_above(p_2)); + REQUIRE(l_vertical.goes_above(p_3)); + REQUIRE(not l_vertical.goes_above(p_4)); + +} + +TEST_CASE("Horizontal line", "[horizontal_line]") +{ + // line y = 1 + DualPoint l_horizontal(AxisType::y_type, AngleType::flat, 0, 1); + + REQUIRE(l_horizontal.is_horizontal()); + REQUIRE(l_horizontal.is_flat()); + REQUIRE(l_horizontal.y_slope() == 0); + REQUIRE(l_horizontal.y_intercept() == 1); + + Point p_1(0.5, 0.5); + Point p_2(1.5, 0.5); + Point p_3(1.5, 1.5); + Point p_4(0.5, 1.5); + Point p_5(2, 1); + + REQUIRE((not l_horizontal.contains(p_1) and + not l_horizontal.contains(p_2) and + not l_horizontal.contains(p_3) and + not l_horizontal.contains(p_4) and + l_horizontal.contains(p_5))); + + REQUIRE(not l_horizontal.goes_below(p_1)); + REQUIRE(not l_horizontal.goes_below(p_2)); + REQUIRE(l_horizontal.goes_below(p_3)); + REQUIRE(l_horizontal.goes_below(p_4)); + REQUIRE(l_horizontal.goes_below(p_5)); + + REQUIRE(l_horizontal.goes_above(p_1)); + REQUIRE(l_horizontal.goes_above(p_2)); + REQUIRE(not l_horizontal.goes_above(p_3)); + REQUIRE(not l_horizontal.goes_above(p_4)); + REQUIRE(l_horizontal.goes_above(p_5)); +} + +TEST_CASE("Flat Line with positive slope", "[flat_line]") +{ + // line y = x / 2 + 1 + DualPoint l_flat(AxisType::y_type, AngleType::flat, 0.5, 1); + + REQUIRE(not l_flat.is_horizontal()); + REQUIRE(l_flat.is_flat()); + REQUIRE(l_flat.y_slope() == 0.5); + REQUIRE(l_flat.y_intercept() == 1); + + REQUIRE(l_flat.y_from_x(0) == 1); + REQUIRE(l_flat.y_from_x(1) == 1.5); + REQUIRE(l_flat.y_from_x(2) == 2); + + Point p_1(3, 2); + Point p_2(-2, 0.01); + Point p_3(0, 1.25); + Point p_4(6, 4.5); + Point p_5(2, 2); + + REQUIRE((not l_flat.contains(p_1) and + not l_flat.contains(p_2) and + not l_flat.contains(p_3) and + not l_flat.contains(p_4) and + l_flat.contains(p_5))); + + REQUIRE(not l_flat.goes_below(p_1)); + REQUIRE(l_flat.goes_below(p_2)); + REQUIRE(l_flat.goes_below(p_3)); + REQUIRE(l_flat.goes_below(p_4)); + REQUIRE(l_flat.goes_below(p_5)); + + REQUIRE(l_flat.goes_above(p_1)); + REQUIRE(not l_flat.goes_above(p_2)); + REQUIRE(not l_flat.goes_above(p_3)); + REQUIRE(not l_flat.goes_above(p_4)); + REQUIRE(l_flat.goes_above(p_5)); + +} diff --git a/matching/tests/test_list.txt b/matching/tests/test_list.txt new file mode 100644 index 0000000..1984606 --- /dev/null +++ b/matching/tests/test_list.txt @@ -0,0 +1 @@ +prism_lesnick_1.bif prism_lesnick_2.bif 1.0 diff --git a/matching/tests/test_matching_distance.cpp b/matching/tests/test_matching_distance.cpp new file mode 100644 index 0000000..aa08cfe --- /dev/null +++ b/matching/tests/test_matching_distance.cpp @@ -0,0 +1,168 @@ +#include "catch/catch.hpp" + +#include <sstream> +#include <iostream> +#include <string> + +#include "spdlog/spdlog.h" +#include "spdlog/fmt/ostr.h" + +#define MD_TEST_CODE + +#include "common_util.h" +#include "simplex.h" +#include "matching_distance.h" + +using Real = double; +using Point = md::Point<Real>; +using Bifiltration = md::Bifiltration<Real>; +using BifiltrationProxy = md::BifiltrationProxy<Real>; +using CalculationParams = md::CalculationParams<Real>; +using CellWithValue = md::CellWithValue<Real>; +using DualPoint = md::DualPoint<Real>; +using DualBox = md::DualBox<Real>; +using Simplex = md::Simplex<Real>; +using AbstractSimplex = md::AbstractSimplex; +using BoundStrategy = md::BoundStrategy; +using TraverseStrategy = md::TraverseStrategy; +using AxisType = md::AxisType; +using AngleType = md::AngleType; +using ValuePoint = md::ValuePoint; +using Column = md::Column; + +using md::k_corner_vps; + +namespace spd = spdlog; + +TEST_CASE("Different bounds", "[bounds]") +{ + std::vector<Simplex> simplices; + std::vector<Point> points; + + Real max_x = 10; + Real max_y = 20; + + int simplex_id = 0; + for(int i = 0; i <= max_x; ++i) { + for(int j = 0; j <= max_y; ++j) { + Point p(i, j); + simplices.emplace_back(simplex_id++, p, 0, Column()); + points.push_back(p); + } + } + + Bifiltration bif_a(simplices.begin(), simplices.end()); + Bifiltration bif_b(simplices.begin(), simplices.end()); + + CalculationParams params; + params.initialization_depth = 2; + + BifiltrationProxy bifp_a(bif_a, params.dim); + BifiltrationProxy bifp_b(bif_b, params.dim); + + md::DistanceCalculator<Real, BifiltrationProxy> calc(bifp_a, bifp_b, params); + +// REQUIRE(calc.max_x_ == Approx(max_x)); +// REQUIRE(calc.max_y_ == Approx(max_y)); + + std::vector<DualBox> boxes; + + for(CellWithValue c : calc.get_refined_grid(5, false, false)) { + boxes.push_back(c.dual_box()); + } + + // fill in boxes and points + + for(DualBox db : boxes) { + Real local_bound = calc.get_local_dual_bound(db); + Real local_bound_refined = calc.get_local_refined_bound(db); + REQUIRE(local_bound >= local_bound_refined); + for(Point p : points) { + for(ValuePoint vp_a : k_corner_vps) { + CellWithValue dual_cell(db, 1); + DualPoint corner_a = dual_cell.value_point(vp_a); + Real wp_a = corner_a.weighted_push(p); + dual_cell.set_value_at(vp_a, wp_a); + Real point_bound = calc.get_max_displacement_single_point(dual_cell, vp_a, p); + for(ValuePoint vp_b : k_corner_vps) { + if (vp_b <= vp_a) + continue; + DualPoint corner_b = dual_cell.value_point(vp_b); + Real wp_b = corner_b.weighted_push(p); + Real diff = fabs(wp_a - wp_b); + if (not(point_bound <= Approx(local_bound_refined))) { + std::cerr << "ERROR point: " << p << ", box = " << db << ", point bound = " << point_bound + << ", refined local = " << local_bound_refined << std::endl; + spd::set_level(spd::level::debug); + calc.get_max_displacement_single_point(dual_cell, vp_a, p); + calc.get_local_refined_bound(db); + spd::set_level(spd::level::info); + } + + REQUIRE(point_bound <= Approx(local_bound_refined)); + REQUIRE(diff <= Approx(point_bound)); + REQUIRE(diff <= Approx(local_bound_refined)); + } + + for(DualPoint l_random : db.random_points(100)) { + Real wp_random = l_random.weighted_push(p); + Real diff = fabs(wp_a - wp_random); + if (not(diff <= Approx(point_bound))) { + if (db.critical_points(p).size() > 4) { + std::cerr << "ERROR interesting case" << std::endl; + } else { + std::cerr << "ERROR boring case" << std::endl; + } + spd::set_level(spd::level::debug); + l_random.weighted_push(p); + spd::set_level(spd::level::info); + std::cerr << "ERROR point: " << p << ", box = " << db << ", point bound = " << point_bound + << ", refined local = " << local_bound_refined; + std::cerr << ", random_dual_point = " << l_random << ", wp_random = " << wp_random + << ", diff = " << diff << std::endl; + } + REQUIRE(diff <= Approx(point_bound)); + } + } + } + } +} + +TEST_CASE("Bifiltrations from file", "[matching_distance][small_example][lesnick]") +{ + std::string fname_a, fname_b; + + fname_a = "../tests/prism_1.bif"; + fname_b = "../tests/prism_2.bif"; + + Bifiltration bif_a(fname_a); + Bifiltration bif_b(fname_b); + + CalculationParams params; + + std::vector<BoundStrategy> bound_strategies {BoundStrategy::local_combined, + BoundStrategy::local_dual_bound_refined}; + + std::vector<TraverseStrategy> traverse_strategies {TraverseStrategy::breadth_first, TraverseStrategy::depth_first}; + + std::vector<double> scaling_factors {10, 1.0}; + + for(auto bs : bound_strategies) { + for(auto ts : traverse_strategies) { + for(double lambda : scaling_factors) { + Bifiltration bif_a_copy(bif_a); + Bifiltration bif_b_copy(bif_b); + bif_a_copy.scale(lambda); + bif_b_copy.scale(lambda); + params.bound_strategy = bs; + params.traverse_strategy = ts; + params.max_depth = 7; + params.delta = 0.1; + params.dim = 1; + Real answer = matching_distance(bif_a_copy, bif_b_copy, params); + Real correct_answer = lambda * 1.0; + REQUIRE(fabs(answer - correct_answer) / correct_answer < params.delta); + } + } + } +} diff --git a/matching/tests/test_module.cpp b/matching/tests/test_module.cpp new file mode 100644 index 0000000..0f239d5 --- /dev/null +++ b/matching/tests/test_module.cpp @@ -0,0 +1,114 @@ +#include "catch/catch.hpp" + +#include <sstream> +#include <iostream> +#include <string> + +#include "spdlog/spdlog.h" +#include "spdlog/fmt/ostr.h" + +#define MD_TEST_CODE + +#include "common_util.h" +#include "persistence_module.h" +#include "matching_distance.h" + +using Real = double; +using Point = md::Point<Real>; +using Bifiltration = md::Bifiltration<Real>; +using BifiltrationProxy = md::BifiltrationProxy<Real>; +using CalculationParams = md::CalculationParams<Real>; +using CellWithValue = md::CellWithValue<Real>; +using DualPoint = md::DualPoint<Real>; +using DualBox = md::DualBox<Real>; +using BoundStrategy = md::BoundStrategy; +using TraverseStrategy = md::TraverseStrategy; +using AxisType = md::AxisType; +using AngleType = md::AngleType; +using ValuePoint = md::ValuePoint; +using Column = md::Column; +using PointVec = md::PointVec<Real>; +using Module = md::ModulePresentation<Real>; +using Relation = Module::Relation; +using RelationVec = Module::RelVec; +using IndexVec = md::IndexVec; + +using md::k_corner_vps; + +namespace spd = spdlog; + +TEST_CASE("Module projection", "[module][projection]") +{ + PointVec gens; + gens.emplace_back(1, 1); // A + gens.emplace_back(2, 3); // B + gens.emplace_back(3, 2); // C + + RelationVec rels; + + Point rel_x_position { 3.98, 2.47 }; + IndexVec rel_x_components { 0, 2 }; // X: A + C = 0 + + Point rel_y_position { 2.5, 4 }; + IndexVec rel_y_components { 0, 1 }; // Y: A + B = 0 + + Point rel_z_position { 5, 5 }; + IndexVec rel_z_components { 1 }; // Z: B = 0 + + + rels.emplace_back(rel_x_position, rel_x_components); + rels.emplace_back(rel_y_position, rel_y_components); + rels.emplace_back(rel_z_position, rel_z_components); + + Module module { gens, rels }; + + { + DualPoint slice_1(AxisType::x_type, AngleType::flat, 6.0 / 7.0, 3.0); + std::vector<Real> gen_ps_1, rel_ps_1; + phat::boundary_matrix<> matr_1; + + module.get_slice_projection_matrix(slice_1, matr_1, gen_ps_1, rel_ps_1); + + phat::column c_1_0, c_1_1, c_1_2; + + matr_1.get_col(0, c_1_0); + matr_1.get_col(1, c_1_1); + matr_1.get_col(2, c_1_2); + + phat::column c_1_0_correct { 0, 1}; + phat::column c_1_1_correct { 0, 2}; + phat::column c_1_2_correct { 2 }; + + REQUIRE(c_1_0 == c_1_0_correct); + REQUIRE(c_1_1 == c_1_1_correct); + REQUIRE(c_1_2 == c_1_2_correct); + } + + { + + DualPoint slice_2(AxisType::y_type, AngleType::flat, 2.0 / 9.0, 5.0); + std::vector<Real> gen_ps_2, rel_ps_2; + phat::boundary_matrix<> matr_2; + + module.get_slice_projection_matrix(slice_2, matr_2, gen_ps_2, rel_ps_2); + + phat::column c_2_0, c_2_1, c_2_2; + + matr_2.get_col(0, c_2_0); + matr_2.get_col(1, c_2_1); + matr_2.get_col(2, c_2_2); + + phat::column c_2_0_correct { 0, 1}; + phat::column c_2_1_correct { 0, 2}; + phat::column c_2_2_correct { 1 }; + + //std::cerr << "gen_ps_2: " << md::container_to_string(gen_ps_2) << std::endl; + //std::cerr << "rel_ps_2: " << md::container_to_string(rel_ps_2) << std::endl; + + REQUIRE(c_2_0 == c_2_0_correct); + REQUIRE(c_2_1 == c_2_1_correct); + REQUIRE(c_2_2 == c_2_2_correct); + } + + +} diff --git a/matching/tests/tests_main.cpp b/matching/tests/tests_main.cpp new file mode 100644 index 0000000..1c77b13 --- /dev/null +++ b/matching/tests/tests_main.cpp @@ -0,0 +1,2 @@ +#define CATCH_CONFIG_MAIN +#include "catch/catch.hpp" diff --git a/geom_matching/wasserstein/CMakeLists.txt b/wasserstein/CMakeLists.txt index dea4550..dea4550 100644 --- a/geom_matching/wasserstein/CMakeLists.txt +++ b/wasserstein/CMakeLists.txt diff --git a/geom_matching/README b/wasserstein/README index 5228d63..5228d63 100644 --- a/geom_matching/README +++ b/wasserstein/README diff --git a/geom_matching/wasserstein/example/wasserstein_dist.cpp b/wasserstein/example/wasserstein_dist.cpp index cbe83e2..cbe83e2 100644 --- a/geom_matching/wasserstein/example/wasserstein_dist.cpp +++ b/wasserstein/example/wasserstein_dist.cpp diff --git a/geom_matching/wasserstein/example/wasserstein_dist_dipha.cpp b/wasserstein/example/wasserstein_dist_dipha.cpp index 2ed9c2c..2ed9c2c 100644 --- a/geom_matching/wasserstein/example/wasserstein_dist_dipha.cpp +++ b/wasserstein/example/wasserstein_dist_dipha.cpp diff --git a/geom_matching/wasserstein/example/wasserstein_dist_point_cloud.cpp b/wasserstein/example/wasserstein_dist_point_cloud.cpp index ab7ff4f..ab7ff4f 100644 --- a/geom_matching/wasserstein/example/wasserstein_dist_point_cloud.cpp +++ b/wasserstein/example/wasserstein_dist_point_cloud.cpp diff --git a/geom_matching/wasserstein/include/auction_oracle.h b/wasserstein/include/auction_oracle.h index d285a1f..d285a1f 100644 --- a/geom_matching/wasserstein/include/auction_oracle.h +++ b/wasserstein/include/auction_oracle.h diff --git a/geom_matching/wasserstein/include/auction_oracle_base.h b/wasserstein/include/auction_oracle_base.h index 08eaf00..08eaf00 100644 --- a/geom_matching/wasserstein/include/auction_oracle_base.h +++ b/wasserstein/include/auction_oracle_base.h diff --git a/geom_matching/wasserstein/include/auction_oracle_base.hpp b/wasserstein/include/auction_oracle_base.hpp index b74c7fb..b74c7fb 100644 --- a/geom_matching/wasserstein/include/auction_oracle_base.hpp +++ b/wasserstein/include/auction_oracle_base.hpp diff --git a/geom_matching/wasserstein/include/auction_oracle_kdtree_pure_geom.h b/wasserstein/include/auction_oracle_kdtree_pure_geom.h index 096583e..096583e 100644 --- a/geom_matching/wasserstein/include/auction_oracle_kdtree_pure_geom.h +++ b/wasserstein/include/auction_oracle_kdtree_pure_geom.h diff --git a/geom_matching/wasserstein/include/auction_oracle_kdtree_pure_geom.hpp b/wasserstein/include/auction_oracle_kdtree_pure_geom.hpp index eaf54cf..eaf54cf 100644 --- a/geom_matching/wasserstein/include/auction_oracle_kdtree_pure_geom.hpp +++ b/wasserstein/include/auction_oracle_kdtree_pure_geom.hpp diff --git a/geom_matching/wasserstein/include/auction_oracle_kdtree_restricted.h b/wasserstein/include/auction_oracle_kdtree_restricted.h index 1999147..1999147 100644 --- a/geom_matching/wasserstein/include/auction_oracle_kdtree_restricted.h +++ b/wasserstein/include/auction_oracle_kdtree_restricted.h diff --git a/geom_matching/wasserstein/include/auction_oracle_kdtree_restricted.hpp b/wasserstein/include/auction_oracle_kdtree_restricted.hpp index 8613ee1..8613ee1 100644 --- a/geom_matching/wasserstein/include/auction_oracle_kdtree_restricted.hpp +++ b/wasserstein/include/auction_oracle_kdtree_restricted.hpp diff --git a/geom_matching/wasserstein/include/auction_oracle_kdtree_single_diag.h b/wasserstein/include/auction_oracle_kdtree_single_diag.h index 9192993..9192993 100644 --- a/geom_matching/wasserstein/include/auction_oracle_kdtree_single_diag.h +++ b/wasserstein/include/auction_oracle_kdtree_single_diag.h diff --git a/geom_matching/wasserstein/include/auction_oracle_kdtree_single_diag.hpp b/wasserstein/include/auction_oracle_kdtree_single_diag.hpp index 42677ab..42677ab 100644 --- a/geom_matching/wasserstein/include/auction_oracle_kdtree_single_diag.hpp +++ b/wasserstein/include/auction_oracle_kdtree_single_diag.hpp diff --git a/geom_matching/wasserstein/include/auction_oracle_lazy_heap.h b/wasserstein/include/auction_oracle_lazy_heap.h index 8b37421..8b37421 100644 --- a/geom_matching/wasserstein/include/auction_oracle_lazy_heap.h +++ b/wasserstein/include/auction_oracle_lazy_heap.h diff --git a/geom_matching/wasserstein/include/auction_oracle_lazy_heap.hpp b/wasserstein/include/auction_oracle_lazy_heap.hpp index d179b3d..d179b3d 100644 --- a/geom_matching/wasserstein/include/auction_oracle_lazy_heap.hpp +++ b/wasserstein/include/auction_oracle_lazy_heap.hpp diff --git a/geom_matching/wasserstein/include/auction_oracle_stupid_sparse_restricted.h b/wasserstein/include/auction_oracle_stupid_sparse_restricted.h index c932396..c932396 100644 --- a/geom_matching/wasserstein/include/auction_oracle_stupid_sparse_restricted.h +++ b/wasserstein/include/auction_oracle_stupid_sparse_restricted.h diff --git a/geom_matching/wasserstein/include/auction_oracle_stupid_sparse_restricted.hpp b/wasserstein/include/auction_oracle_stupid_sparse_restricted.hpp index 8f4504d..8f4504d 100644 --- a/geom_matching/wasserstein/include/auction_oracle_stupid_sparse_restricted.hpp +++ b/wasserstein/include/auction_oracle_stupid_sparse_restricted.hpp diff --git a/geom_matching/wasserstein/include/auction_runner_fr.h b/wasserstein/include/auction_runner_fr.h index 1abca20..1abca20 100644 --- a/geom_matching/wasserstein/include/auction_runner_fr.h +++ b/wasserstein/include/auction_runner_fr.h diff --git a/geom_matching/wasserstein/include/auction_runner_fr.hpp b/wasserstein/include/auction_runner_fr.hpp index 07c1459..07c1459 100644 --- a/geom_matching/wasserstein/include/auction_runner_fr.hpp +++ b/wasserstein/include/auction_runner_fr.hpp diff --git a/geom_matching/wasserstein/include/auction_runner_gs.h b/wasserstein/include/auction_runner_gs.h index f8b5a8b..f8b5a8b 100644 --- a/geom_matching/wasserstein/include/auction_runner_gs.h +++ b/wasserstein/include/auction_runner_gs.h diff --git a/geom_matching/wasserstein/include/auction_runner_gs.hpp b/wasserstein/include/auction_runner_gs.hpp index 4ef94db..4ef94db 100644 --- a/geom_matching/wasserstein/include/auction_runner_gs.hpp +++ b/wasserstein/include/auction_runner_gs.hpp diff --git a/geom_matching/wasserstein/include/auction_runner_gs_single_diag.h b/wasserstein/include/auction_runner_gs_single_diag.h index f32fbbc..f32fbbc 100644 --- a/geom_matching/wasserstein/include/auction_runner_gs_single_diag.h +++ b/wasserstein/include/auction_runner_gs_single_diag.h diff --git a/geom_matching/wasserstein/include/auction_runner_gs_single_diag.hpp b/wasserstein/include/auction_runner_gs_single_diag.hpp index a3c401e..a3c401e 100644 --- a/geom_matching/wasserstein/include/auction_runner_gs_single_diag.hpp +++ b/wasserstein/include/auction_runner_gs_single_diag.hpp diff --git a/geom_matching/wasserstein/include/auction_runner_jac.h b/wasserstein/include/auction_runner_jac.h index 252ca32..252ca32 100644 --- a/geom_matching/wasserstein/include/auction_runner_jac.h +++ b/wasserstein/include/auction_runner_jac.h diff --git a/geom_matching/wasserstein/include/auction_runner_jac.hpp b/wasserstein/include/auction_runner_jac.hpp index e623f4a..e623f4a 100644 --- a/geom_matching/wasserstein/include/auction_runner_jac.hpp +++ b/wasserstein/include/auction_runner_jac.hpp diff --git a/geom_matching/wasserstein/include/basic_defs_ws.h b/wasserstein/include/basic_defs_ws.h index 1712ccf..1712ccf 100644 --- a/geom_matching/wasserstein/include/basic_defs_ws.h +++ b/wasserstein/include/basic_defs_ws.h diff --git a/geom_matching/wasserstein/include/basic_defs_ws.hpp b/wasserstein/include/basic_defs_ws.hpp index a1153af..a1153af 100644 --- a/geom_matching/wasserstein/include/basic_defs_ws.hpp +++ b/wasserstein/include/basic_defs_ws.hpp diff --git a/geom_matching/wasserstein/include/catch/catch.hpp b/wasserstein/include/catch/catch.hpp index f7681f4..f7681f4 100644 --- a/geom_matching/wasserstein/include/catch/catch.hpp +++ b/wasserstein/include/catch/catch.hpp diff --git a/geom_matching/wasserstein/include/def_debug_ws.h b/wasserstein/include/def_debug_ws.h index 791ce1d..791ce1d 100644 --- a/geom_matching/wasserstein/include/def_debug_ws.h +++ b/wasserstein/include/def_debug_ws.h diff --git a/geom_matching/wasserstein/include/diagonal_heap.h b/wasserstein/include/diagonal_heap.h index 3b3c8bc..3b3c8bc 100644 --- a/geom_matching/wasserstein/include/diagonal_heap.h +++ b/wasserstein/include/diagonal_heap.h diff --git a/geom_matching/wasserstein/include/diagram_reader.h b/wasserstein/include/diagram_reader.h index b52fcbd..b52fcbd 100644 --- a/geom_matching/wasserstein/include/diagram_reader.h +++ b/wasserstein/include/diagram_reader.h diff --git a/geom_matching/wasserstein/include/dnn/geometry/euclidean-dynamic.h b/wasserstein/include/dnn/geometry/euclidean-dynamic.h index b003906..b003906 100644 --- a/geom_matching/wasserstein/include/dnn/geometry/euclidean-dynamic.h +++ b/wasserstein/include/dnn/geometry/euclidean-dynamic.h diff --git a/geom_matching/wasserstein/include/dnn/geometry/euclidean-fixed.h b/wasserstein/include/dnn/geometry/euclidean-fixed.h index 3e38baf..3e38baf 100644 --- a/geom_matching/wasserstein/include/dnn/geometry/euclidean-fixed.h +++ b/wasserstein/include/dnn/geometry/euclidean-fixed.h diff --git a/geom_matching/wasserstein/include/dnn/local/kd-tree.h b/wasserstein/include/dnn/local/kd-tree.h index 8e52a5c..8e52a5c 100644 --- a/geom_matching/wasserstein/include/dnn/local/kd-tree.h +++ b/wasserstein/include/dnn/local/kd-tree.h diff --git a/geom_matching/wasserstein/include/dnn/local/kd-tree.hpp b/wasserstein/include/dnn/local/kd-tree.hpp index bdeef45..bdeef45 100644 --- a/geom_matching/wasserstein/include/dnn/local/kd-tree.hpp +++ b/wasserstein/include/dnn/local/kd-tree.hpp diff --git a/geom_matching/wasserstein/include/dnn/local/search-functors.h b/wasserstein/include/dnn/local/search-functors.h index 1419f22..1419f22 100644 --- a/geom_matching/wasserstein/include/dnn/local/search-functors.h +++ b/wasserstein/include/dnn/local/search-functors.h diff --git a/geom_matching/wasserstein/include/dnn/parallel/tbb.h b/wasserstein/include/dnn/parallel/tbb.h index 712f812..712f812 100644 --- a/geom_matching/wasserstein/include/dnn/parallel/tbb.h +++ b/wasserstein/include/dnn/parallel/tbb.h diff --git a/geom_matching/wasserstein/include/dnn/parallel/utils.h b/wasserstein/include/dnn/parallel/utils.h index 7104ec3..7104ec3 100644 --- a/geom_matching/wasserstein/include/dnn/parallel/utils.h +++ b/wasserstein/include/dnn/parallel/utils.h diff --git a/geom_matching/wasserstein/include/dnn/utils.h b/wasserstein/include/dnn/utils.h index bbce793..bbce793 100644 --- a/geom_matching/wasserstein/include/dnn/utils.h +++ b/wasserstein/include/dnn/utils.h diff --git a/geom_matching/wasserstein/include/hera_infinity.h b/wasserstein/include/hera_infinity.h index 8d86dbb..8d86dbb 100644 --- a/geom_matching/wasserstein/include/hera_infinity.h +++ b/wasserstein/include/hera_infinity.h diff --git a/geom_matching/wasserstein/include/opts/opts.h b/wasserstein/include/opts/opts.h index 74e788b..74e788b 100755 --- a/geom_matching/wasserstein/include/opts/opts.h +++ b/wasserstein/include/opts/opts.h diff --git a/geom_matching/wasserstein/include/spdlog/async_logger.h b/wasserstein/include/spdlog/async_logger.h index 9d7e08f..9d7e08f 100644 --- a/geom_matching/wasserstein/include/spdlog/async_logger.h +++ b/wasserstein/include/spdlog/async_logger.h diff --git a/geom_matching/wasserstein/include/spdlog/common.h b/wasserstein/include/spdlog/common.h index 7e352fa..7e352fa 100644 --- a/geom_matching/wasserstein/include/spdlog/common.h +++ b/wasserstein/include/spdlog/common.h diff --git a/geom_matching/wasserstein/include/spdlog/details/async_log_helper.h b/wasserstein/include/spdlog/details/async_log_helper.h index 6145dfa..6145dfa 100644 --- a/geom_matching/wasserstein/include/spdlog/details/async_log_helper.h +++ b/wasserstein/include/spdlog/details/async_log_helper.h diff --git a/geom_matching/wasserstein/include/spdlog/details/async_logger_impl.h b/wasserstein/include/spdlog/details/async_logger_impl.h index 33486c2..33486c2 100644 --- a/geom_matching/wasserstein/include/spdlog/details/async_logger_impl.h +++ b/wasserstein/include/spdlog/details/async_logger_impl.h diff --git a/geom_matching/wasserstein/include/spdlog/details/file_helper.h b/wasserstein/include/spdlog/details/file_helper.h index d0d730e..d0d730e 100644 --- a/geom_matching/wasserstein/include/spdlog/details/file_helper.h +++ b/wasserstein/include/spdlog/details/file_helper.h diff --git a/geom_matching/wasserstein/include/spdlog/details/log_msg.h b/wasserstein/include/spdlog/details/log_msg.h index 0d7ce4b..0d7ce4b 100644 --- a/geom_matching/wasserstein/include/spdlog/details/log_msg.h +++ b/wasserstein/include/spdlog/details/log_msg.h diff --git a/geom_matching/wasserstein/include/spdlog/details/logger_impl.h b/wasserstein/include/spdlog/details/logger_impl.h index 79c4ef6..79c4ef6 100644 --- a/geom_matching/wasserstein/include/spdlog/details/logger_impl.h +++ b/wasserstein/include/spdlog/details/logger_impl.h diff --git a/geom_matching/wasserstein/include/spdlog/details/mpmc_bounded_q.h b/wasserstein/include/spdlog/details/mpmc_bounded_q.h index afd4c88..afd4c88 100644 --- a/geom_matching/wasserstein/include/spdlog/details/mpmc_bounded_q.h +++ b/wasserstein/include/spdlog/details/mpmc_bounded_q.h diff --git a/geom_matching/wasserstein/include/spdlog/details/null_mutex.h b/wasserstein/include/spdlog/details/null_mutex.h index 67b0aee..67b0aee 100644 --- a/geom_matching/wasserstein/include/spdlog/details/null_mutex.h +++ b/wasserstein/include/spdlog/details/null_mutex.h diff --git a/geom_matching/wasserstein/include/spdlog/details/os.h b/wasserstein/include/spdlog/details/os.h index 735f601..735f601 100644 --- a/geom_matching/wasserstein/include/spdlog/details/os.h +++ b/wasserstein/include/spdlog/details/os.h diff --git a/geom_matching/wasserstein/include/spdlog/details/pattern_formatter_impl.h b/wasserstein/include/spdlog/details/pattern_formatter_impl.h index c1ce719..c1ce719 100644 --- a/geom_matching/wasserstein/include/spdlog/details/pattern_formatter_impl.h +++ b/wasserstein/include/spdlog/details/pattern_formatter_impl.h diff --git a/geom_matching/wasserstein/include/spdlog/details/registry.h b/wasserstein/include/spdlog/details/registry.h index b518990..b518990 100644 --- a/geom_matching/wasserstein/include/spdlog/details/registry.h +++ b/wasserstein/include/spdlog/details/registry.h diff --git a/geom_matching/wasserstein/include/spdlog/details/spdlog_impl.h b/wasserstein/include/spdlog/details/spdlog_impl.h index 7fe9ab4..7fe9ab4 100644 --- a/geom_matching/wasserstein/include/spdlog/details/spdlog_impl.h +++ b/wasserstein/include/spdlog/details/spdlog_impl.h diff --git a/geom_matching/wasserstein/include/spdlog/fmt/bundled/format.cc b/wasserstein/include/spdlog/fmt/bundled/format.cc index 2bd774e..2bd774e 100644 --- a/geom_matching/wasserstein/include/spdlog/fmt/bundled/format.cc +++ b/wasserstein/include/spdlog/fmt/bundled/format.cc diff --git a/geom_matching/wasserstein/include/spdlog/fmt/bundled/format.h b/wasserstein/include/spdlog/fmt/bundled/format.h index 64c949b..64c949b 100644 --- a/geom_matching/wasserstein/include/spdlog/fmt/bundled/format.h +++ b/wasserstein/include/spdlog/fmt/bundled/format.h diff --git a/geom_matching/wasserstein/include/spdlog/fmt/bundled/ostream.cc b/wasserstein/include/spdlog/fmt/bundled/ostream.cc index bcb67fe..bcb67fe 100644 --- a/geom_matching/wasserstein/include/spdlog/fmt/bundled/ostream.cc +++ b/wasserstein/include/spdlog/fmt/bundled/ostream.cc diff --git a/geom_matching/wasserstein/include/spdlog/fmt/bundled/ostream.h b/wasserstein/include/spdlog/fmt/bundled/ostream.h index c52646d..c52646d 100644 --- a/geom_matching/wasserstein/include/spdlog/fmt/bundled/ostream.h +++ b/wasserstein/include/spdlog/fmt/bundled/ostream.h diff --git a/geom_matching/wasserstein/include/spdlog/fmt/bundled/posix.cc b/wasserstein/include/spdlog/fmt/bundled/posix.cc index 76eb7f0..76eb7f0 100644 --- a/geom_matching/wasserstein/include/spdlog/fmt/bundled/posix.cc +++ b/wasserstein/include/spdlog/fmt/bundled/posix.cc diff --git a/geom_matching/wasserstein/include/spdlog/fmt/bundled/posix.h b/wasserstein/include/spdlog/fmt/bundled/posix.h index 859fcaa..859fcaa 100644 --- a/geom_matching/wasserstein/include/spdlog/fmt/bundled/posix.h +++ b/wasserstein/include/spdlog/fmt/bundled/posix.h diff --git a/geom_matching/wasserstein/include/spdlog/fmt/bundled/time.h b/wasserstein/include/spdlog/fmt/bundled/time.h index 10c6cfc..10c6cfc 100644 --- a/geom_matching/wasserstein/include/spdlog/fmt/bundled/time.h +++ b/wasserstein/include/spdlog/fmt/bundled/time.h diff --git a/geom_matching/wasserstein/include/spdlog/fmt/fmt.h b/wasserstein/include/spdlog/fmt/fmt.h index a4ee467..a4ee467 100644 --- a/geom_matching/wasserstein/include/spdlog/fmt/fmt.h +++ b/wasserstein/include/spdlog/fmt/fmt.h diff --git a/geom_matching/wasserstein/include/spdlog/fmt/ostr.h b/wasserstein/include/spdlog/fmt/ostr.h index 49b5e98..49b5e98 100644 --- a/geom_matching/wasserstein/include/spdlog/fmt/ostr.h +++ b/wasserstein/include/spdlog/fmt/ostr.h diff --git a/geom_matching/wasserstein/include/spdlog/formatter.h b/wasserstein/include/spdlog/formatter.h index 6bba902..6bba902 100644 --- a/geom_matching/wasserstein/include/spdlog/formatter.h +++ b/wasserstein/include/spdlog/formatter.h diff --git a/geom_matching/wasserstein/include/spdlog/logger.h b/wasserstein/include/spdlog/logger.h index 642208e..642208e 100644 --- a/geom_matching/wasserstein/include/spdlog/logger.h +++ b/wasserstein/include/spdlog/logger.h diff --git a/geom_matching/wasserstein/include/spdlog/sinks/android_sink.h b/wasserstein/include/spdlog/sinks/android_sink.h index 239f2d2..239f2d2 100644 --- a/geom_matching/wasserstein/include/spdlog/sinks/android_sink.h +++ b/wasserstein/include/spdlog/sinks/android_sink.h diff --git a/geom_matching/wasserstein/include/spdlog/sinks/ansicolor_sink.h b/wasserstein/include/spdlog/sinks/ansicolor_sink.h index 56fd3fd..56fd3fd 100644 --- a/geom_matching/wasserstein/include/spdlog/sinks/ansicolor_sink.h +++ b/wasserstein/include/spdlog/sinks/ansicolor_sink.h diff --git a/geom_matching/wasserstein/include/spdlog/sinks/base_sink.h b/wasserstein/include/spdlog/sinks/base_sink.h index 926f493..926f493 100644 --- a/geom_matching/wasserstein/include/spdlog/sinks/base_sink.h +++ b/wasserstein/include/spdlog/sinks/base_sink.h diff --git a/geom_matching/wasserstein/include/spdlog/sinks/dist_sink.h b/wasserstein/include/spdlog/sinks/dist_sink.h index 4d4b6b6..4d4b6b6 100644 --- a/geom_matching/wasserstein/include/spdlog/sinks/dist_sink.h +++ b/wasserstein/include/spdlog/sinks/dist_sink.h diff --git a/geom_matching/wasserstein/include/spdlog/sinks/file_sinks.h b/wasserstein/include/spdlog/sinks/file_sinks.h index 421acc8..421acc8 100644 --- a/geom_matching/wasserstein/include/spdlog/sinks/file_sinks.h +++ b/wasserstein/include/spdlog/sinks/file_sinks.h diff --git a/geom_matching/wasserstein/include/spdlog/sinks/msvc_sink.h b/wasserstein/include/spdlog/sinks/msvc_sink.h index 68b0255..68b0255 100644 --- a/geom_matching/wasserstein/include/spdlog/sinks/msvc_sink.h +++ b/wasserstein/include/spdlog/sinks/msvc_sink.h diff --git a/geom_matching/wasserstein/include/spdlog/sinks/null_sink.h b/wasserstein/include/spdlog/sinks/null_sink.h index ed4b5e4..ed4b5e4 100644 --- a/geom_matching/wasserstein/include/spdlog/sinks/null_sink.h +++ b/wasserstein/include/spdlog/sinks/null_sink.h diff --git a/geom_matching/wasserstein/include/spdlog/sinks/ostream_sink.h b/wasserstein/include/spdlog/sinks/ostream_sink.h index f056107..f056107 100644 --- a/geom_matching/wasserstein/include/spdlog/sinks/ostream_sink.h +++ b/wasserstein/include/spdlog/sinks/ostream_sink.h diff --git a/geom_matching/wasserstein/include/spdlog/sinks/sink.h b/wasserstein/include/spdlog/sinks/sink.h index 0974f33..0974f33 100644 --- a/geom_matching/wasserstein/include/spdlog/sinks/sink.h +++ b/wasserstein/include/spdlog/sinks/sink.h diff --git a/geom_matching/wasserstein/include/spdlog/sinks/stdout_sinks.h b/wasserstein/include/spdlog/sinks/stdout_sinks.h index dcdcc7c..dcdcc7c 100644 --- a/geom_matching/wasserstein/include/spdlog/sinks/stdout_sinks.h +++ b/wasserstein/include/spdlog/sinks/stdout_sinks.h diff --git a/geom_matching/wasserstein/include/spdlog/sinks/syslog_sink.h b/wasserstein/include/spdlog/sinks/syslog_sink.h index 0b509c4..0b509c4 100644 --- a/geom_matching/wasserstein/include/spdlog/sinks/syslog_sink.h +++ b/wasserstein/include/spdlog/sinks/syslog_sink.h diff --git a/geom_matching/wasserstein/include/spdlog/sinks/wincolor_sink.h b/wasserstein/include/spdlog/sinks/wincolor_sink.h index 6611124..6611124 100644 --- a/geom_matching/wasserstein/include/spdlog/sinks/wincolor_sink.h +++ b/wasserstein/include/spdlog/sinks/wincolor_sink.h diff --git a/geom_matching/wasserstein/include/spdlog/spdlog.h b/wasserstein/include/spdlog/spdlog.h index fb4ea59..fb4ea59 100644 --- a/geom_matching/wasserstein/include/spdlog/spdlog.h +++ b/wasserstein/include/spdlog/spdlog.h diff --git a/geom_matching/wasserstein/include/spdlog/tweakme.h b/wasserstein/include/spdlog/tweakme.h index 53f5cf7..53f5cf7 100644 --- a/geom_matching/wasserstein/include/spdlog/tweakme.h +++ b/wasserstein/include/spdlog/tweakme.h diff --git a/geom_matching/wasserstein/include/wasserstein.h b/wasserstein/include/wasserstein.h index db6ce11..db6ce11 100644 --- a/geom_matching/wasserstein/include/wasserstein.h +++ b/wasserstein/include/wasserstein.h diff --git a/geom_matching/wasserstein/include/wasserstein_pure_geom.hpp b/wasserstein/include/wasserstein_pure_geom.hpp index 096d95d..096d95d 100644 --- a/geom_matching/wasserstein/include/wasserstein_pure_geom.hpp +++ b/wasserstein/include/wasserstein_pure_geom.hpp diff --git a/geom_matching/wasserstein/tests/data/test_100_A b/wasserstein/tests/data/test_100_A index 8d126f0..8d126f0 100644 --- a/geom_matching/wasserstein/tests/data/test_100_A +++ b/wasserstein/tests/data/test_100_A diff --git a/geom_matching/wasserstein/tests/data/test_100_A.pd.dipha b/wasserstein/tests/data/test_100_A.pd.dipha Binary files differindex e94f5fe..e94f5fe 100644 --- a/geom_matching/wasserstein/tests/data/test_100_A.pd.dipha +++ b/wasserstein/tests/data/test_100_A.pd.dipha diff --git a/geom_matching/wasserstein/tests/data/test_100_B b/wasserstein/tests/data/test_100_B index 852799d..852799d 100644 --- a/geom_matching/wasserstein/tests/data/test_100_B +++ b/wasserstein/tests/data/test_100_B diff --git a/geom_matching/wasserstein/tests/data/test_100_B.pd.dipha b/wasserstein/tests/data/test_100_B.pd.dipha Binary files differindex 25d6734..25d6734 100644 --- a/geom_matching/wasserstein/tests/data/test_100_B.pd.dipha +++ b/wasserstein/tests/data/test_100_B.pd.dipha diff --git a/geom_matching/wasserstein/tests/data/test_200_A b/wasserstein/tests/data/test_200_A index 164b71d..164b71d 100644 --- a/geom_matching/wasserstein/tests/data/test_200_A +++ b/wasserstein/tests/data/test_200_A diff --git a/geom_matching/wasserstein/tests/data/test_200_B b/wasserstein/tests/data/test_200_B index 761943d..761943d 100644 --- a/geom_matching/wasserstein/tests/data/test_200_B +++ b/wasserstein/tests/data/test_200_B diff --git a/geom_matching/wasserstein/tests/data/test_5000_A b/wasserstein/tests/data/test_5000_A index 094c6e0..094c6e0 100644 --- a/geom_matching/wasserstein/tests/data/test_5000_A +++ b/wasserstein/tests/data/test_5000_A diff --git a/geom_matching/wasserstein/tests/data/test_5000_B b/wasserstein/tests/data/test_5000_B index 5f6e43c..5f6e43c 100644 --- a/geom_matching/wasserstein/tests/data/test_5000_B +++ b/wasserstein/tests/data/test_5000_B diff --git a/geom_matching/wasserstein/tests/data/test_5_A b/wasserstein/tests/data/test_5_A index 51cff1c..51cff1c 100644 --- a/geom_matching/wasserstein/tests/data/test_5_A +++ b/wasserstein/tests/data/test_5_A diff --git a/geom_matching/wasserstein/tests/data/test_5_A.pd.dipha b/wasserstein/tests/data/test_5_A.pd.dipha Binary files differindex be84441..be84441 100644 --- a/geom_matching/wasserstein/tests/data/test_5_A.pd.dipha +++ b/wasserstein/tests/data/test_5_A.pd.dipha diff --git a/geom_matching/wasserstein/tests/data/test_5_B b/wasserstein/tests/data/test_5_B index be62ed3..be62ed3 100644 --- a/geom_matching/wasserstein/tests/data/test_5_B +++ b/wasserstein/tests/data/test_5_B diff --git a/geom_matching/wasserstein/tests/data/test_5_B.pd.dipha b/wasserstein/tests/data/test_5_B.pd.dipha Binary files differindex 14ca67c..14ca67c 100644 --- a/geom_matching/wasserstein/tests/data/test_5_B.pd.dipha +++ b/wasserstein/tests/data/test_5_B.pd.dipha diff --git a/geom_matching/wasserstein/tests/data/test_diag1_A b/wasserstein/tests/data/test_diag1_A index f7f90ff..f7f90ff 100644 --- a/geom_matching/wasserstein/tests/data/test_diag1_A +++ b/wasserstein/tests/data/test_diag1_A diff --git a/geom_matching/wasserstein/tests/data/test_diag1_A.pd.dipha b/wasserstein/tests/data/test_diag1_A.pd.dipha Binary files differindex fa4a4d9..fa4a4d9 100644 --- a/geom_matching/wasserstein/tests/data/test_diag1_A.pd.dipha +++ b/wasserstein/tests/data/test_diag1_A.pd.dipha diff --git a/geom_matching/wasserstein/tests/data/test_diag1_B b/wasserstein/tests/data/test_diag1_B index a167a4f..a167a4f 100644 --- a/geom_matching/wasserstein/tests/data/test_diag1_B +++ b/wasserstein/tests/data/test_diag1_B diff --git a/geom_matching/wasserstein/tests/data/test_diag1_B.pd.dipha b/wasserstein/tests/data/test_diag1_B.pd.dipha Binary files differindex 621a55f..621a55f 100644 --- a/geom_matching/wasserstein/tests/data/test_diag1_B.pd.dipha +++ b/wasserstein/tests/data/test_diag1_B.pd.dipha diff --git a/geom_matching/wasserstein/tests/data/test_diag2_A b/wasserstein/tests/data/test_diag2_A index a167a4f..a167a4f 100644 --- a/geom_matching/wasserstein/tests/data/test_diag2_A +++ b/wasserstein/tests/data/test_diag2_A diff --git a/geom_matching/wasserstein/tests/data/test_diag2_A.pd.dipha b/wasserstein/tests/data/test_diag2_A.pd.dipha Binary files differindex 621a55f..621a55f 100644 --- a/geom_matching/wasserstein/tests/data/test_diag2_A.pd.dipha +++ b/wasserstein/tests/data/test_diag2_A.pd.dipha diff --git a/geom_matching/wasserstein/tests/data/test_diag2_B b/wasserstein/tests/data/test_diag2_B index a167a4f..a167a4f 100644 --- a/geom_matching/wasserstein/tests/data/test_diag2_B +++ b/wasserstein/tests/data/test_diag2_B diff --git a/geom_matching/wasserstein/tests/data/test_diag2_B.pd.dipha b/wasserstein/tests/data/test_diag2_B.pd.dipha Binary files differindex 621a55f..621a55f 100644 --- a/geom_matching/wasserstein/tests/data/test_diag2_B.pd.dipha +++ b/wasserstein/tests/data/test_diag2_B.pd.dipha diff --git a/geom_matching/wasserstein/tests/data/test_diag3_A b/wasserstein/tests/data/test_diag3_A index 151d4b1..151d4b1 100644 --- a/geom_matching/wasserstein/tests/data/test_diag3_A +++ b/wasserstein/tests/data/test_diag3_A diff --git a/geom_matching/wasserstein/tests/data/test_diag3_A.pd.dipha b/wasserstein/tests/data/test_diag3_A.pd.dipha Binary files differindex 0dbfb89..0dbfb89 100644 --- a/geom_matching/wasserstein/tests/data/test_diag3_A.pd.dipha +++ b/wasserstein/tests/data/test_diag3_A.pd.dipha diff --git a/geom_matching/wasserstein/tests/data/test_diag3_B b/wasserstein/tests/data/test_diag3_B index bb8655a..bb8655a 100644 --- a/geom_matching/wasserstein/tests/data/test_diag3_B +++ b/wasserstein/tests/data/test_diag3_B diff --git a/geom_matching/wasserstein/tests/data/test_diag3_B.pd.dipha b/wasserstein/tests/data/test_diag3_B.pd.dipha Binary files differindex 3fbfd90..3fbfd90 100644 --- a/geom_matching/wasserstein/tests/data/test_diag3_B.pd.dipha +++ b/wasserstein/tests/data/test_diag3_B.pd.dipha diff --git a/geom_matching/wasserstein/tests/data/test_list.txt b/wasserstein/tests/data/test_list.txt index 27340d8..27340d8 100644 --- a/geom_matching/wasserstein/tests/data/test_list.txt +++ b/wasserstein/tests/data/test_list.txt diff --git a/geom_matching/wasserstein/tests/test_hera_wasserstein.cpp b/wasserstein/tests/test_hera_wasserstein.cpp index 0a80d2f..0a80d2f 100644 --- a/geom_matching/wasserstein/tests/test_hera_wasserstein.cpp +++ b/wasserstein/tests/test_hera_wasserstein.cpp diff --git a/geom_matching/wasserstein/tests/test_hera_wasserstein_pure_geom.cpp b/wasserstein/tests/test_hera_wasserstein_pure_geom.cpp index 9603ceb..9603ceb 100644 --- a/geom_matching/wasserstein/tests/test_hera_wasserstein_pure_geom.cpp +++ b/wasserstein/tests/test_hera_wasserstein_pure_geom.cpp diff --git a/geom_matching/wasserstein/tests/tests_main.cpp b/wasserstein/tests/tests_main.cpp index d24407e..d24407e 100644 --- a/geom_matching/wasserstein/tests/tests_main.cpp +++ b/wasserstein/tests/tests_main.cpp diff --git a/geom_matching/wasserstein/tests/tests_reader.h b/wasserstein/tests/tests_reader.h index f2d5735..f2d5735 100644 --- a/geom_matching/wasserstein/tests/tests_reader.h +++ b/wasserstein/tests/tests_reader.h |