202 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			C#
		
	
	
			
		
		
	
	
			202 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			C#
		
	
	
using System;
 | 
						|
using System.Collections.Generic;
 | 
						|
 | 
						|
namespace fec
 | 
						|
{
 | 
						|
    public class ReedSolomonTest
 | 
						|
    {
 | 
						|
 | 
						|
 | 
						|
    /**
 | 
						|
     * Try encoding and decoding with a lot of shards.
 | 
						|
     */
 | 
						|
    public void testBigEncodeDecode() {
 | 
						|
         Random random = new Random(0);
 | 
						|
         for (int k = 0; k < 1000; k++)
 | 
						|
         {
 | 
						|
             int dataCount = 64;
 | 
						|
             int parityCount = 64;
 | 
						|
             int shardSize = 200;
 | 
						|
             byte [] [] dataShards = new byte [dataCount] [];
 | 
						|
             for (var j = 0; j < dataShards.Length; j++)
 | 
						|
             {
 | 
						|
                 var shard = dataShards[j] = new byte[shardSize];
 | 
						|
                 for (int i = 0; i < shard.Length; i++) {
 | 
						|
                     shard[i] = (byte) random.Next(256);
 | 
						|
                 }
 | 
						|
             }
 | 
						|
             runEncodeDecode(dataCount, parityCount, dataShards);
 | 
						|
         }
 | 
						|
 | 
						|
        Console.WriteLine("测试完成");
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Encodes a set of data shards, and then tries decoding
 | 
						|
     * using all possible subsets of the encoded shards.
 | 
						|
     *
 | 
						|
     * Uses 5+5 coding, so there must be 5 input data shards.
 | 
						|
     */
 | 
						|
    private void runEncodeDecode(int dataCount, int parityCount, byte[][] dataShards) {
 | 
						|
 | 
						|
         int totalCount = dataCount + parityCount;
 | 
						|
         int shardLength = dataShards[0].Length;
 | 
						|
 | 
						|
        // Make the list of data and parity shards.
 | 
						|
//        assertEquals(dataCount, dataShards.length);
 | 
						|
         int dataLength = dataShards[0].Length;
 | 
						|
         byte [] [] allShards = new byte [totalCount] [];
 | 
						|
        for (int i = 0; i < dataCount; i++) {
 | 
						|
            byte[] temp = new byte[dataLength];
 | 
						|
            Array.Copy(dataShards[i],0,temp,0,dataLength);
 | 
						|
            allShards[i] = temp;
 | 
						|
        }
 | 
						|
        for (int i = dataCount; i < totalCount; i++) {
 | 
						|
            allShards[i] = new byte [dataLength];
 | 
						|
        }
 | 
						|
 | 
						|
        // Encode.
 | 
						|
        ReedSolomon codec = ReedSolomon.create(dataCount, parityCount);
 | 
						|
        codec.encodeParity(allShards, 0, dataLength);
 | 
						|
 | 
						|
        // Make a copy to decode with.
 | 
						|
        byte [] [] testShards = new byte [totalCount] [];
 | 
						|
        bool [] shardPresent = new bool [totalCount];
 | 
						|
        for (int i = 0; i < totalCount; i++) {
 | 
						|
            byte[] temp = new byte[shardLength];
 | 
						|
            Array.Copy(allShards[i],0,temp,0,shardLength);
 | 
						|
            testShards[i] = temp;
 | 
						|
            shardPresent[i] = true;
 | 
						|
        }
 | 
						|
 | 
						|
        // Decode with 0, 1, ..., 5 shards missing.
 | 
						|
        for (int numberMissing = 0; numberMissing < parityCount + 1; numberMissing++) {
 | 
						|
            tryAllSubsetsMissing(codec, allShards, testShards, shardPresent, numberMissing);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    private void tryAllSubsetsMissing(ReedSolomon codec,
 | 
						|
        byte [] [] allShards, byte [] [] testShards,
 | 
						|
                                      bool [] shardPresent, int numberMissing) {
 | 
						|
         int shardLength = allShards[0].Length;
 | 
						|
        List<int []> subsets = allSubsets(numberMissing, 0, 10);
 | 
						|
        foreach (var subset in subsets) {
 | 
						|
            // Get rid of the shards specified by this subset.
 | 
						|
            foreach (var missingShard in subset)
 | 
						|
            {
 | 
						|
                clearBytes(testShards[missingShard]);
 | 
						|
                shardPresent[missingShard] = false;
 | 
						|
            }
 | 
						|
 | 
						|
            // Reconstruct the missing shards
 | 
						|
            codec.decodeMissing(testShards, shardPresent, 0, shardLength);
 | 
						|
 | 
						|
            // Check the results.  After checking, the contents of testShards
 | 
						|
            // is ready for the next test, the next time through the loop.
 | 
						|
            checkShards(allShards, testShards);
 | 
						|
 | 
						|
            // Put the "present" flags back
 | 
						|
            for (int i = 0; i < codec.getTotalShardCount(); i++) {
 | 
						|
                shardPresent[i] = true;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
    private void assertTrue(bool isParityCorrect)
 | 
						|
    {
 | 
						|
        throw new NotImplementedException();
 | 
						|
    }
 | 
						|
 | 
						|
    private void assertFalse(bool isParityCorrect)
 | 
						|
    {
 | 
						|
        throw new NotImplementedException();
 | 
						|
    }
 | 
						|
 | 
						|
    private void clearBytes(byte [] data) {
 | 
						|
        for (int i = 0; i < data.Length; i++) {
 | 
						|
            data[i] = 0;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    private void checkShards(byte[][] expectedShards, byte[][] actualShards) {
 | 
						|
        assertEquals(expectedShards.Length, actualShards.Length);
 | 
						|
        for (int i = 0; i < expectedShards.Length; i++) {
 | 
						|
            assertArrayEquals(expectedShards[i], actualShards[i]);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    private void assertArrayEquals(byte[] expectedShard, byte[] actualShard)
 | 
						|
    {
 | 
						|
 | 
						|
        var len1 = expectedShard.Length;
 | 
						|
        var len2 = actualShard.Length;
 | 
						|
        if (len1 != len2)
 | 
						|
        {
 | 
						|
            throw new NotImplementedException();
 | 
						|
        }
 | 
						|
        for (var i = 0; i < len1; i++)
 | 
						|
        {
 | 
						|
            if (expectedShard[i] != actualShard[i])
 | 
						|
            {
 | 
						|
                throw new NotImplementedException();
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    private void assertEquals(int expectedShardsLength, int actualShardsLength)
 | 
						|
    {
 | 
						|
        if (expectedShardsLength != actualShardsLength)
 | 
						|
        {
 | 
						|
            throw new NotImplementedException();
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns a list of arrays with all possible sets of
 | 
						|
     * unique values where (min <= n < max).
 | 
						|
     *
 | 
						|
     * This is NOT EFFICIENT, because it allocates lots of
 | 
						|
     * temporary arrays, but it's OK for these tests.
 | 
						|
     *
 | 
						|
     * To avoid duplicates that are in a different order,
 | 
						|
     * each subset is generated with elements in increasing
 | 
						|
     * order.
 | 
						|
     *
 | 
						|
     * Given (n=2, min=1, max=4), returns:
 | 
						|
     *    [1, 2]
 | 
						|
     *    [1, 3]
 | 
						|
     *    [1, 4]
 | 
						|
     *    [2, 3]
 | 
						|
     *    [2, 4]
 | 
						|
     *    [3, 4]
 | 
						|
     */
 | 
						|
    private List<int []> allSubsets(int n, int min, int max) {
 | 
						|
        List<int []> result = new List<int[]>();
 | 
						|
        if (n == 0) {
 | 
						|
            result.Add(new int [0]);
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            for (int i = min; i < max - n; i++) {
 | 
						|
                int [] prefix = { i };
 | 
						|
                foreach (var suffix in allSubsets(n - 1, i + 1, max))
 | 
						|
                {
 | 
						|
                    result.Add(appendIntArrays(prefix, suffix));
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return result;
 | 
						|
    }
 | 
						|
 | 
						|
    private int [] appendIntArrays(int [] a, int [] b) {
 | 
						|
        int [] result = new int[a.Length + b.Length];
 | 
						|
        Array.Copy(a, 0, result, 0, a.Length);
 | 
						|
        Array.Copy(b, 0, result, a.Length, b.Length);
 | 
						|
        return result;
 | 
						|
    }
 | 
						|
    }
 | 
						|
} |