2025-06-19 11:06:31 +00:00
using System ;
2024-06-02 06:18:57 +00:00
using System.Collections.Generic ;
using System.Linq ;
namespace Flow.Launcher.Infrastructure
{
public class TranslationMapping
{
private bool constructed ;
2025-04-09 12:06:17 +00:00
private readonly List < int > originalIndexes = new ( ) ;
private readonly List < int > translatedIndexes = new ( ) ;
2024-06-02 06:18:57 +00:00
private int translatedLength = 0 ;
2025-06-19 11:06:31 +00:00
/// <summary>
/// Adds a mapping between an original index and a translated index range.
/// </summary>
/// <param name="originalIndex">The index in the original sequence.</param>
/// <param name="translatedIndex">The starting index of the corresponding range in the translated sequence.</param>
/// <param name="length">The length of the translated index range.</param>
/// <exception cref="InvalidOperationException">Thrown if the mapping has already been finalized.</exception>
2024-06-02 06:18:57 +00:00
public void AddNewIndex ( int originalIndex , int translatedIndex , int length )
{
if ( constructed )
throw new InvalidOperationException ( "Mapping shouldn't be changed after constructed" ) ;
2025-04-09 12:06:17 +00:00
originalIndexes . Add ( originalIndex ) ;
translatedIndexes . Add ( translatedIndex ) ;
translatedIndexes . Add ( translatedIndex + length ) ;
2024-06-02 06:18:57 +00:00
translatedLength + = length - 1 ;
}
2025-06-19 11:06:31 +00:00
/// <summary>
/// Maps a translated index back to its corresponding original index based on stored translation ranges.
/// </summary>
/// <param name="translatedIndex">The index in the translated sequence to map.</param>
/// <returns>The corresponding index in the original sequence. If the translated index falls outside known ranges, returns an adjusted index based on accumulated translation lengths.</returns>
2024-06-02 06:18:57 +00:00
public int MapToOriginalIndex ( int translatedIndex )
{
2025-04-09 12:06:17 +00:00
if ( translatedIndex > translatedIndexes . Last ( ) )
2024-06-02 06:18:57 +00:00
return translatedIndex - translatedLength - 1 ;
int lowerBound = 0 ;
2025-04-09 12:06:17 +00:00
int upperBound = originalIndexes . Count - 1 ;
2024-06-02 06:18:57 +00:00
int count = 0 ;
// Corner case handle
2025-04-09 12:06:17 +00:00
if ( translatedIndex < translatedIndexes [ 0 ] )
2024-06-02 06:18:57 +00:00
return translatedIndex ;
2025-04-09 12:06:17 +00:00
if ( translatedIndex > translatedIndexes . Last ( ) )
2024-06-02 06:18:57 +00:00
{
int indexDef = 0 ;
2025-04-09 12:06:17 +00:00
for ( int k = 0 ; k < originalIndexes . Count ; k + + )
2024-06-02 06:18:57 +00:00
{
2025-04-09 12:06:17 +00:00
indexDef + = translatedIndexes [ k * 2 + 1 ] - translatedIndexes [ k * 2 ] ;
2024-06-02 06:18:57 +00:00
}
return translatedIndex - indexDef - 1 ;
}
// Binary Search with Range
2025-04-09 12:06:17 +00:00
for ( int i = originalIndexes . Count / 2 ; ; count + + )
2024-06-02 06:18:57 +00:00
{
2025-04-09 12:06:17 +00:00
if ( translatedIndex < translatedIndexes [ i * 2 ] )
2024-06-02 06:18:57 +00:00
{
// move to lower middle
upperBound = i ;
i = ( i + lowerBound ) / 2 ;
}
2025-04-09 12:06:17 +00:00
else if ( translatedIndex > translatedIndexes [ i * 2 + 1 ] - 1 )
2024-06-02 06:18:57 +00:00
{
lowerBound = i ;
// move to upper middle
// due to floor of integer division, move one up on corner case
i = ( i + upperBound + 1 ) / 2 ;
}
else
2025-04-09 12:06:17 +00:00
{
return originalIndexes [ i ] ;
}
2024-06-02 06:18:57 +00:00
if ( upperBound - lowerBound < = 1 & &
2025-04-09 12:06:17 +00:00
translatedIndex > translatedIndexes [ lowerBound * 2 + 1 ] & &
translatedIndex < translatedIndexes [ upperBound * 2 ] )
2024-06-02 06:18:57 +00:00
{
int indexDef = 0 ;
for ( int j = 0 ; j < upperBound ; j + + )
{
2025-04-09 12:06:17 +00:00
indexDef + = translatedIndexes [ j * 2 + 1 ] - translatedIndexes [ j * 2 ] ;
2024-06-02 06:18:57 +00:00
}
return translatedIndex - indexDef - 1 ;
}
}
}
2025-06-19 11:06:31 +00:00
/// <summary>
/// Finalizes the mapping, preventing any further modifications.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown if the mapping has already been finalized.</exception>
2024-06-02 06:18:57 +00:00
public void endConstruct ( )
{
if ( constructed )
throw new InvalidOperationException ( "Mapping has already been constructed" ) ;
constructed = true ;
}
}
}