Exemplo n.º 1
0
        static EnumBitStreamer()
        {
            var        generation_args = new MethodGenerationArgs();
            MethodInfo read_method_info, write_method_info, swap_method;

            #region Get read/write method info
            if (generation_args.UseUnderlyingType)
            {
                // Since we use a type-parameter hack to imply we want to use the underlying type
                // for the TStreamType, we have to use reflection to instantiate StreamType<>
                // using kUnderlyingType, which kStreamType is set to up above
                var stream_type_gen_class = typeof(StreamType <>);
                var stream_type_class     = stream_type_gen_class.MakeGenericType(generation_args.StreamType);
                read_method_info  = stream_type_class.GetField("kRead").GetValue(null) as MethodInfo;
                write_method_info = stream_type_class.GetField("kWrite").GetValue(null) as MethodInfo;
                swap_method       = stream_type_class.GetField("kBitSwap").GetValue(null) as MethodInfo;
            }
            else
            {
                // If we don't use the type-parameter hack and instead are explicitly given the
                // integer type, we can safely instantiate StreamType<> without reflection
                read_method_info  = StreamType <TStreamType> .kRead;
                write_method_info = StreamType <TStreamType> .kWrite;
                swap_method       = StreamType <TStreamType> .kBitSwap;
            }
            #endregion

            kRead  = GenerateReadMethod(generation_args, read_method_info, swap_method);
            kWrite = GenerateWriteMethod(generation_args, write_method_info, swap_method);

            Instance = new EnumBitStreamer <TEnum, TStreamType, TOptions>();
        }
Exemplo n.º 2
0
        /// <summary>Generates a method similar to this:
        /// <code>
        /// void Write(IO.BitStream s, TEnum v, int bitCount)
        /// {
        ///     s.Write((TStreamType)v, bitCount);
        /// }
        /// </code>
        /// </summary>
        /// <returns>The generated method.</returns>
        /// <param name="args"></param>
        /// <param name="writeMethodInfo"></param>
        /// <param name="bitSwapMethod"></param>
        /// <remarks>
        /// If <see cref="args.UnderlyingType"/> is the same as <typeparamref name="TStreamType"/>, no conversion code is generated
        /// </remarks>
        static Action <IO.BitStream, TEnum, int> GenerateWriteMethod(MethodGenerationArgs args, MethodInfo writeMethodInfo, MethodInfo bitSwapMethod)
        {
            //////////////////////////////////////////////////////////////////////////
            // Define the generated method's parameters
            var param_s  = Expr.Parameter(kBitStreamType, "s");                                                         // BitStream s
            var param_v  = Expr.Parameter(args.EnumType, "v");                                                          // TEnum v
            var param_bc = Expr.Parameter(typeof(int), "bitCount");                                                     // int bitCount

            //////////////////////////////////////////////////////////////////////////
            // Define the member access
            var param_v_member = Expr.PropertyOrField(param_v, EnumUtils.kMemberName);                  // i.e., 'v.value__'
            var write_param    = args.UnderlyingTypeNeedsConversion ?                                   // If the underlying type is different from the type we're writing,
                                 Expr.Convert(param_v_member, args.StreamType) :                        // we need to cast the Write param from UnderlyingType to TStreamType
                                 (Expr)param_v_member;

            if (args.Options.UseNoneSentinelEncoding)
            {
                write_param = Expr.Increment(write_param);
            }

            #region options.BitSwap
            if (args.Options.BitSwap)
            {
                // i.e., Bits.BitSwap( value, bitCount-1 );
                var  start_bit_index = Expr.Decrement(param_bc);
                Expr swap_call       = Expr.Call(null, bitSwapMethod, write_param, start_bit_index);

                // i.e., bitCount-1 ? Bits.BitSwap( value, bitCount-1 ) : value ;
                if (args.Options.BitSwapGuardAgainstOneBit)
                {
                    var start_bit_index_is_not_zero = Expr.NotEqual(start_bit_index, Expr.Constant(0, typeof(int)));
                    swap_call = Expr.Condition(start_bit_index_is_not_zero,
                                               swap_call, write_param);
                }

                write_param = swap_call;
            }
            #endregion

            //////////////////////////////////////////////////////////////////////////
            // Define the Write call
            // i.e., 's.Write(v.value__, bitCount)' or 's.Write((TStreamType)v.value__, bitCount)'
            var call_write = Expr.Call(param_s, writeMethodInfo, write_param, param_bc);

            //////////////////////////////////////////////////////////////////////////
            // Generate a method based on the expression tree we've built
            var lambda = Expr.Lambda <Action <IO.BitStream, TEnum, int> >(call_write, param_s, param_v, param_bc);
            return(lambda.Compile());
        }
Exemplo n.º 3
0
        /// <summary>Generates a method similar to this:
        /// <code>
        /// void Read(IO.BitStream s, out TEnum v, int bitCount)
        /// {
        ///     v = (UnderlyingType)s.Read[TStreamType](bitCount);
        /// }
        /// </code>
        /// </summary>
        /// <param name="args"></param>
        /// <param name="readMethodInfo"></param>
        /// <param name="bitSwapMethod"></param>
        /// <returns>The generated method.</returns>
        /// <remarks>
        /// If <see cref="args.UnderlyingType"/> is the same as <typeparamref name="TStreamType"/>, no conversion code is generated
        /// </remarks>
        static ReadDelegate GenerateReadMethod(MethodGenerationArgs args, MethodInfo readMethodInfo, MethodInfo bitSwapMethod)
        {
            // Get a "ref type" of the enum we're dealing with so we can define the enum value as an 'out' parameter
            var enum_ref = args.EnumType.MakeByRefType();

            //////////////////////////////////////////////////////////////////////////
            // Define the generated method's parameters
            var param_s  = Expr.Parameter(kBitStreamType, "s");                                                         // BitStream s
            var param_v  = Expr.Parameter(enum_ref, "v");                                                               // ref TEnum v
            var param_bc = Expr.Parameter(typeof(int), "bitCount");                                                     // int bitCount

            //////////////////////////////////////////////////////////////////////////
            // Define the Read call
            Expr call_read;

            if (args.StreamTypeIsSigned)
            {
                call_read = Expr.Call(param_s, readMethodInfo, param_bc, Expr.Constant(args.Options.SignExtend));
            }
            else
            {
                call_read = Expr.Call(param_s, readMethodInfo, param_bc);                                               // i.e., 's.Read<Type>(bitCount)'
            }
            if (args.Options.UseNoneSentinelEncoding)
            {
                call_read = Expr.Decrement(call_read);
            }

            #region options.BitSwap
            if (args.Options.BitSwap)
            {
                // i.e., Bits.BitSwap( Read(), bitCount-1 );
                var  start_bit_index = Expr.Decrement(param_bc);
                Expr swap_call       = Expr.Call(null, bitSwapMethod, call_read, start_bit_index);

                // i.e., bitCount-1 ? Bits.BitSwap( Read(), bitCount-1 ) : Read() ;
                if (args.Options.BitSwapGuardAgainstOneBit)
                {
                    var start_bit_index_is_not_zero = Expr.NotEqual(start_bit_index, Expr.Constant(0, typeof(int)));
                    swap_call = Expr.Condition(start_bit_index_is_not_zero,
                                               swap_call, call_read);
                }

                call_read = swap_call;
            }
            #endregion

            var read_result = args.UnderlyingTypeNeedsConversion ?                                                      // If the underlying type is different from the type we're reading,
                              Expr.Convert(call_read, args.UnderlyingType) :                                            // we need to cast the Read result from TStreamType to UnderlyingType
                              (Expr)call_read;

            //////////////////////////////////////////////////////////////////////////
            // Define the member assignment
            var param_v_member = Expr.PropertyOrField(param_v, EnumUtils.kMemberName);                  // i.e., 'v.value__'
            // i.e., 'v.value__ = s.Read<Type>()' or 'v.value__ = (UnderlyingType)s.Read<Type>()'
            var assign = Expr.Assign(param_v_member, read_result);

            //////////////////////////////////////////////////////////////////////////
            // Generate a method based on the expression tree we've built
            var lambda = Expr.Lambda <ReadDelegate>(assign, param_s, param_v, param_bc);
            return(lambda.Compile());
        }