From 9a68d3658e9d4f71121f90a1e0489898fea849f5 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Fri, 22 May 2026 12:33:12 +0300 Subject: rpn: eliminate duplicated prefixMode state between RPN and Operations Remove the prefixMode field from the RPN struct; it was duplicated from Operations where it is actually used. Add GetPrefixMode to the Operator interface so RPN can delegate both GetPrefixMode and SetPrefixMode to the Operations instance behind the interface. In rpn_parse.go evaluate(), drop the direct r.prefixMode = IEC/SI writes and the now-unnecessary lock ordering comment; only r.ops.SetPrefixMode() remains. --- internal/rpn/operations.go | 2 ++ internal/rpn/rpn_parse.go | 5 ----- internal/rpn/rpn_state.go | 8 +++----- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/internal/rpn/operations.go b/internal/rpn/operations.go index 04c2014..d45ffd1 100644 --- a/internal/rpn/operations.go +++ b/internal/rpn/operations.go @@ -158,6 +158,8 @@ type Operator interface { SetMode(CalculationMode) // SetPrefixMode sets the prefix mode for data size calculations SetPrefixMode(PrefixMode) + // GetPrefixMode returns the current prefix mode + GetPrefixMode() PrefixMode // Metric command handlers MetricShow(stack *Stack) (string, error) MetricList(stack *Stack) (string, error) diff --git a/internal/rpn/rpn_parse.go b/internal/rpn/rpn_parse.go index 7abd41c..ab64ec7 100644 --- a/internal/rpn/rpn_parse.go +++ b/internal/rpn/rpn_parse.go @@ -367,17 +367,12 @@ func (r *RPN) evaluate(input string, tokens []string) (string, error) { return result, nil case "binary": if i+2 < len(tokens) && tokens[i+2] == "set" { - // Lock order: r.mu → o.mu (same as RPN.SetPrefixMode) - // No deadlock risk: both paths acquire in the same direction. - // r.mu is held by evaluate(); o.mu is a separate mutex on Operations. - r.prefixMode = IEC r.ops.SetPrefixMode(IEC) return "prefix mode: IEC", nil } return "", fmt.Errorf("rpn: metric binary: use 'metric binary set'") case "decimal": if i+2 < len(tokens) && tokens[i+2] == "set" { - r.prefixMode = SI r.ops.SetPrefixMode(SI) return "prefix mode: SI", nil } diff --git a/internal/rpn/rpn_state.go b/internal/rpn/rpn_state.go index 3b63984..a146409 100644 --- a/internal/rpn/rpn_state.go +++ b/internal/rpn/rpn_state.go @@ -20,7 +20,6 @@ type RPN struct { maxStack int currentStack *Stack mode CalculationMode - prefixMode PrefixMode } // NewRPN creates a new RPN parser and evaluator with the given variable store. @@ -37,7 +36,6 @@ func NewRPN(vars VariableStore) *RPN { maxStack: 1000, // Reasonable limit for RPN expressions currentStack: NewStack(), mode: FloatMode, // Default mode - prefixMode: SI, // Default prefix mode } } @@ -96,19 +94,19 @@ func (r *RPN) Stack() []Number { } // SetPrefixMode sets the prefix mode (SI or IEC). -// Propagates to the Operations instance so arithmetic uses the correct mode. +// Delegates to the Operations instance. // This method is thread-safe for writes. func (r *RPN) SetPrefixMode(mode PrefixMode) { r.mu.Lock() defer r.mu.Unlock() - r.prefixMode = mode r.ops.SetPrefixMode(mode) } // GetPrefixMode returns the current prefix mode. +// Delegates to the Operations instance. // This method is thread-safe for concurrent reads. func (r *RPN) GetPrefixMode() PrefixMode { r.mu.RLock() defer r.mu.RUnlock() - return r.prefixMode + return r.ops.GetPrefixMode() } -- cgit v1.2.3