@@ -192,13 +192,18 @@ func (s *KeywordMapShape) indexOf(key Keyword) int {
192192}
193193
194194func newArrayMap (keyVals []any ) * Map {
195- if len (keyVals ) <= arrayMapInlineSize {
195+ m := newArrayMapWithSize (len (keyVals ))
196+ copy (m .keyVals , keyVals )
197+ return m
198+ }
199+
200+ func newArrayMapWithSize (size int ) * Map {
201+ if size <= arrayMapInlineSize {
196202 storage := & inlineMapStorage {}
197- copy (storage .keyVals [:], keyVals )
198- storage .Map .keyVals = storage .keyVals [:len (keyVals )]
203+ storage .Map .keyVals = storage .keyVals [:size ]
199204 return & storage .Map
200205 }
201- return & Map {keyVals : append ([]any ( nil ), keyVals ... )}
206+ return & Map {keyVals : make ([]any , size )}
202207}
203208
204209// canBePersistentArrayMap mirrors Clojure's PersistentArrayMap thresholds.
@@ -221,7 +226,8 @@ func canBePersistentArrayMap(keyVals []any) bool {
221226}
222227
223228func NewPersistentArrayMapAsIfByAssoc (init []any ) IPersistentMap {
224- complexPath := (len (init ) & 1 ) == 1
229+ hasTrailing := (len (init ) & 1 ) == 1
230+ complexPath := hasTrailing
225231 for i := 0 ; i < len (init ) && ! complexPath ; i += 2 {
226232 for j := 0 ; j < i ; j += 2 {
227233 if equalKey (init [i ], init [j ]) {
@@ -232,13 +238,28 @@ func NewPersistentArrayMapAsIfByAssoc(init []any) IPersistentMap {
232238 }
233239
234240 if complexPath {
235- return newPersistentArrayMapAsIfByAssocComplexPath (init )
241+ return newPersistentArrayMapAsIfByAssocComplexPath (init , hasTrailing )
236242 }
237243
238- return NewMap (init ... )
244+ return newArrayMap (init )
239245}
240246
241- func newPersistentArrayMapAsIfByAssocComplexPath (init []any ) IPersistentMap {
247+ func newPersistentArrayMapAsIfByAssocComplexPath (init []any , hasTrailing bool ) IPersistentMap {
248+ if hasTrailing {
249+ trailing := emptyMap .Cons (init [len (init )- 1 ]).(IPersistentMap )
250+ seedCount := len (init ) - 1
251+ grown := make ([]any , seedCount + trailing .Count ()* 2 )
252+ copy (grown , init [:seedCount ])
253+ i := seedCount
254+ for seq := trailing .Seq (); seq != nil ; seq = seq .Next () {
255+ entry := seq .First ().(IMapEntry )
256+ grown [i ] = entry .Key ()
257+ grown [i + 1 ] = entry .Val ()
258+ i += 2
259+ }
260+ init = grown
261+ }
262+
242263 n := 0
243264 for i := 0 ; i < len (init ); i += 2 {
244265 duplicateKey := false
@@ -283,7 +304,7 @@ func newPersistentArrayMapAsIfByAssocComplexPath(init []any) IPersistentMap {
283304 }
284305 init = nodups
285306 }
286- return NewMap (init ... )
307+ return newArrayMap (init )
287308}
288309
289310func (m * Map ) ValAt (key any ) any {
@@ -479,13 +500,25 @@ func (m *Map) Without(k any) IPersistentMap {
479500 }
480501 return NewMapUniqueKeys (keyVals ... ).(IObj ).WithMeta (m .meta ).(IPersistentMap )
481502 }
482- newKeyVals := make ([] any , 0 , len ( m . keyVals ))
503+ remove := - 1
483504 for i := 0 ; i < len (m .keyVals ); i += 2 {
484- if ! Equiv (m .keyVals [i ], k ) {
485- newKeyVals = append (newKeyVals , m .keyVals [i ], m .keyVals [i + 1 ])
505+ if Equiv (m .keyVals [i ], k ) {
506+ remove = i
507+ break
486508 }
487509 }
488- return NewMap (newKeyVals ... ).(IObj ).WithMeta (m .meta ).(IPersistentMap )
510+ if remove < 0 {
511+ return m
512+ }
513+ if len (m .keyVals ) == 2 {
514+ return emptyMap .WithMeta (m .meta ).(IPersistentMap )
515+ }
516+
517+ result := newArrayMapWithSize (len (m .keyVals ) - 2 )
518+ result .meta = m .meta
519+ copy (result .keyVals , m .keyVals [:remove ])
520+ copy (result .keyVals [remove :], m .keyVals [remove + 2 :])
521+ return result
489522}
490523
491524func (m * Map ) Count () int {
@@ -596,8 +629,7 @@ func (m *Map) ReduceInit(f IFn, init any) any {
596629}
597630
598631func (m * Map ) AsTransient () ITransientCollection {
599- // TODO: implement transients
600- return & TransientMap {IPersistentMap : m }
632+ return & TransientMap {IPersistentMap : m .clone ()}
601633}
602634
603635////////////////////////////////////////////////////////////////////////////////
@@ -650,12 +682,49 @@ func (m *TransientMap) Conj(v any) Conjer {
650682
651683func (m * TransientMap ) Assoc (k , v any ) Associative {
652684 m .ensureEditable ()
685+ if arrayMap , ok := m .IPersistentMap .(* Map ); ok && arrayMap .keywordShape == nil {
686+ for i := 0 ; i < len (arrayMap .keyVals ); i += 2 {
687+ if Equiv (arrayMap .keyVals [i ], k ) {
688+ arrayMap .keyVals [i + 1 ] = v
689+ arrayMap .hash = 0
690+ arrayMap .hasheq = 0
691+ return m
692+ }
693+ }
694+
695+ threshold := arrayMapHashThreshold
696+ if _ , ok := k .(Keyword ); ok {
697+ threshold = arrayMapKeywordThreshold
698+ }
699+ if len (arrayMap .keyVals ) < threshold {
700+ arrayMap .keyVals = append (arrayMap .keyVals , k , v )
701+ arrayMap .hash = 0
702+ arrayMap .hasheq = 0
703+ return m
704+ }
705+ }
653706 m .IPersistentMap = m .IPersistentMap .Assoc (k , v ).(IPersistentMap )
654707 return m
655708}
656709
657710func (m * TransientMap ) Without (key any ) IPersistentMap {
658711 m .ensureEditable ()
712+ if arrayMap , ok := m .IPersistentMap .(* Map ); ok && arrayMap .keywordShape == nil {
713+ for i := 0 ; i < len (arrayMap .keyVals ); i += 2 {
714+ if ! Equiv (arrayMap .keyVals [i ], key ) {
715+ continue
716+ }
717+ newLen := len (arrayMap .keyVals ) - 2
718+ copy (arrayMap .keyVals [i :], arrayMap .keyVals [i + 2 :])
719+ arrayMap .keyVals [newLen ] = nil
720+ arrayMap .keyVals [newLen + 1 ] = nil
721+ arrayMap .keyVals = arrayMap .keyVals [:newLen ]
722+ arrayMap .hash = 0
723+ arrayMap .hasheq = 0
724+ break
725+ }
726+ return m
727+ }
659728 m .IPersistentMap = m .IPersistentMap .Without (key ).(IPersistentMap )
660729 return m
661730}
0 commit comments