All files / TRANSPILE/3-Render/codegen/helpers BitRangeHelper.ts

100% Statements 16/16
100% Branches 12/12
100% Functions 5/5
100% Lines 16/16

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120                                                                                          5x     5x       5x 3x       2x 2x                     8x     8x 4x   4x       8x 3x     5x                           306x             4x                   2x          
/**
 * Helper utilities for generating bit range access code.
 * Extracted from CodeGenerator to improve testability.
 */
 
import type TranspileState from "../../../TranspileState";
import NarrowingCastHelper from "./NarrowingCastHelper";
 
/**
 * Options for generating float bit read expressions.
 */
interface IFloatBitReadOptions {
  shadowName: string;
  varName: string;
  start: string;
  mask: string;
  shadowIsCurrent: boolean;
}
 
/**
 * Options for generating integer bit read expressions.
 */
interface IIntegerBitReadOptions {
  varName: string;
  start: string;
  mask: string;
  sourceType?: string; // Optional: source variable type for cast detection
  targetType?: string; // Optional: target variable type for cast
 
  /**
   * 2.3 Render's per-file working state (#1452 box 4), needed only for the
   * MISRA 10.3 cast, which asks the run's C++ mode.
   */
  state: TranspileState;
}
 
/**
 * Helper class for bit range access code generation.
 */
class BitRangeHelper {
  /**
   * Build the bit read expression for floats.
   * Uses memcpy pattern to safely reinterpret float bits.
   */
  static buildFloatBitReadExpr(options: IFloatBitReadOptions): string {
    const { shadowName, varName, start, mask, shadowIsCurrent } = options;
 
    const shiftedRead =
      start === "0"
        ? `(${shadowName} & ${mask})`
        : `((${shadowName} >> ${start}) & ${mask})`;
 
    if (shadowIsCurrent) {
      return shiftedRead;
    }
 
    // Need memcpy to update shadow
    const memcpyPrefix = `memcpy(&${shadowName}, &${varName}, sizeof(${varName}))`;
    return `(${memcpyPrefix}, ${shiftedRead})`;
  }
 
  /**
   * Generate integer bit range read: ((value >> start) & mask)
   * Optimizes away the shift when start is 0.
   *
   * When sourceType and targetType are provided, wraps the expression
   * with MISRA 10.3 compliant cast if needed.
   */
  static buildIntegerBitReadExpr(options: IIntegerBitReadOptions): string {
    const { varName, start, mask, sourceType, targetType, state } = options;
 
    let expr: string;
    if (start === "0") {
      expr = `((${varName}) & ${mask})`;
    } else {
      expr = `((${varName} >> ${start}) & ${mask})`;
    }
 
    // If target type provided, wrap with MISRA cast if needed
    if (sourceType && targetType) {
      return NarrowingCastHelper.wrap(expr, sourceType, targetType, state);
    }
 
    return expr;
  }
 
  /**
   * Generate the shadow variable name for float bit access.
   *
   * #1322: the single encoder. The same `__bits_` prefix was also built inline
   * in `FloatBitHelper`, in `PostfixExpressionGenerator`'s float bit-range
   * path, and in the assignment path that invalidates a shadow -- four homes
   * for one decision, so changing the prefix meant four edits and any missed
   * one would have written a shadow under a name nothing read back. The three
   * others call this now.
   */
  static getShadowVarName(rawName: string): string {
    return `__bits_${rawName}`;
  }
 
  /**
   * Get the shadow type for a float type.
   */
  static getShadowType(baseType: string): string {
    return baseType === "f64" ? "uint64_t" : "uint32_t";
  }
 
  /**
   * Generate a shadow variable declaration.
   */
  static buildShadowDeclaration(
    shadowName: string,
    shadowType: string,
  ): string {
    return `${shadowType} ${shadowName};`;
  }
}
 
export default BitRangeHelper;