@@ -11,7 +11,7 @@ class SubEntry:
1111class Parameter :
1212 name : str
1313 index : int
14- entry : SubEntry
14+ entries : List [ SubEntry ]
1515 mode : int # 0: orig*(1+x), 1: =x, 2: orig+x
1616 typ : int # 1: int, else: float
1717 precision : int
@@ -85,7 +85,7 @@ def register_param(
8585 precision = lib_info .file .precision
8686 lb = lib_info .lb if hardBound else None
8787 ub = lib_info .ub if hardBound else None
88-
88+ maxNum = lib_info . file . maxNum
8989 line_idx = linePos - 1
9090
9191 if typ == 1 :
@@ -95,18 +95,23 @@ def register_param(
9595 ub = int (ub )
9696
9797 line_start = self .line_offsets [line_idx ]
98-
99- off = line_start + (staPos - 1 )
100-
101- field = bytes (self .base_content [off :off + width ])
102- val = self ._parse_float_field (field )
103-
104- entry = SubEntry (offset = off , original_val = val )
98+ # TODO
99+ if line_idx + 1 < len (self .line_offsets ):
100+ line_end = self .line_offsets [line_idx + 1 ]
101+ else :
102+ line_end = len (self .base_content )
103+ base_offset = line_start + (staPos - 1 )
104+ entries = self ._scan_entries (
105+ start_offset = base_offset ,
106+ width = width ,
107+ max_num = maxNum ,
108+ line_end_offset = line_end
109+ )
105110
106111 self .params [index ] = Parameter (
107112 name = name ,
108113 index = index ,
109- entry = entry ,
114+ entries = entries ,
110115 mode = mode ,
111116 typ = typ ,
112117 precision = precision ,
@@ -118,66 +123,85 @@ def register_param(
118123 return True
119124
120125 def set_values_and_save (
121- self ,
122- output_filepath : str ,
123- indices : List [int ],
124- vals : List [float ],
125- warn_stacklevel : int = 2 ,
126- warn_detail_limit : int = 20 ,
127- ):
126+ self ,
127+ output_filepath : str ,
128+ indices : List [int ],
129+ vals : List [float ],
130+ warn_stacklevel : int = 2 ,
131+ warn_detail_limit : int = 20 ,
132+ ):
133+
134+ self .file_content = bytearray (self .base_content )
135+ mods : List [Modification ] = []
136+ clamp_events = []
137+
138+ for idx , input_val in zip (indices , vals ):
139+ p = self .params .get (idx )
140+ if not p :
141+ continue
142+
143+ for e in p .entries :
144+
145+ if p .mode == 0 : # relative %
146+ raw = e .original_val * (1.0 + float (input_val ))
147+ elif p .mode == 1 : # replace
148+ raw = float (input_val )
149+ elif p .mode == 2 : # absolute add
150+ raw = e .original_val + float (input_val )
151+ else :
152+ raw = float (input_val )
153+
154+ raw2 = int (raw ) if p .typ == 1 else raw
155+
156+ clamped = raw2
157+ if p .lb is not None and clamped < p .lb :
158+ clamped = p .lb
159+ if p .ub is not None and clamped > p .ub :
160+ clamped = p .ub
161+
162+ if clamped != raw2 :
163+ clamp_events .append ((idx , p .name , raw2 , clamped , p .lb , p .ub ))
164+
165+ b = self ._format_value (clamped , p .width , p .precision , p .typ )
166+ mods .append (Modification (offset = e .offset , width = p .width , data = b ))
167+
168+ for m in mods :
169+ self .file_content [m .offset : m .offset + m .width ] = m .data
170+
171+ if clamp_events :
172+ head = clamp_events [:warn_detail_limit ]
173+ msg_lines = [
174+ f"Param clamp: { output_filepath } , idx={ i } , raw={ raw :.2f} ->{ clamped :.2f} "
175+ for (i , name , raw , clamped , lb , ub ) in head
176+ ]
177+ more = "" if len (clamp_events ) <= warn_detail_limit else f"\n ... { len (clamp_events )- warn_detail_limit } more"
178+ warnings .warn ("\n " .join (msg_lines ) + more , stacklevel = warn_stacklevel )
179+
180+ with open (output_filepath , "wb" ) as out :
181+ out .write (self .file_content )
182+
183+ def _scan_entries (
184+ self , start_offset : int , width : int , max_num : int , line_end_offset : int
185+ ) -> List [SubEntry ]:
186+
187+ entries = []
128188
129- self .file_content = bytearray (self .base_content )
189+ for i in range (max_num ):
190+ curr_off = start_offset + (i * width )
191+ curr_end = curr_off + width
192+
193+ if curr_end > line_end_offset :
194+ break
195+
196+ if curr_end > len (self .base_content ):
197+ break
198+
199+ field = bytes (self .base_content [curr_off : curr_end ])
200+ val = self ._parse_float_field (field )
130201
131- mods : List [ Modification ] = []
132- clamp_events = []
202+ if val is None :
203+ break
133204
134- for idx , input_val in zip ( indices , vals ):
205+ entries . append ( SubEntry ( offset = curr_off , original_val = val ))
135206
136- p = self .params .get (idx )
137- if not p :
138- continue
139-
140- e = p .entry
141-
142- # 1) calculate raw
143- if p .mode == 0 :
144- raw = e .original_val * (1.0 + float (input_val ))
145- elif p .mode == 1 :
146- raw = float (input_val )
147- elif p .mode == 2 :
148- raw = e .original_val + float (input_val )
149- else :
150- raw = float (input_val )
151-
152- # 2) transform type
153- raw2 = int (raw ) if p .typ == 1 else raw
154-
155- # 3) clamp (warning)
156- clamped = raw2
157- if p .lb is not None and clamped < p .lb :
158- clamped = p .lb
159- if p .ub is not None and clamped > p .ub :
160- clamped = p .ub
161-
162- if clamped != raw2 :
163- clamp_events .append ((idx , p .name , raw2 , clamped , p .lb , p .ub ))
164-
165- b = self ._format_value (clamped , p .width , p .precision , p .typ )
166- mods .append (Modification (offset = e .offset , width = p .width , data = b ))
167-
168- for m in mods :
169- self .file_content [m .offset :m .offset + m .width ] = m .data
170-
171- if clamp_events :
172- head = clamp_events [:warn_detail_limit ]
173- msg_lines = [
174- f"Param clamp: in file { output_filepath } , idx={ i } , name={ name } , { raw } -> { clamped } , hardBounds=[{ lb } ,{ ub } ]"
175- for (i , name , raw , clamped , lb , ub ) in head
176- ]
177- more = "" if len (clamp_events ) <= warn_detail_limit else (
178- f"\n ... and { len (clamp_events ) - warn_detail_limit } more clamps"
179- )
180- warnings .warn ("\n " .join (msg_lines ) + more , stacklevel = warn_stacklevel )
181-
182- with open (output_filepath , "wb" ) as out :
183- out .write (self .file_content )
207+ return entries
0 commit comments