@@ -115,7 +115,8 @@ class StringKWargs(TypedDict):
115
115
116
116
117
117
class BytesKWargs (TypedDict ):
118
- size : int
118
+ min_size : int
119
+ max_size : Optional [int ]
119
120
120
121
121
122
class BooleanKWargs (TypedDict ):
@@ -206,7 +207,7 @@ def structural_coverage(label: int) -> StructuralCoverageTag:
206
207
FLOAT_INIT_LOGIC_CACHE = LRUCache (4096 )
207
208
POOLED_KWARGS_CACHE = LRUCache (4096 )
208
209
209
- DRAW_STRING_DEFAULT_MAX_SIZE = 10 ** 10 # "arbitrarily large"
210
+ COLLECTION_DEFAULT_MAX_SIZE = 10 ** 10 # "arbitrarily large"
210
211
211
212
212
213
class Example :
@@ -1036,7 +1037,7 @@ def trivial(self):
1036
1037
return self .value == (minimal_char * self .kwargs ["min_size" ])
1037
1038
if self .ir_type == "bytes" :
1038
1039
# smallest size and all-zero value.
1039
- return len (self .value ) == self .kwargs ["size " ] and not any (self .value )
1040
+ return len (self .value ) == self .kwargs ["min_size " ] and not any (self .value )
1040
1041
1041
1042
raise NotImplementedError (f"unhandled ir_type { self .ir_type } " )
1042
1043
@@ -1095,7 +1096,11 @@ def ir_value_permitted(value, ir_type, kwargs):
1095
1096
return False
1096
1097
return all (ord (c ) in kwargs ["intervals" ] for c in value )
1097
1098
elif ir_type == "bytes" :
1098
- return len (value ) == kwargs ["size" ]
1099
+ if len (value ) < kwargs ["min_size" ]:
1100
+ return False
1101
+ if kwargs ["max_size" ] is not None and len (value ) > kwargs ["max_size" ]:
1102
+ return False
1103
+ return True
1099
1104
elif ir_type == "boolean" :
1100
1105
if kwargs ["p" ] <= 2 ** (- 64 ):
1101
1106
return value is False
@@ -1322,7 +1327,12 @@ def draw_string(
1322
1327
1323
1328
@abc .abstractmethod
1324
1329
def draw_bytes (
1325
- self , size : int , * , forced : Optional [bytes ] = None , fake_forced : bool = False
1330
+ self ,
1331
+ min_size : int ,
1332
+ max_size : Optional [int ],
1333
+ * ,
1334
+ forced : Optional [bytes ] = None ,
1335
+ fake_forced : bool = False ,
1326
1336
) -> bytes :
1327
1337
raise NotImplementedError
1328
1338
@@ -1611,7 +1621,7 @@ def draw_string(
1611
1621
fake_forced : bool = False ,
1612
1622
) -> str :
1613
1623
if max_size is None :
1614
- max_size = DRAW_STRING_DEFAULT_MAX_SIZE
1624
+ max_size = COLLECTION_DEFAULT_MAX_SIZE
1615
1625
1616
1626
assert forced is None or min_size <= len (forced ) <= max_size
1617
1627
assert self ._cd is not None
@@ -1663,17 +1673,44 @@ def draw_string(
1663
1673
return "" .join (chars )
1664
1674
1665
1675
def draw_bytes (
1666
- self , size : int , * , forced : Optional [bytes ] = None , fake_forced : bool = False
1676
+ self ,
1677
+ min_size : int ,
1678
+ max_size : Optional [int ],
1679
+ * ,
1680
+ forced : Optional [bytes ] = None ,
1681
+ fake_forced : bool = False ,
1667
1682
) -> bytes :
1668
- forced_i = None
1669
- if forced is not None :
1670
- forced_i = int_from_bytes (forced )
1671
- size = len (forced )
1683
+ if max_size is None :
1684
+ max_size = COLLECTION_DEFAULT_MAX_SIZE
1672
1685
1673
- assert self ._cd is not None
1674
- return self ._cd .draw_bits (
1675
- 8 * size , forced = forced_i , fake_forced = fake_forced
1676
- ).to_bytes (size , "big" )
1686
+ assert forced is None or min_size <= len (forced ) <= max_size
1687
+
1688
+ buf = bytearray ()
1689
+ average_size = min (
1690
+ max (min_size * 2 , min_size + 5 ),
1691
+ 0.5 * (min_size + max_size ),
1692
+ )
1693
+ elements = many (
1694
+ self ._cd ,
1695
+ min_size = min_size ,
1696
+ max_size = max_size ,
1697
+ average_size = average_size ,
1698
+ forced = None if forced is None else len (forced ),
1699
+ fake_forced = fake_forced ,
1700
+ observe = False ,
1701
+ )
1702
+ while elements .more ():
1703
+ forced_i : Optional [int ] = None
1704
+ if forced is not None :
1705
+ # implicit conversion from bytes to int by indexing here
1706
+ forced_i = forced [elements .count - 1 ]
1707
+
1708
+ assert self ._cd is not None
1709
+ buf += self ._cd .draw_bits (
1710
+ 8 , forced = forced_i , fake_forced = fake_forced
1711
+ ).to_bytes (1 , "big" )
1712
+
1713
+ return bytes (buf )
1677
1714
1678
1715
def _draw_float (
1679
1716
self ,
@@ -2222,6 +2259,7 @@ def draw_string(
2222
2259
observe : bool = True ,
2223
2260
) -> str :
2224
2261
assert forced is None or min_size <= len (forced )
2262
+ assert min_size >= 0
2225
2263
2226
2264
kwargs : StringKWargs = self ._pooled_kwargs (
2227
2265
"string" ,
@@ -2255,17 +2293,19 @@ def draw_string(
2255
2293
2256
2294
def draw_bytes (
2257
2295
self ,
2258
- # TODO move to min_size and max_size here.
2259
- size : int ,
2296
+ min_size : int ,
2297
+ max_size : Optional [ int ] ,
2260
2298
* ,
2261
2299
forced : Optional [bytes ] = None ,
2262
2300
fake_forced : bool = False ,
2263
2301
observe : bool = True ,
2264
2302
) -> bytes :
2265
- assert forced is None or len (forced ) == size
2266
- assert size >= 0
2303
+ assert forced is None or min_size <= len (forced )
2304
+ assert min_size >= 0
2267
2305
2268
- kwargs : BytesKWargs = self ._pooled_kwargs ("bytes" , {"size" : size })
2306
+ kwargs : BytesKWargs = self ._pooled_kwargs (
2307
+ "bytes" , {"min_size" : min_size , "max_size" : max_size }
2308
+ )
2269
2309
2270
2310
if self .ir_tree_nodes is not None and observe :
2271
2311
node_value = self ._pop_ir_tree_node ("bytes" , kwargs , forced = forced )
0 commit comments