<#/*THIS IS A T4 FILE - see t4_text_templating.md for what it is and how to run codegen*/#>
<#@ template debug="True" #>
<#@ output extension=".gen.cs" #>
<#@ assembly name="System.Core" #>
using System;
using Unity.Collections.LowLevel.Unsafe;

namespace Unity.Collections.LowLevel.Unsafe
{
    /// <summary>
    /// Provides extension methods for sets.
    /// </summary>
    public unsafe static class HashSetExtensions
    {
<#
{
    foreach (var ContainerType in new[] {
        ( "NativeParallelHashSet" ),
    }) {

    foreach (var OtherContainerType in new[] {
        ( "UnsafeParallelHashSet" ),
        ( "UnsafeList" ),
    }) {
#>
        /// <summary>
        /// Removes the values from this set which are also present in another collection.
        /// </summary>
        /// <typeparam name="T">The type of values.</typeparam>
        /// <param name="container">The set to remove values from.</param>
        /// <param name="other">The collection to compare with.</param>
        public static void ExceptWith<T>(this <#=ContainerType#><T> container, <#=OtherContainerType#><T> other)
            where T : unmanaged, IEquatable<T>
        {
            foreach (var item in other)
            {
                container.Remove(item);
            }
        }

        /// <summary>
        /// Removes the values from this set which are absent in another collection.
        /// </summary>
        /// <typeparam name="T">The type of values.</typeparam>
        /// <param name="container">The set to remove values from.</param>
        /// <param name="other">The collection to compare with.</param>
        public static void IntersectWith<T>(this <#=ContainerType#><T> container, <#=OtherContainerType#><T> other)
            where T : unmanaged, IEquatable<T>
        {
            var result = new UnsafeList<T>(container.Count(), Allocator.Temp);

            foreach (var item in other)
            {
                if (container.Contains(item))
                {
                    result.Add(item);
                }
            }

            container.Clear();
            container.UnionWith(result);

            result.Dispose();
        }

        /// <summary>
        /// Adds all values from a collection to this set.
        /// </summary>
        /// <typeparam name="T">The type of values.</typeparam>
        /// <param name="container">The set to add values to.</param>
        /// <param name="other">The collection to copy values from.</param>
        public static void UnionWith<T>(this <#=ContainerType#><T> container, <#=OtherContainerType#><T> other)
            where T : unmanaged, IEquatable<T>
        {
            foreach (var item in other)
            {
                container.Add(item);
            }
        }
<#}}}#>

<#
{
    foreach (var ContainerType in new[] {
        ( "UnsafeParallelHashSet" ),
    }) {

    foreach (var OtherContainerType in new[] {
        ( "FixedList128Bytes" ),
        ( "FixedList32Bytes" ),
        ( "FixedList4096Bytes" ),
        ( "FixedList512Bytes" ),
        ( "FixedList64Bytes" ),
        ( "NativeArray" ),
        ( "NativeParallelHashSet" ),
        ( "NativeList" ),
        ( "UnsafeParallelHashSet" ),
        ( "UnsafeList" ),
    }) {
#>
        /// <summary>
        /// Removes the values from this set which are also present in another collection.
        /// </summary>
        /// <typeparam name="T">The type of values.</typeparam>
        /// <param name="container">The set to remove values from.</param>
        /// <param name="other">The collection to compare with.</param>
        public static void ExceptWith<T>(this <#=ContainerType#><T> container, <#=OtherContainerType#><T> other)
            where T : unmanaged, IEquatable<T>
        {
            foreach (var item in other)
            {
                container.Remove(item);
            }
        }

        /// <summary>
        /// Removes the values from this set which are absent in another collection.
        /// </summary>
        /// <typeparam name="T">The type of values.</typeparam>
        /// <param name="container">The set to remove values from.</param>
        /// <param name="other">The collection to compare with.</param>
        public static void IntersectWith<T>(this <#=ContainerType#><T> container, <#=OtherContainerType#><T> other)
            where T : unmanaged, IEquatable<T>
        {
            var result = new UnsafeList<T>(container.Count(), Allocator.Temp);

            foreach (var item in other)
            {
                if (container.Contains(item))
                {
                    result.Add(item);
                }
            }

            container.Clear();
            container.UnionWith(result);

            result.Dispose();
        }

        /// <summary>
        /// Adds all values from a collection to this set.
        /// </summary>
        /// <typeparam name="T">The type of values.</typeparam>
        /// <param name="container">The set to add values to.</param>
        /// <param name="other">The collection to copy values from.</param>
        public static void UnionWith<T>(this <#=ContainerType#><T> container, <#=OtherContainerType#><T> other)
            where T : unmanaged, IEquatable<T>
        {
            foreach (var item in other)
            {
                container.Add(item);
            }
        }
<#}}}#>
    }
}