| 
						
						
							
								
							
						
						
					 | 
					@ -18,12 +18,12 @@ using klotski::group::GROUP_DATA; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					using klotski::group::PATTERN_DATA; | 
					 | 
					 | 
					using klotski::group::PATTERN_DATA; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					template <typename MF, typename RF> | 
					 | 
					 | 
					template <typename MF, typename RF> | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					KLSK_NOINLINE static void extend(RawCode seed, const size_t size, MF add_mirror, RF release) { | 
					 | 
					 | 
					KLSK_NOINLINE static void extend(const RawCode seed, const size_t reserve, MF add_mirror, RF release) { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    std::vector<RawCode> queue, mirrors; | 
					 | 
					 | 
					    std::vector<RawCode> queue, mirrors; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    phmap::flat_hash_map<RawCode, uint64_t> cases; | 
					 | 
					 | 
					    phmap::flat_hash_map<RawCode, uint64_t> cases; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    queue.reserve(size); mirrors.reserve(size); | 
					 | 
					 | 
					    queue.reserve(reserve); mirrors.reserve(reserve); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    cases.reserve(static_cast<size_t>(static_cast<double>(size) * 1.56)); // reduce load factor
 | 
					 | 
					 | 
					    cases.reserve(static_cast<size_t>(static_cast<double>(reserve) * 1.56)); // reduce load factor
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    auto mover = MaskMover([&queue, &cases, &mirrors, add_mirror](RawCode code, uint64_t hint) { | 
					 | 
					 | 
					    auto mover = MaskMover([&queue, &cases, &mirrors, add_mirror](RawCode code, uint64_t hint) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        if (const auto [iter, ret] = cases.try_emplace(code, hint); !ret) { | 
					 | 
					 | 
					        if (const auto [iter, ret] = cases.try_emplace(code, hint); !ret) { | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -53,174 +53,204 @@ KLSK_NOINLINE static void extend(RawCode seed, const size_t size, MF add_mirror, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    for (const auto code : mirrors) { release(code); } | 
					 | 
					 | 
					    for (const auto code : mirrors) { release(code); } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					static RangesUnion extend_type_common(RawCode seed, size_t reserve) { | 
					 | 
					 | 
					#define RELEASE_TO(RU) \ | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    RangesUnion data {}; | 
					 | 
					 | 
					    [&data](const RawCode raw_code) { \ | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    extend(seed, reserve, [](RawCode, auto) {}, [&data](const RawCode raw_code) { | 
					 | 
					 | 
					        const auto code = raw_code.to_common_code().unwrap(); \ | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        const auto code = raw_code.to_common_code().unwrap(); | 
					 | 
					 | 
					        data.ranges(code >> 32).emplace_back(static_cast<uint32_t>(code)); \ | 
				
			
			
				
				
			
		
	
		
		
			
				
					 | 
					 | 
					        data.ranges(code >> 32).emplace_back(static_cast<uint32_t>(code)); | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    }); | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    return data; | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					static RangesUnion extend_type_hor(RawCode seed, size_t reserve) { | 
					 | 
					 | 
					template <Group::MirrorType TYPE> | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					static RangesUnion extend_type_xxx(const RawCode seed, const size_t reserve) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    RangesUnion data {}; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    // size_t size_a = static_cast<size_t>(static_cast<double>(size) * 0.500892) + 11;
 | 
					 | 
					 | 
					    if constexpr(TYPE == Group::MirrorType::Ordinary) { | 
				
			
			
				
				
			
		
	
		
		
			
				
					 | 
					 | 
					    // size_t size_b = static_cast<size_t>(static_cast<double>(size) * 0.499108) + 10;
 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    RangesUnion data {}; | 
					 | 
					 | 
					        extend(seed, reserve, [](RawCode, auto) {}, RELEASE_TO(data)); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    // TODO: how to reserve
 | 
					 | 
					 | 
					    } else if constexpr(TYPE == Group::MirrorType::Horizontal) { | 
				
			
			
				
				
			
		
	
		
		
			
				
					 | 
					 | 
					    // size_t val = reserve / 8;
 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    //
 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // data.ranges(0).reserve(val);
 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // data.ranges(1).reserve(val);
 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // data.ranges(2).reserve(val);
 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    //
 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // data.ranges(4).reserve(val);
 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // data.ranges(5).reserve(val);
 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // data.ranges(6).reserve(val);
 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    //
 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // data.ranges(8).reserve(val);
 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // data.ranges(9).reserve(val);
 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // data.ranges(10).reserve(val);
 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    //
 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // data.ranges(12).reserve(val);
 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // data.ranges(13).reserve(val);
 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // data.ranges(14).reserve(val);
 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        extend(seed, reserve, [](const RawCode code, auto callback) { | 
					 | 
					 | 
					        extend(seed, reserve, [](const RawCode code, auto callback) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        if (const auto mirror = code.to_horizontal_mirror(); mirror != code) { | 
					 | 
					 | 
					            if (const auto m_hor = code.to_horizontal_mirror(); m_hor != code) { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            callback(mirror); | 
					 | 
					 | 
					                callback(m_hor); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            } | 
					 | 
					 | 
					            } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    }, [&data](const RawCode raw_code) { | 
					 | 
					 | 
					        }, RELEASE_TO(data)); | 
				
			
			
				
				
			
		
	
		
		
			
				
					 | 
					 | 
					        const auto code = raw_code.to_common_code().unwrap(); | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        data.ranges(code >> 32).emplace_back(static_cast<uint32_t>(code)); | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    }); | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    return data; | 
					 | 
					 | 
					    } else if constexpr(TYPE == Group::MirrorType::Vertical) { | 
				
			
			
				
				
			
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					static RangesUnion extend_type_ver(RawCode seed, size_t reserve) { | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    RangesUnion data {}; | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        extend(seed, reserve, [](const RawCode code, auto callback) { | 
					 | 
					 | 
					        extend(seed, reserve, [](const RawCode code, auto callback) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            callback(code.to_vertical_mirror()); | 
					 | 
					 | 
					            callback(code.to_vertical_mirror()); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    }, [&data](const RawCode raw_code) { | 
					 | 
					 | 
					        }, RELEASE_TO(data)); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        const auto code = raw_code.to_common_code().unwrap(); | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        data.ranges(code >> 32).emplace_back(static_cast<uint32_t>(code)); | 
					 | 
					 | 
					    } else if constexpr(TYPE == Group::MirrorType::Centro) { | 
				
			
			
				
				
			
		
	
		
		
			
				
					 | 
					 | 
					    }); | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    return data; | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					static RangesUnion extend_type_diag(RawCode seed, size_t reserve) { | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    RangesUnion data {}; | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        extend(seed, reserve, [](const RawCode code, auto callback) { | 
					 | 
					 | 
					        extend(seed, reserve, [](const RawCode code, auto callback) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            callback(code.to_diagonal_mirror()); | 
					 | 
					 | 
					            callback(code.to_diagonal_mirror()); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    }, [&data](const RawCode raw_code) { | 
					 | 
					 | 
					        }, RELEASE_TO(data)); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        const auto code = raw_code.to_common_code().unwrap(); | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        data.ranges(code >> 32).emplace_back(static_cast<uint32_t>(code)); | 
					 | 
					 | 
					    } else if constexpr(TYPE == Group::MirrorType::Full) { | 
				
			
			
				
				
			
		
	
		
		
			
				
					 | 
					 | 
					    }); | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    return data; | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					static RangesUnion extend_type_x(RawCode seed, size_t reserve) { | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    RangesUnion data {}; | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        extend(seed, reserve, [](const RawCode code, auto callback) { | 
					 | 
					 | 
					        extend(seed, reserve, [](const RawCode code, auto callback) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        const auto mirror_1 = code.to_vertical_mirror(); | 
					 | 
					 | 
					            const auto m_vrt = code.to_vertical_mirror(); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        callback(mirror_1); | 
					 | 
					 | 
					            callback(m_vrt); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        if (const auto mirror_2 = code.to_horizontal_mirror(); mirror_2 != code) { | 
					 | 
					 | 
					            if (const auto m_hor = code.to_horizontal_mirror(); m_hor != code) { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            callback(mirror_2); | 
					 | 
					 | 
					                callback(m_hor); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            callback(mirror_1.to_horizontal_mirror()); | 
					 | 
					 | 
					                callback(m_vrt.to_horizontal_mirror()); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            } | 
					 | 
					 | 
					            } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    }, [&data](const RawCode raw_code) { | 
					 | 
					 | 
					        }, RELEASE_TO(data)); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        const auto code = raw_code.to_common_code().unwrap(); | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        data.ranges(code >> 32).emplace_back(static_cast<uint32_t>(code)); | 
					 | 
					 | 
					    } | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    }); | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    return data; | 
					 | 
					 | 
					    return data; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					// static RangesUnion extend_type_ord(const RawCode seed, const size_t reserve) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//     RangesUnion data {};
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//     extend(seed, reserve, [](RawCode, auto) {}, RELEASE_TO(data));
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//     return data;
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					// }
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					// static RangesUnion extend_type_hor(const RawCode seed, const size_t reserve) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//     RangesUnion data {};
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//     extend(seed, reserve, [](const RawCode code, auto callback) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//         if (const auto m_hor = code.to_horizontal_mirror(); m_hor != code) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//             callback(m_hor);
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//         }
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//     }, RELEASE_TO(data));
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//     return data;
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					// }
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					// static RangesUnion extend_type_vrt(const RawCode seed, const size_t reserve) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//     RangesUnion data {};
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//     extend(seed, reserve, [](const RawCode code, auto callback) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//         callback(code.to_vertical_mirror());
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//     }, RELEASE_TO(data));
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//     return data;
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					// }
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					// static RangesUnion extend_type_diag(const RawCode seed, const size_t reserve) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//     RangesUnion data {};
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//     extend(seed, reserve, [](const RawCode code, auto callback) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//         callback(code.to_diagonal_mirror());
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//     }, RELEASE_TO(data));
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//     return data;
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					// }
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					// static RangesUnion extend_type_full(const RawCode seed, const size_t reserve) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//     RangesUnion data {};
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//     extend(seed, reserve, [](const RawCode code, auto callback) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//         const auto m_vrt = code.to_vertical_mirror();
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//         callback(m_vrt);
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//         if (const auto m_hor = code.to_horizontal_mirror(); m_hor != code) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//             callback(m_hor);
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//             callback(m_vrt.to_horizontal_mirror());
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//         }
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//     }, RELEASE_TO(data));
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					//     return data;
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					// }
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					template <typename MFunc, typename RFunc> | 
					 | 
					 | 
					template <typename MFunc, typename RFunc> | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					KLSK_NOINLINE static void spawn_pattern(RawCode seed, const size_t reserve, MFunc add_mirror, RFunc release) { | 
					 | 
					 | 
					KLSK_NOINLINE static void spawn_pattern(RawCode seed, const size_t reserve, MFunc add_mirror, RFunc release) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					
 | 
					 | 
					 | 
					    std::vector<RawCode> queue; | 
				
			
			
				
				
			
		
	
		
		
			
				
					 | 
					 | 
					    std::vector<RawCode> codes; | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    std::vector<RawCode> mirrors; | 
					 | 
					 | 
					    std::vector<RawCode> mirrors; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    phmap::flat_hash_map<RawCode, uint64_t> cases; // <code, hint>
 | 
					 | 
					 | 
					    phmap::flat_hash_map<RawCode, uint64_t> cases; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    codes.reserve(reserve); | 
					 | 
					 | 
					    queue.reserve(reserve); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    mirrors.reserve(reserve); // TODO: cal max size-coff
 | 
					 | 
					 | 
					    mirrors.reserve(reserve); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    cases.reserve(static_cast<size_t>(reserve * 1.56)); | 
					 | 
					 | 
					    cases.reserve(static_cast<size_t>(reserve * 1.56)); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    auto core = MaskMover([&codes, &cases, &mirrors, add_mirror](RawCode code, uint64_t hint) { | 
					 | 
					 | 
					    auto mover = MaskMover([&queue, &cases, &mirrors, add_mirror](RawCode code, uint64_t hint) { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					        if (const auto [iter, ret] = cases.try_emplace(code, hint); !ret) { | 
					 | 
					 | 
					        if (const auto [iter, ret] = cases.try_emplace(code, hint); !ret) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            iter->second |= hint; // update hint
 | 
					 | 
					 | 
					            iter->second |= hint; // update hint
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            return; | 
					 | 
					 | 
					            return; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        } | 
					 | 
					 | 
					        } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        codes.emplace_back(code); | 
					 | 
					 | 
					        queue.emplace_back(code); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					        add_mirror(code, [&cases, &mirrors](RawCode mirror) { | 
					 | 
					 | 
					        add_mirror(code, [&cases, &mirrors](RawCode mirror) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            cases.emplace(mirror, 0); | 
					 | 
					 | 
					            cases.emplace(mirror, 0); // without hint
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            mirrors.emplace_back(mirror); | 
					 | 
					 | 
					            mirrors.emplace_back(mirror); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        }); | 
					 | 
					 | 
					        }); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    }); | 
					 | 
					 | 
					    }); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    uint64_t offset = 0; | 
					 | 
					 | 
					    uint64_t offset = 0; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    codes.emplace_back(seed); | 
					 | 
					 | 
					    queue.emplace_back(seed); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    cases.emplace(seed, 0); // without hint
 | 
					 | 
					 | 
					    cases.emplace(seed, 0); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    add_mirror(seed, [&mirrors, &cases](RawCode mirror) { | 
					 | 
					 | 
					    add_mirror(seed, [&mirrors, &cases](RawCode mirror) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        cases.emplace(mirror, 0); | 
					 | 
					 | 
					        cases.emplace(mirror, 0); // without hint
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					        mirrors.emplace_back(mirror); | 
					 | 
					 | 
					        mirrors.emplace_back(mirror); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    }); | 
					 | 
					 | 
					    }); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    while (offset != codes.size()) { | 
					 | 
					 | 
					    while (offset != queue.size()) { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        const auto curr = codes[offset++]; | 
					 | 
					 | 
					        const auto curr = queue[offset++]; | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        core.next_cases(curr, cases.find(curr)->second); | 
					 | 
					 | 
					        mover.next_cases(curr, cases.find(curr)->second); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    for (const auto code : codes) { | 
					 | 
					 | 
					    for (const auto code : queue) { release(code); } | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        release(code); | 
					 | 
					 | 
					    for (const auto code : mirrors) { release(code); } | 
				
			
			
				
				
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    for (const auto code : mirrors) { | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        release(code); | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					#define OUTPUT(VAR, EXPL, OUT) \ | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    const auto VAR = (EXPL).to_common_code().unwrap(); \ | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    OUT.ranges(VAR >> 32).emplace_back(static_cast<uint32_t>(VAR)) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					#define KLSK_CONCAT_IMPL(X, Y) X##Y | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					#define KLSK_CONCAT(X, Y) KLSK_CONCAT_IMPL(X, Y) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					#define OUTPUT_IMPL(VAR, EXPL, OUT) \ | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    const auto VAR = (EXPL).to_common_code().unwrap(); \ | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    OUT.ranges(VAR >> 32).emplace_back(static_cast<uint32_t>(VAR)) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					#define OUTPUT(EXPL, OUT) \ | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    OUTPUT_IMPL(KLSK_CONCAT(c_, __COUNTER__), EXPL, OUT) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					KLSK_NOINLINE static void spawn_full_pattern(RawCode seed, const size_t reserve, RangesUnion &output) { | 
					 | 
					 | 
					KLSK_NOINLINE static void spawn_full_pattern(RawCode seed, const size_t reserve, RangesUnion &output) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    spawn_pattern(seed, reserve, [](RawCode, auto) {}, [&output](RawCode raw_code) { | 
					 | 
					 | 
					    spawn_pattern(seed, reserve, [](RawCode, auto) {}, [&output](RawCode raw_code) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        const auto code = raw_code.to_common_code().unwrap(); | 
					 | 
					 | 
					        // const auto code = raw_code.to_common_code().unwrap();
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        output.ranges(code >> 32).emplace_back(static_cast<uint32_t>(code)); | 
					 | 
					 | 
					        // output.ranges(code >> 32).emplace_back(static_cast<uint32_t>(code));
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        // OUTPUT(code, raw_code, output);
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        OUTPUT(raw_code, output); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    }); | 
					 | 
					 | 
					    }); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					KLSK_NOINLINE static void spawn_hor_pattern(RawCode seed, const size_t reserve, RangesUnion &output) { | 
					 | 
					 | 
					KLSK_NOINLINE static void spawn_hor_pattern(RawCode seed, const size_t reserve, RangesUnion &output) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    spawn_pattern(seed, reserve, [](RawCode, auto) {}, [&output](RawCode raw_code) { | 
					 | 
					 | 
					    spawn_pattern(seed, reserve, [](RawCode, auto) {}, [&output](RawCode raw_code) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        const auto code = raw_code.to_common_code().unwrap(); | 
					 | 
					 | 
					        // const auto code = raw_code.to_common_code().unwrap();
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        output.ranges(code >> 32).emplace_back(static_cast<uint32_t>(code)); | 
					 | 
					 | 
					        // output.ranges(code >> 32).emplace_back(static_cast<uint32_t>(code));
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        OUTPUT(raw_code, output); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        const auto code_ = raw_code.to_vertical_mirror().to_common_code().unwrap(); | 
					 | 
					 | 
					        // const auto code_ = raw_code.to_vertical_mirror().to_common_code().unwrap();
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        output.ranges(code_ >> 32).emplace_back(static_cast<uint32_t>(code_)); | 
					 | 
					 | 
					        // output.ranges(code_ >> 32).emplace_back(static_cast<uint32_t>(code_));
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        OUTPUT(raw_code.to_vertical_mirror(), output); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    }); | 
					 | 
					 | 
					    }); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					KLSK_NOINLINE static void spawn_ver_pattern(RawCode seed, const size_t reserve, RangesUnion &output) { | 
					 | 
					 | 
					KLSK_NOINLINE static void spawn_ver_pattern(RawCode seed, const size_t reserve, RangesUnion &output) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    spawn_pattern(seed, reserve, [](RawCode, auto) {}, [&output](RawCode raw_code) { | 
					 | 
					 | 
					    spawn_pattern(seed, reserve, [](RawCode, auto) {}, [&output](RawCode raw_code) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        const auto code = raw_code.to_common_code().unwrap(); | 
					 | 
					 | 
					        // const auto code = raw_code.to_common_code().unwrap();
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        output.ranges(code >> 32).emplace_back(static_cast<uint32_t>(code)); | 
					 | 
					 | 
					        // output.ranges(code >> 32).emplace_back(static_cast<uint32_t>(code));
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        OUTPUT(raw_code, output); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        const auto code_ = raw_code.to_horizontal_mirror().to_common_code().unwrap(); | 
					 | 
					 | 
					        // const auto code_ = raw_code.to_horizontal_mirror().to_common_code().unwrap();
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        output.ranges(code_ >> 32).emplace_back(static_cast<uint32_t>(code_)); | 
					 | 
					 | 
					        // output.ranges(code_ >> 32).emplace_back(static_cast<uint32_t>(code_));
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        OUTPUT(raw_code.to_horizontal_mirror(), output); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    }); | 
					 | 
					 | 
					    }); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					KLSK_NOINLINE static void spawn_ord_pattern(RawCode seed, const size_t reserve, RangesUnion &output) { | 
					 | 
					 | 
					KLSK_NOINLINE static void spawn_ord_pattern(RawCode seed, const size_t reserve, RangesUnion &output) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    spawn_pattern(seed, reserve, [](RawCode, auto) {}, [&output](RawCode raw_code) { | 
					 | 
					 | 
					    spawn_pattern(seed, reserve, [](RawCode, auto) {}, [&output](RawCode raw_code) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        const auto code = raw_code.to_common_code().unwrap(); | 
					 | 
					 | 
					        // const auto code = raw_code.to_common_code().unwrap();
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        output.ranges(code >> 32).emplace_back(static_cast<uint32_t>(code)); | 
					 | 
					 | 
					        // output.ranges(code >> 32).emplace_back(static_cast<uint32_t>(code));
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        OUTPUT(raw_code, output); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        const auto code_1 = raw_code.to_vertical_mirror().to_common_code().unwrap(); | 
					 | 
					 | 
					        // const auto code_1 = raw_code.to_vertical_mirror().to_common_code().unwrap();
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        output.ranges(code_1 >> 32).emplace_back(static_cast<uint32_t>(code_1)); | 
					 | 
					 | 
					        // output.ranges(code_1 >> 32).emplace_back(static_cast<uint32_t>(code_1));
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        OUTPUT(raw_code.to_vertical_mirror(), output); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        const auto code_2 = raw_code.to_horizontal_mirror().to_common_code().unwrap(); | 
					 | 
					 | 
					        // const auto code_2 = raw_code.to_horizontal_mirror().to_common_code().unwrap();
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        output.ranges(code_2 >> 32).emplace_back(static_cast<uint32_t>(code_2)); | 
					 | 
					 | 
					        // output.ranges(code_2 >> 32).emplace_back(static_cast<uint32_t>(code_2));
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        OUTPUT(raw_code.to_horizontal_mirror(), output); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        const auto code_3 = raw_code.to_diagonal_mirror().to_common_code().unwrap(); | 
					 | 
					 | 
					        // const auto code_3 = raw_code.to_diagonal_mirror().to_common_code().unwrap();
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        output.ranges(code_3 >> 32).emplace_back(static_cast<uint32_t>(code_3)); | 
					 | 
					 | 
					        // output.ranges(code_3 >> 32).emplace_back(static_cast<uint32_t>(code_3));
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        OUTPUT(raw_code.to_diagonal_mirror(), output); // TODO: perf it
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    }); | 
					 | 
					 | 
					    }); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -263,7 +293,8 @@ RangesUnion Group::cases() const { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        // return GroupUnion::unsafe_create(type_id_).cases();
 | 
					 | 
					 | 
					        // return GroupUnion::unsafe_create(type_id_).cases();
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    auto seed = CommonCode::unsafe_create(PATTERN_DATA[flat_id()] >> 23).to_raw_code(); | 
					 | 
					 | 
					    const auto seed_val = PATTERN_DATA[flat_id()] >> 23; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    auto seed = CommonCode::unsafe_create(seed_val).to_raw_code(); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    if (toward_ == Toward::B) { | 
					 | 
					 | 
					    if (toward_ == Toward::B) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        seed = seed.to_horizontal_mirror(); | 
					 | 
					 | 
					        seed = seed.to_horizontal_mirror(); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } else if (toward_ == Toward::C) { | 
					 | 
					 | 
					    } else if (toward_ == Toward::C) { | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -272,20 +303,96 @@ RangesUnion Group::cases() const { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        seed = seed.to_diagonal_mirror(); | 
					 | 
					 | 
					        seed = seed.to_diagonal_mirror(); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // const auto centro_mirror = [](const RawCode code, auto callback) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     callback(code.to_diagonal_mirror());
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // };
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // const auto vertical_mirror = [](const RawCode code, auto callback) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     callback(code.to_vertical_mirror());
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // };
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // const auto horizontal_mirror = [](const RawCode code, auto callback) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     if (const auto m_hor = code.to_horizontal_mirror(); m_hor != code) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //         callback(m_hor);
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     }
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // };
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // const auto full_mirror = [](const RawCode code, auto callback) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     const auto m_vrt = code.to_vertical_mirror();
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     callback(m_vrt);
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     if (const auto m_hor = code.to_horizontal_mirror(); m_hor != code) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //         callback(m_hor);
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //         callback(m_vrt.to_horizontal_mirror());
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     }
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // };
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // TODO: how to reserve `data`
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    RangesUnion data; | 
					 | 
					 | 
					    RangesUnion data; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // if (mirror_type() == MirrorType::Ordinary) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     // std::println("Ordinary"); // 24892
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     // extend(seed, size(), [](RawCode, auto) {}, RELEASE_TO(data));
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     data = extend_ord(seed, size());
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // } else if (mirror_type() == MirrorType::Horizontal) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     // std::println("Horizontal"); // 294
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     // extend(seed, size(), [](const RawCode code, auto callback) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     //     if (const auto m_hor = code.to_horizontal_mirror(); m_hor != code) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     //         callback(m_hor);
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     //     }
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     // }, RELEASE_TO(data));
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     // return extend_hor(seed, size());
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     data = extend_hor(seed, size());
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // } else if (mirror_type() == MirrorType::Vertical) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     // std::println("Vertical"); // 54
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     // extend(seed, size(), vertical_mirror, RELEASE_TO(data));
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     data = extend_ver(seed, size());
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // } else if (mirror_type() == MirrorType::Full) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     // std::println("Full"); // 3
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     // extend(seed, size(), full_mirror, RELEASE_TO(data));
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     data = extend_type_x(seed, size());
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // } else {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     // std::println("Centro"); // 4
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     // extend(seed, size(), centro_mirror, RELEASE_TO(data));
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     data = extend_diag(seed, size());
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // }
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    if (mirror_type() == MirrorType::Full) { | 
					 | 
					 | 
					    if (mirror_type() == MirrorType::Full) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        data = extend_type_x(seed, size()); | 
					 | 
					 | 
					        // data = extend_type_full(seed, size());
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        data = extend_type_xxx<MirrorType::Full>(seed, size()); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } else if (mirror_type() == MirrorType::Horizontal) { | 
					 | 
					 | 
					    } else if (mirror_type() == MirrorType::Horizontal) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        data = extend_type_hor(seed, size()); | 
					 | 
					 | 
					        // data = extend_type_hor(seed, size());
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        data = extend_type_xxx<MirrorType::Horizontal>(seed, size()); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } else if (mirror_type() == MirrorType::Vertical) { | 
					 | 
					 | 
					    } else if (mirror_type() == MirrorType::Vertical) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        data = extend_type_ver(seed, size()); | 
					 | 
					 | 
					        // data = extend_type_vrt(seed, size());
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        data = extend_type_xxx<MirrorType::Vertical>(seed, size()); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } else if (mirror_type() == MirrorType::Centro) { | 
					 | 
					 | 
					    } else if (mirror_type() == MirrorType::Centro) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        data = extend_type_diag(seed, size()); | 
					 | 
					 | 
					        // data = extend_type_diag(seed, size());
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        data = extend_type_xxx<MirrorType::Centro>(seed, size()); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } else { | 
					 | 
					 | 
					    } else { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        data = extend_type_common(seed, size()); | 
					 | 
					 | 
					        // data = extend_type_ord(seed, size());
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    } | 
					 | 
					 | 
					        data = extend_type_xxx<MirrorType::Ordinary>(seed, size()); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					
 | 
					 | 
					 | 
					    } | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    for (int head = 0; head < 16; ++head) { | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // if (mirror_type() == MirrorType::Ordinary) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     data = extend_type_ord(seed, size());
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // } else if (mirror_type() == MirrorType::Horizontal) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     data = extend_type_hor(seed, size());
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // } else if (mirror_type() == MirrorType::Vertical) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     data = extend_type_vrt(seed, size());
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // } else if (mirror_type() == MirrorType::Full) {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     data = extend_type_full(seed, size());
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // } else {
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    //     data = extend_type_diag(seed, size());
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    // }
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    for (const auto head : RangesUnion::Heads) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        std::stable_sort(data.ranges(head).begin(), data.ranges(head).end()); | 
					 | 
					 | 
					        std::stable_sort(data.ranges(head).begin(), data.ranges(head).end()); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    return data; | 
					 | 
					 | 
					    return data; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
					
  |