# This file is a part of Julia. License is MIT: https://julialang.org/license module VersionWeights importall ....Base.Operators export VersionWeight struct HierarchicalValue{T} v::Vector{T} rest::T end HierarchicalValue{T}(v::Vector{T}) = HierarchicalValue{T}(v, zero(T)) HierarchicalValue(T::Type) = HierarchicalValue(T[]) Base.zero(::Type{HierarchicalValue{T}}) where {T} = HierarchicalValue(T) Base.typemin(::Type{HierarchicalValue{T}}) where {T} = HierarchicalValue(T[], typemin(T)) for f in (:-, :+) @eval function Base.$f(a::HierarchicalValue{T}, b::HierarchicalValue{T}) where T av = a.v bv = b.v la = length(a.v) lb = length(b.v) l0 = min(la, lb) l1 = max(la, lb) ld = la - lb rv = Vector{T}(l1) rf = ($f)(a.rest, b.rest) @inbounds for i = 1:l0 rv[i] = ($f)(av[i], bv[i]) end @inbounds for i = l0+1:l0+ld rv[i] = ($f)(av[i], b.rest) end @inbounds for i = l0+1:l0-ld rv[i] = ($f)(a.rest, bv[i]) end return HierarchicalValue(rv, rf) end end Base.:-(a::HierarchicalValue) = HierarchicalValue(-a.v, -a.rest) function Base.cmp(a::HierarchicalValue{T}, b::HierarchicalValue{T}) where T av = a.v bv = b.v la = length(a.v) lb = length(b.v) l0 = min(la, lb) l1 = max(la, lb) ld = la - lb @inbounds for i = 1:l0 c = cmp(av[i], bv[i]); c != 0 && return c end @inbounds for i = l0+1:l0+ld c = cmp(av[i], b.rest); c != 0 && return c end @inbounds for i = l0+1:l0-ld c = cmp(a.rest, bv[i]); c != 0 && return c end return cmp(a.rest, b.rest) end Base.isless(a::HierarchicalValue{T}, b::HierarchicalValue{T}) where {T} = cmp(a,b) < 0 Base.:(==)(a::HierarchicalValue{T}, b::HierarchicalValue{T}) where {T} = cmp(a,b) == 0 Base.abs(a::HierarchicalValue{T}) where {T} = HierarchicalValue(T[abs(x) for x in a.v], abs(a.rest)) Base.copy(a::HierarchicalValue{T}) where {T} = HierarchicalValue(T[copy(x) for x in a.v], copy(a.rest)) struct VWPreBuildItem nonempty::Int s::HierarchicalValue{Int} i::Int end VWPreBuildItem() = VWPreBuildItem(0, HierarchicalValue(Int), 0) VWPreBuildItem(i::Int) = VWPreBuildItem(1, HierarchicalValue(Int), i) VWPreBuildItem(s::String) = VWPreBuildItem(1, HierarchicalValue(Int[s...]), 0) Base.zero(::Type{VWPreBuildItem}) = VWPreBuildItem() Base.typemin(::Type{VWPreBuildItem}) = (x=typemin(Int); VWPreBuildItem(x, typemin(HierarchicalValue{Int}), x)) Base.:-(a::VWPreBuildItem, b::VWPreBuildItem) = VWPreBuildItem(a.nonempty-b.nonempty, a.s-b.s, a.i-b.i) Base.:+(a::VWPreBuildItem, b::VWPreBuildItem) = VWPreBuildItem(a.nonempty+b.nonempty, a.s+b.s, a.i+b.i) Base.:-(a::VWPreBuildItem) = VWPreBuildItem(-a.nonempty, -a.s, -a.i) function Base.cmp(a::VWPreBuildItem, b::VWPreBuildItem) c = cmp(a.nonempty, b.nonempty); c != 0 && return c c = cmp(a.s, b.s); c != 0 && return c return cmp(a.i, b.i) end Base.isless(a::VWPreBuildItem, b::VWPreBuildItem) = cmp(a,b) < 0 Base.:(==)(a::VWPreBuildItem, b::VWPreBuildItem) = cmp(a,b) == 0 Base.abs(a::VWPreBuildItem) = VWPreBuildItem(abs(a.nonempty), abs(a.s), abs(a.i)) Base.copy(a::VWPreBuildItem) = VWPreBuildItem(a.nonempty, copy(a.s), a.i) struct VWPreBuild nonempty::Int w::HierarchicalValue{VWPreBuildItem} end const _vwprebuild_zero = VWPreBuild(0, HierarchicalValue(VWPreBuildItem)) function VWPreBuild(ispre::Bool, desc::Tuple{Vararg{Union{Int,String}}}) isempty(desc) && return _vwprebuild_zero desc == ("",) && return VWPreBuild(ispre ? -1 : 1, HierarchicalValue(VWPreBuildItem[])) hv = HierarchicalValue([VWPreBuildItem(item) for item in desc]) return VWPreBuild(ispre ? -1 : 0, hv) end VWPreBuild() = _vwprebuild_zero Base.zero(::Type{VWPreBuild}) = VWPreBuild() const _vwprebuild_min = VWPreBuild(typemin(Int), typemin(HierarchicalValue{VWPreBuildItem})) Base.typemin(::Type{VWPreBuild}) = _vwprebuild_min function Base.:(-)(a::VWPreBuild, b::VWPreBuild) b === _vwprebuild_zero && return a a === _vwprebuild_zero && return -b VWPreBuild(a.nonempty-b.nonempty, a.w-b.w) end function Base.:(+)(a::VWPreBuild, b::VWPreBuild) b === _vwprebuild_zero && return a a === _vwprebuild_zero && return b VWPreBuild(a.nonempty+b.nonempty, a.w+b.w) end function Base.:(-)(a::VWPreBuild) a === _vwprebuild_zero && return a VWPreBuild(-a.nonempty, -a.w) end @inline function Base.cmp(a::VWPreBuild, b::VWPreBuild) a === _vwprebuild_zero && b === _vwprebuild_zero && return 0 c = cmp(a.nonempty, b.nonempty); c != 0 && return c return cmp(a.w, b.w) end Base.isless(a::VWPreBuild, b::VWPreBuild) = cmp(a,b) < 0 Base.:(==)(a::VWPreBuild, b::VWPreBuild) = cmp(a,b) == 0 function Base.abs(a::VWPreBuild) a === _vwprebuild_zero && return a VWPreBuild(abs(a.nonempty), abs(a.w)) end function Base.copy(a::VWPreBuild) a === _vwprebuild_zero && return a VWPreBuild(a.nonempty, copy(a.w)) end function Base.deepcopy_internal(a::VWPreBuild, dict::ObjectIdDict) haskey(dict, a) && return dict[a] b = (a === _vwprebuild_zero) ? _vwprebuild_zero : VWPreBuild(a.nonempty, Base.deepcopy_internal(a.w, dict)) dict[a] = b return b end # The numeric type used to determine how the different # versions of a package should be weighed struct VersionWeight major::Int minor::Int patch::Int prerelease::VWPreBuild build::VWPreBuild end VersionWeight(major::Int, minor::Int, patch::Int, prerelease::VWPreBuild) = VersionWeight(major, minor, patch, prerelease, zero(VWPreBuild)) VersionWeight(major::Int, minor::Int, patch::Int) = VersionWeight(major, minor, patch, zero(VWPreBuild)) VersionWeight(major::Int, minor::Int) = VersionWeight(major, minor, 0) VersionWeight(major::Int) = VersionWeight(major, 0) VersionWeight() = VersionWeight(0) VersionWeight(vn::VersionNumber) = VersionWeight(vn.major, vn.minor, vn.patch, VWPreBuild(true, vn.prerelease), VWPreBuild(false, vn.build)) Base.zero(::Type{VersionWeight}) = VersionWeight() Base.typemin(::Type{VersionWeight}) = (x=typemin(Int); y=typemin(VWPreBuild); VersionWeight(x, x, x, y, y)) Base.:(-)(a::VersionWeight, b::VersionWeight) = VersionWeight(a.major-b.major, a.minor-b.minor, a.patch-b.patch, a.prerelease-b.prerelease, a.build-b.build) Base.:(+)(a::VersionWeight, b::VersionWeight) = VersionWeight(a.major+b.major, a.minor+b.minor, a.patch+b.patch, a.prerelease+b.prerelease, a.build+b.build) Base.:(-)(a::VersionWeight) = VersionWeight(-a.major, -a.minor, -a.patch, -a.prerelease, -a.build) function Base.cmp(a::VersionWeight, b::VersionWeight) c = cmp(a.major, b.major); c != 0 && return c c = cmp(a.minor, b.minor); c != 0 && return c c = cmp(a.patch, b.patch); c != 0 && return c c = cmp(a.prerelease, b.prerelease); c != 0 && return c return cmp(a.build, b.build) end Base.isless(a::VersionWeight, b::VersionWeight) = cmp(a,b) < 0 Base.:(==)(a::VersionWeight, b::VersionWeight) = cmp(a,b) == 0 Base.abs(a::VersionWeight) = VersionWeight(abs(a.major), abs(a.minor), abs(a.patch), abs(a.prerelease), abs(a.build)) Base.copy(a::VersionWeight) = VersionWeight(a.major, a.minor, a.patch, copy(a.prerelease), copy(a.build)) # This isn't nice, but it's for debugging only anyway function Base.show(io::IO, a::VersionWeight) print(io, "(", a.major) a == VersionWeight(a.major) && @goto done print(io, ".", a.minor) a == VersionWeight(a.major, a.minor) && @goto done print(io, ".", a.patch) a.prerelease ≠ _vwprebuild_zero && print(io, "-", a.prerelease) a.build ≠ _vwprebuild_zero && print(io, "+", a.build) @label done print(io, ")") end end