Skip to content

Commit a59138f

Browse files
committed
HashSet, Lists, and EqualityComparers oh my
1 parent 2f9b3d1 commit a59138f

File tree

6 files changed

+305
-1
lines changed

6 files changed

+305
-1
lines changed

ComparerBuilder.ps1

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
$code = @"
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Collections.ObjectModel;
5+
using System.Linq;
6+
using System.Management.Automation;
7+
8+
namespace ListFunctions
9+
{
10+
public class ScriptBlockComparer<T> : IEqualityComparer<T>
11+
{
12+
public ScriptBlock EqualityTester { get; set; }
13+
public ScriptBlock HashCodeScript { get; set; }
14+
15+
public ScriptBlockComparer() { }
16+
public ScriptBlockComparer(ScriptBlock tester)
17+
{
18+
this.EqualityTester = tester;
19+
}
20+
21+
public bool Equals(T x, T y)
22+
{
23+
if (this.EqualityTester == null)
24+
{
25+
return x.Equals(y);
26+
}
27+
28+
bool answer = false;
29+
foreach (PSObject pso in this.EqualityTester.Invoke(x, y))
30+
{
31+
bool? maybe = pso.ImmediateBaseObject as bool?;
32+
if (maybe.HasValue && maybe.Value)
33+
{
34+
answer = true;
35+
break;
36+
}
37+
}
38+
return answer;
39+
}
40+
public int GetHashCode(T item)
41+
{
42+
if (this.HashCodeScript == null)
43+
{
44+
item.GetHashCode();
45+
}
46+
47+
foreach (PSObject pso in this.HashCodeScript.Invoke(item))
48+
{
49+
int? maybe = pso.ImmediateBaseObject as int?;
50+
if (maybe.HasValue)
51+
{
52+
return maybe.Value;
53+
}
54+
}
55+
return item.GetHashCode();
56+
}
57+
}
58+
}
59+
"@
60+
61+
Add-Type -TypeDefinition $code -Language CSharp -ReferencedAssemblies "System",
62+
"System.Collections", "System.Management.Automation", "System.Linq"

ListFunctions.psd1

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ PowerShellVersion = '4.0'
5757
# RequiredAssemblies = @()
5858

5959
# Script files (.ps1) that are run in the caller's environment prior to importing this module.
60-
# ScriptsToProcess = @()
60+
ScriptsToProcess = @("ComparerBuilder.ps1")
6161

6262
# Type files (.ps1xml) to be loaded when importing this module
6363
# TypesToProcess = @()
@@ -74,6 +74,9 @@ FunctionsToExport = @(
7474
"Assert-Any",
7575
"Find-IndexOf",
7676
"Find-LastIndexOf",
77+
"New-EqualityComparer",
78+
"New-HashSet",
79+
"New-List",
7780
"Remove-All",
7881
"Remove-At"
7982
)

ListFunctions.psm1

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,127 @@ Function Find-LastIndexOf()
413413
}
414414
}
415415

416+
Function New-EqualityComparer() {
417+
[CmdletBinding()]
418+
param (
419+
[Parameter(Mandatory = $false)]
420+
[Alias("Type", "t")]
421+
[ValidateScript( { $_ -is [type] -or $_ -is [string] })]
422+
[object] $GenericType = "[object]",
423+
424+
[Parameter(Mandatory=$true)]
425+
[scriptblock] $EqualityScript,
426+
427+
[Parameter(Mandatory=$true)]
428+
[scriptblock] $HashCodeScript
429+
)
430+
431+
if ($GenericType -is [type]) {
432+
$GenericType = $GenericType.FullName
433+
}
434+
435+
New-Object -TypeName "ListFunctions.ScriptBlockComparer[$GenericType]" -Property @{
436+
EqualityTester = $EqualityScript
437+
HashCodeScript = $HashCodeScript
438+
}
439+
}
440+
441+
Function New-HashSet() {
442+
[CmdletBinding()]
443+
param (
444+
[Parameter(Mandatory = $false)]
445+
[int] $Capacity = 1,
446+
447+
[Parameter(Mandatory = $false, Position = 0)]
448+
[Alias("Type", "t")]
449+
[ValidateScript( { $_ -is [type] -or $_ -is [string] })]
450+
[object] $GenericType = "[object]",
451+
452+
[Parameter(Mandatory = $false)]
453+
[ValidateScript({
454+
$true -in @(
455+
$_.GetType().ImplementedInterfaces.FullName | Foreach-Object {
456+
$_ -like "System.Collections.Generic.IEqualityComparer*"
457+
}
458+
)
459+
})]
460+
[object] $EqualityComparer
461+
)
462+
463+
if ($GenericType -is [type]) {
464+
$GenericType = $GenericType.FullName
465+
}
466+
467+
if ($PSBoundParameters.ContainsKey("Capacity") -and -not $PSBoundParameters.ContainsKey("EqualityComparer"))
468+
{
469+
$set = New-Object -TypeName "System.Collections.Generic.Hashset[$GenericType]"($Capacity)
470+
}
471+
elseif (-not $PSBoundParameters.ContainsKey("Capacity") -and $PSBoundParameters.ContainsKey("EqualityComparer"))
472+
{
473+
$set = New-Object -TypeName "System.Collections.Generic.Hashset[$GenericType]"($EqualityComparer)
474+
}
475+
elseif ($PSBoundParameters.ContainsKey("Capacity") -and $PSBoundParameters.ContainsKey("EqualityComparer"))
476+
{
477+
$set = New-Object -TypeName "System.Collections.Generic.Hashset[$GenericType]"($Capacity, $EqualityComparer)
478+
}
479+
else {
480+
$set = New-Object -TypeName "System.Collections.Generic.Hashset[$GenericType]"($Capacity)
481+
}
482+
, $set
483+
}
484+
485+
Function New-List() {
486+
[CmdletBinding()]
487+
param
488+
(
489+
[Parameter(Mandatory = $false)]
490+
[Alias("Type", "t")]
491+
[ValidateScript( { $_ -is [type] -or $_ -is [string] })]
492+
[object] $GenericType = "[object]",
493+
494+
[Parameter(Mandatory = $false, Position = 0)]
495+
[Alias("c", "cap")]
496+
[int] $Capacity = 1,
497+
498+
[Parameter(Mandatory = $false, ValueFromPipeline=$true)]
499+
[object[]] $InputObject
500+
)
501+
Begin {
502+
503+
if ($GenericType -is [type]) {
504+
$private:type = $GenericType
505+
$GenericType = $GenericType.FullName
506+
}
507+
508+
if ($PSBoundParameters.ContainsKey("Capacity")) {
509+
$private:list = New-Object "System.Collections.Generic.List[$GenericType]"($Capacity)
510+
}
511+
else {
512+
$private:list = New-Object "System.Collections.Generic.List[$GenericType]"
513+
514+
}
515+
Write-Verbose "List - Created with 'Capacity': $($private:list.Capacity)"
516+
517+
if ($null -eq $type) {
518+
$private:type = $private:list.GetType().GenericTypeArguments[0]
519+
}
520+
Write-Verbose "List - GenericType: $($private:type.FullName)"
521+
$private:type = $private:type.MakeArrayType()
522+
}
523+
Process {
524+
525+
if ($PSBoundParameters.ContainsKey("InputObject")) {
526+
527+
$private:list.AddRange(($InputObject -as $private:type))
528+
}
529+
530+
}
531+
End {
532+
533+
, $private:list
534+
}
535+
}
536+
416537
Function Remove-All()
417538
{
418539
<#

Public/New-EqualityComparer.ps1

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
Function New-EqualityComparer() {
2+
[CmdletBinding()]
3+
param (
4+
[Parameter(Mandatory = $false)]
5+
[Alias("Type", "t")]
6+
[ValidateScript( { $_ -is [type] -or $_ -is [string] })]
7+
[object] $GenericType = "[object]",
8+
9+
[Parameter(Mandatory=$true)]
10+
[scriptblock] $EqualityScript,
11+
12+
[Parameter(Mandatory=$true)]
13+
[scriptblock] $HashCodeScript
14+
)
15+
16+
if ($GenericType -is [type]) {
17+
$GenericType = $GenericType.FullName
18+
}
19+
20+
New-Object -TypeName "ListFunctions.ScriptBlockComparer[$GenericType]" -Property @{
21+
EqualityTester = $EqualityScript
22+
HashCodeScript = $HashCodeScript
23+
}
24+
}

Public/New-HashSet.ps1

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
Function New-HashSet() {
2+
[CmdletBinding()]
3+
param (
4+
[Parameter(Mandatory = $false)]
5+
[int] $Capacity = 1,
6+
7+
[Parameter(Mandatory = $false, Position = 0)]
8+
[Alias("Type", "t")]
9+
[ValidateScript( { $_ -is [type] -or $_ -is [string] })]
10+
[object] $GenericType = "[object]",
11+
12+
[Parameter(Mandatory = $false)]
13+
[ValidateScript({
14+
$true -in @(
15+
$_.GetType().ImplementedInterfaces.FullName | Foreach-Object {
16+
$_ -like "System.Collections.Generic.IEqualityComparer*"
17+
}
18+
)
19+
})]
20+
[object] $EqualityComparer
21+
)
22+
23+
if ($GenericType -is [type]) {
24+
$GenericType = $GenericType.FullName
25+
}
26+
27+
if ($PSBoundParameters.ContainsKey("Capacity") -and -not $PSBoundParameters.ContainsKey("EqualityComparer"))
28+
{
29+
$set = New-Object -TypeName "System.Collections.Generic.Hashset[$GenericType]"($Capacity)
30+
}
31+
elseif (-not $PSBoundParameters.ContainsKey("Capacity") -and $PSBoundParameters.ContainsKey("EqualityComparer"))
32+
{
33+
$set = New-Object -TypeName "System.Collections.Generic.Hashset[$GenericType]"($EqualityComparer)
34+
}
35+
elseif ($PSBoundParameters.ContainsKey("Capacity") -and $PSBoundParameters.ContainsKey("EqualityComparer"))
36+
{
37+
$set = New-Object -TypeName "System.Collections.Generic.Hashset[$GenericType]"($Capacity, $EqualityComparer)
38+
}
39+
else {
40+
$set = New-Object -TypeName "System.Collections.Generic.Hashset[$GenericType]"($Capacity)
41+
}
42+
, $set
43+
}

Public/New-List.ps1

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
Function New-List() {
2+
[CmdletBinding()]
3+
param
4+
(
5+
[Parameter(Mandatory = $false)]
6+
[Alias("Type", "t")]
7+
[ValidateScript( { $_ -is [type] -or $_ -is [string] })]
8+
[object] $GenericType = "[object]",
9+
10+
[Parameter(Mandatory = $false, Position = 0)]
11+
[Alias("c", "cap")]
12+
[int] $Capacity = 1,
13+
14+
[Parameter(Mandatory = $false, ValueFromPipeline=$true)]
15+
[object[]] $InputObject
16+
)
17+
Begin {
18+
19+
if ($GenericType -is [type]) {
20+
$private:type = $GenericType
21+
$GenericType = $GenericType.FullName
22+
}
23+
24+
if ($PSBoundParameters.ContainsKey("Capacity")) {
25+
$private:list = New-Object "System.Collections.Generic.List[$GenericType]"($Capacity)
26+
}
27+
else {
28+
$private:list = New-Object "System.Collections.Generic.List[$GenericType]"
29+
30+
}
31+
Write-Verbose "List - Created with 'Capacity': $($private:list.Capacity)"
32+
33+
if ($null -eq $type) {
34+
$private:type = $private:list.GetType().GenericTypeArguments[0]
35+
}
36+
Write-Verbose "List - GenericType: $($private:type.FullName)"
37+
$private:type = $private:type.MakeArrayType()
38+
}
39+
Process {
40+
41+
if ($PSBoundParameters.ContainsKey("InputObject")) {
42+
43+
$private:list.AddRange(($InputObject -as $private:type))
44+
}
45+
46+
}
47+
End {
48+
49+
, $private:list
50+
}
51+
}

0 commit comments

Comments
 (0)