| 
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -50,18 +50,10 @@ static uint32_t check_range(uint32_t head, uint32_t range) noexcept { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    return 0; // pass check
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					std::mutex ShortCode::busy_ {}; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// ShortCode::Stage ShortCode::stage_ = Stage::UNINIT;
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					// const klotski::cases::RangesUnion *ShortCode::cases_ = &AllCases::instance().fetch();
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					const klotski::cases::RangesUnion *ShortCode::cases_ = nullptr; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					const klotski::cases::Ranges *ShortCode::ranges_ = nullptr; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					uint32_t ShortCode::fast_encode(uint64_t common_code) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    auto head = common_code >> 32; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    auto &ranges = AllCases::instance().fetch()[head]; // match available ranges
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    auto &ranges = (*cases_)[head]; // match available ranges
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    // TODO: try to narrow the scope by prefix
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    auto target = std::lower_bound(ranges.begin(), ranges.end(), (uint32_t)common_code); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    return ALL_CASES_OFFSET[head] + (target - ranges.begin()); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -79,19 +71,22 @@ uint32_t ShortCode::tiny_encode(uint64_t common_code) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    uint32_t offset = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    auto index = RANGES_GLOBAL_OFFSET[prefix]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const auto &basic_ranges = BasicRanges::instance().fetch(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    ranges_ = &cases::BasicRanges::instance().fetch(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const auto &ranges = *ranges_; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    auto target = (uint32_t)common_code; // target range
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    for (; index < basic_ranges.size(); ++index) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        auto broken_offset = check_range(head, range_reverse(basic_ranges[index])); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    for (; index < ranges.size(); ++index) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        auto broken_offset = check_range(head, range_reverse(ranges[index])); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        if (!broken_offset) { // valid case
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (basic_ranges[index] == target) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            if (ranges[index] == target) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					                break; // found target range
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            ++offset; // record sub offset
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } else { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            auto delta = (uint32_t)1 << (32 - broken_offset * 2); // delta to next possible range
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            auto next_min = (basic_ranges[index] & ~(delta - 1)) + delta; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            while (basic_ranges[++index] < next_min); // located next range
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            auto next_min = (ranges[index] & ~(delta - 1)) + delta; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            while (ranges[++index] < next_min); // located next range
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					            --index; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        } | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    } | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -99,13 +94,6 @@ uint32_t ShortCode::tiny_encode(uint64_t common_code) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					uint64_t ShortCode::tiny_decode(uint32_t short_code) { // short code --> common code
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    // speed_up(false);
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    // std::lock_guard guard {busy_};
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    ranges_ = &cases::BasicRanges::instance().fetch(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    // stage_ = Stage::TINY;
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    auto offset_ = std::upper_bound(ALL_CASES_OFFSET.begin(), ALL_CASES_OFFSET.end(), short_code) - 1; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    auto head = offset_ - ALL_CASES_OFFSET.begin(); // head index
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    short_code -= *offset_; | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -116,11 +104,9 @@ uint64_t ShortCode::tiny_decode(uint32_t short_code) { // short code --> common | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    /// search for target range
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    auto index = RANGES_GLOBAL_OFFSET[prefix]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    // auto basic_ranges = ranges_;
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    // const auto &basic_ranges = BasicRanges::instance().fetch();
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    ranges_ = &cases::BasicRanges::instance().fetch(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    const auto &ranges = *ranges_; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    // const auto &ranges = BasicRanges::instance().fetch();
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					    for (; index < ranges.size(); ++index) { // traverse basic ranges
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					        auto broken_offset = check_range(head, range_reverse(ranges[index])); | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
				 | 
				
					
  |