@ -240,7 +240,7 @@ merge_opts(NewOpts, OldOpts) ->
true - >
NewValue ;
false - >
tup_umerge ( lists : sort( NewValue ) , lists : sort( OldValue ) )
tup_umerge ( tup_ sort( NewValue ) , tup_ sort( OldValue ) )
end ;
( _ Key , NewValue , _ OldValue ) - >
NewValue
@ -363,33 +363,45 @@ add_hook(pre, {PreHooks, PostHooks}, Hook) ->
add_hook ( post , { PreHooks , PostHooks } , Hook ) - >
{ PreHooks , [ Hook | PostHooks ] } .
% % Sort the list in proplist - order , meaning that ` { a , b } ' and `{a,c}'
% % both compare as usual , and ` a ' and `b' do the same , but ` a ' and `{a,b}' will
% % compare based on the first element of the key , and in order . So the following
% % list will sort as :
% % - ` [ native , { native , o3 } , check ] ' -> `[check, native, {native, o3}]'
% % - ` [ native , { native , o3 } , { native , o2 } , check ] ' -> `[check,native,{native,o3},{native,o2}]'
% % Meaning that :
% % a ) no deduplication takes place
% % b ) the key of a tuple is what counts in being sorted , but atoms are seen as { atom }
% % as far as comparison is concerned ( departing from lists : ukeysort / 2 )
% % c ) order is preserved for similar keys and tuples no matter their size ( sort is stable )
% %
% % These properties let us merge proplists fairly easily .
tup_sort ( List ) - >
lists : sort ( fun ( A , B ) when is_tuple ( A ) , is_tuple ( B ) - > element ( 1 , A ) =< element ( 1 , B )
; ( A , B ) when is_tuple ( A ) - > element ( 1 , A ) =< B
; ( A , B ) when is_tuple ( B ) - > A =< element ( 1 , B )
; ( A , B ) - > A =< B
end , List ) .
% % Custom merge functions . The objective is to behave like lists : umerge / 2 ,
% % except that we also compare the merge elements based on the key if they ' re a
% % tuple , such that ` { key , val1 } ' is always prioritized over `{key, val0}' if
% % the former is from the 'new' list .
% %
% % This lets us apply proper overrides to list of elements according to profile
% % priority .
% % priority . This function depends on a stable proplist sort .
tup_umerge ( [ ] , Olds ) - >
Olds ;
tup_umerge ( News , Olds ) - >
[ ENew | ENews ] = expand ( News ) ,
EOlds = expand ( Olds ) ,
unexpand ( lists : reverse ( umerge ( ENews , EOlds , [ ] , ENew ) ) ) .
% % Expand values , so they ` key ' is now `{key, key}' , and so that
% % ` { key , val } ' is now `{key, {key, val}' . This allows us to compare
% % possibly only on the total key or the value itself .
expand ( [ ] ) - > [ ] ;
expand ( [ Tup | T ] ) when is_tuple ( Tup ) - > [ { element ( 1 , Tup ) , Tup } | expand ( T ) ] ;
expand ( [ H | T ] ) - > [ { H , H } | expand ( T ) ] .
% % Go back to unexpanded form .
unexpand ( List ) - > [ element ( 2 , X ) | | X < - List ] .
tup_umerge ( [ New | News ] , Olds ) - >
lists : reverse ( umerge ( News , Olds , [ ] , New ) ) .
% % This is equivalent to umerge2_2 in the stdlib , except we use the expanded
% % value / key only to compare
umerge ( News , [ { KOld , _ } = Old | Olds ] , Merged , { KCmp , _ } = Cmp ) when KCmp =< KOld - >
umerge ( News , [ Old | Olds ] , Merged , Cmp ) when element ( 1 , Cmp ) == element ( 1 , Old ) ;
element ( 1 , Cmp ) == Old ;
Cmp == element ( 1 , Old ) ;
Cmp =< Old - >
umerge ( News , Olds , [ Cmp | Merged ] , Cmp , Old ) ;
umerge ( News , [ Old | Olds ] , Merged , Cmp ) - >
umerge ( News , Olds , [ Old | Merged ] , Cmp ) ;
@ -400,21 +412,17 @@ umerge(News, [], Merged, Cmp) ->
% % value / keys compare equal , we check if the element is a full dupe to clear it
% % ( like the stdlib function does ) or otherwise keep the duplicate around in
% % an order that prioritizes 'New' elements .
umerge ( [ { KNew , _ } = New | News ] , Olds , Merged , _ CmpMerged , { KCmp , _ } = Cmp ) when KNew =< KCmp - >
umerge ( [ New | News ] , Olds , Merged , CmpMerged , Cmp ) when CmpMerged == Cmp - >
umerge ( News , Olds , Merged , New ) ;
umerge ( [ New | News ] , Olds , Merged , _ CmpMerged , Cmp ) when element ( 1 , New ) == element ( 1 , Cmp ) ;
element ( 1 , New ) == Cmp ;
New == element ( 1 , Cmp ) ;
New =< Cmp - >
umerge ( News , Olds , [ New | Merged ] , New , Cmp ) ;
umerge ( [ { KNew , _ } = New | News ] , Olds , Merged , { KCmp , _ } = CmpMerged , Cmp ) when KNew == KCmp - >
if New == CmpMerged - >
umerge ( News , Olds , Merged , New ) ;
New =/= CmpMerged - > % this is where we depart from the stdlib !
umerge ( News , Olds , [ New | Merged ] , New , Cmp )
end ;
umerge ( [ New | News ] , Olds , Merged , _ CmpMerged , Cmp ) - > % >
umerge ( News , Olds , [ Cmp | Merged ] , New ) ;
umerge ( [ ] , Olds , Merged , { KCmpM , _ } = CmpMerged , { KCmp , _ } = Cmp ) when KCmpM =:= KCmp - >
if CmpMerged == Cmp - >
lists : reverse ( Olds , Merged ) ;
CmpMerged =/= Cmp - > % We depart from stdlib here too !
lists : reverse ( Olds , [ Cmp | Merged ] )
end ;
umerge ( [ ] , Olds , Merged , CmpMerged , Cmp ) when CmpMerged == Cmp - >
lists : reverse ( Olds , Merged ) ;
umerge ( [ ] , Olds , Merged , _ CmpMerged , Cmp ) - >
lists : reverse ( Olds , [ Cmp | Merged ] ) .