/* * Copyright 2019 by its authors. See AUTHORS. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma warning disable 1591 using System; using System.Runtime.InteropServices; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using static Eina.TraitFunctions; using static Eina.InarrayNativeFunctions; namespace Eina { [EditorBrowsable(EditorBrowsableState.Never)] internal static class InarrayNativeFunctions { [DllImport(efl.Libs.Eina)] internal static extern IntPtr eina_inarray_new(uint member_size, uint step); [DllImport(efl.Libs.Eina)] internal static extern void eina_inarray_free(IntPtr array); [DllImport(efl.Libs.Eina)] internal static extern void eina_inarray_step_set(IntPtr array, uint sizeof_eina_inarray, uint member_size, uint step); [DllImport(efl.Libs.Eina)] internal static extern void eina_inarray_flush(IntPtr array); [DllImport(efl.Libs.Eina)] internal static extern int eina_inarray_push(IntPtr array, IntPtr data); [DllImport(efl.Libs.Eina)] internal static extern IntPtr eina_inarray_grow(IntPtr array, uint size); [DllImport(efl.Libs.Eina)] internal static extern int eina_inarray_insert(IntPtr array, IntPtr data, IntPtr compare); [DllImport(efl.Libs.Eina)] internal static extern int eina_inarray_insert_sorted(IntPtr array, IntPtr data, IntPtr compare); [DllImport(efl.Libs.Eina)] internal static extern int eina_inarray_remove(IntPtr array, IntPtr data); [DllImport(efl.Libs.Eina)] internal static extern IntPtr eina_inarray_pop(IntPtr array); [DllImport(efl.Libs.Eina)] internal static extern IntPtr eina_inarray_nth(IntPtr array, uint position); [DllImport(efl.Libs.Eina)] [return: MarshalAs(UnmanagedType.U1)] internal static extern bool eina_inarray_insert_at(IntPtr array, uint position, IntPtr data); [DllImport(efl.Libs.Eina)] internal static extern IntPtr eina_inarray_alloc_at(IntPtr array, uint position, uint member_count); [DllImport(efl.Libs.Eina)] [return: MarshalAs(UnmanagedType.U1)] internal static extern bool eina_inarray_replace_at(IntPtr array, uint position, IntPtr data); [DllImport(efl.Libs.Eina)] [return: MarshalAs(UnmanagedType.U1)] internal static extern bool eina_inarray_remove_at(IntPtr array, uint position); [DllImport(efl.Libs.Eina)] internal static extern void eina_inarray_reverse(IntPtr array); [DllImport(efl.Libs.Eina)] internal static extern void eina_inarray_sort(IntPtr array, IntPtr compare); [DllImport(efl.Libs.Eina)] internal static extern int eina_inarray_search(IntPtr array, IntPtr data, IntPtr compare); [DllImport(efl.Libs.Eina)] internal static extern int eina_inarray_search_sorted(IntPtr array, IntPtr data, IntPtr compare); [DllImport(efl.Libs.Eina)] [return: MarshalAs(UnmanagedType.U1)] internal static extern bool eina_inarray_foreach(IntPtr array, IntPtr function, IntPtr user_data); [DllImport(efl.Libs.Eina)] internal static extern int eina_inarray_foreach_remove(IntPtr array, IntPtr match, IntPtr user_data); [DllImport(efl.Libs.Eina)] [return: MarshalAs(UnmanagedType.U1)] internal static extern bool eina_inarray_resize(IntPtr array, uint new_size); [DllImport(efl.Libs.Eina)] internal static extern uint eina_inarray_count(IntPtr array); [DllImport(efl.Libs.Eina)] internal static extern IntPtr eina_inarray_iterator_new(IntPtr array); [DllImport(efl.Libs.Eina)] internal static extern IntPtr eina_inarray_iterator_reversed_new(IntPtr array); [DllImport(efl.Libs.Eina)] internal static extern IntPtr eina_inarray_accessor_new(IntPtr array); } /// Wrapper around an inplace array. /// Since EFL 1.23. /// [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Justification="This is a generalized container mapping the native one.")] public class Inarray : IEnumerable, IDisposable { public const uint DefaultStep = 0; [EditorBrowsable(EditorBrowsableState.Never)] public IntPtr Handle {get;set;} = IntPtr.Zero; /// Whether this wrapper owns the native buffer. /// Since EFL 1.23. /// public bool Own {get;set;} /// Who is in charge of releasing the resources wrapped by /// this instance. /// Since EFL 1.23. /// public bool OwnContent {get;set;} /// Length of the array. /// Since EFL 1.23. /// public int Length { get { return Count(); } } private void InitNew(uint step) { Handle = EinaInarrayNew(step); Own = true; OwnContent = true; if (Handle == IntPtr.Zero) { throw new SEHException("Could not alloc inarray"); } } /// /// Default constructor /// Since EFL 1.23. /// public Inarray() { InitNew(DefaultStep); } /// /// Constructor with step. /// Since EFL 1.23. /// /// Step size of the array. public Inarray(uint step) { InitNew(step); } [EditorBrowsable(EditorBrowsableState.Never)] public Inarray(IntPtr handle, bool own) { Handle = handle; Own = own; OwnContent = own; } [EditorBrowsable(EditorBrowsableState.Never)] public Inarray(IntPtr handle, bool own, bool ownContent) { Handle = handle; Own = own; OwnContent = ownContent; } /// /// Finalizer to be called from the Garbage Collector. /// Since EFL 1.23. /// ~Inarray() { Dispose(false); } /// Disposes of this wrapper, releasing the native array if owned. /// Since EFL 1.23. /// /// True if this was called from public method. False if /// called from the C# finalizer. protected virtual void Dispose(bool disposing) { IntPtr h = Handle; Handle = IntPtr.Zero; if (h == IntPtr.Zero) { return; } if (OwnContent) { uint len = eina_inarray_count(h); for (uint i = 0; i < len; ++i) { NativeFreeInplace(eina_inarray_nth(h, i)); } } if (Own) { if (disposing) { eina_inarray_free(h); } else { Efl.Eo.Globals.ThreadSafeFreeCbExec(eina_inarray_free, h); } } } /// Releases the native resources held by this instance. /// Since EFL 1.23. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// Releases the native resources held by this instance. /// Since EFL 1.23. /// public void Free() { Dispose(); } /// /// Releases the native array. /// Since EFL 1.23. /// /// The native array. public IntPtr Release() { IntPtr h = Handle; Handle = IntPtr.Zero; return h; } private void FreeElementsIfOwned() { if (OwnContent) { int len = Length; for (int i = 0; i < len; ++i) { NativeFreeInplace(eina_inarray_nth(Handle, (uint)i)); } } } /// /// Removes every member from the array. /// Since EFL 1.23. /// public void Flush() { FreeElementsIfOwned(); eina_inarray_flush(Handle); } /// /// Counts the number of members in an array. /// Since EFL 1.23. /// /// THe number of members in the array. public int Count() { return (int)eina_inarray_count(Handle); } /// Sets all ownership. /// Since EFL 1.23. /// /// If the hash own for all ownerships. public void SetOwnership(bool ownAll) { Own = ownAll; OwnContent = ownAll; } /// Sets own individually. /// Since EFL 1.23. /// /// If own the object. /// If own the content's object. public void SetOwnership(bool own, bool ownContent) { Own = own; OwnContent = ownContent; } /// /// Puts the value as the last member of the array. /// Since EFL 1.23. /// /// The value to be pushed. /// The index of the new member, otherwise -1 on errors. public int Push(T val) { IntPtr ele = IntPtr.Zero; GCHandle gch = GCHandle.Alloc(ele, GCHandleType.Pinned); IntPtr ind = gch.AddrOfPinnedObject(); ManagedToNativeCopyTo(val, ind); var r = eina_inarray_push(Handle, ind); if (r == -1) { NativeFreeInplace(ele); } ResidueFreeInplace(ele); gch.Free(); return r; } // TODO ??? // public void Add(T val) // { // if (!Push(val)) // { // throw; // } // } /// /// Removes the last member of the array. /// Since EFL 1.23. /// /// The data poppep out of the array. public T Pop() { IntPtr ele = eina_inarray_pop(Handle); var r = NativeToManagedInplace(ele); if (OwnContent && ele != IntPtr.Zero) { NativeFreeInplace(ele); } return r; } /// /// Gets the member at the given position. /// Since EFL 1.23. /// /// The member position. /// The element of the given position. public T Nth(uint idx) { IntPtr ele = eina_inarray_nth(Handle, idx); return NativeToManagedInplace(ele); } /// /// Gets the member at the given position. /// Since EFL 1.23. /// /// The member position. /// The element of the given position. public T At(int idx) { return Nth((uint)idx); } /// /// Inserts the value at the given position in the array. /// Since EFL 1.23. /// /// The position to insert the member at. /// The value to be inserted. /// true on success, false on failure. public bool InsertAt(uint idx, T val) { IntPtr ele = IntPtr.Zero; GCHandle gch = GCHandle.Alloc(ele, GCHandleType.Pinned); IntPtr ind = gch.AddrOfPinnedObject(); ManagedToNativeCopyTo(val, ind); var r = eina_inarray_insert_at(Handle, idx, ind); if (!r) { NativeFreeInplace(ele); } ResidueFreeInplace(ele); return r; } /// /// Replaces the value at the given position. /// Since EFL 1.23. /// /// The position to replace the member at. /// The value to replace. public bool ReplaceAt(uint idx, T val) { var old = eina_inarray_nth(Handle, idx); if (old == IntPtr.Zero) { return false; } if (OwnContent) { NativeFreeInplace(old); } var ele = IntPtr.Zero; GCHandle gch = GCHandle.Alloc(ele, GCHandleType.Pinned); IntPtr ind = gch.AddrOfPinnedObject(); ManagedToNativeCopyTo(val, ind); var r = eina_inarray_replace_at(Handle, idx, ind); ResidueFreeInplace(ele); return r; } /// Accessor by index to the elements of this list. /// Since EFL 1.23. /// public T this[int idx] { get { return At(idx); } set { ReplaceAt((uint)idx, value); } } /// /// Removes a member from the given position. /// Since EFL 1.23. /// /// The position to remove the member at. /// true on success, false on failure. public bool RemoveAt(uint idx) { IntPtr ele = eina_inarray_nth(Handle, idx); if (ele == IntPtr.Zero) { return false; } if (OwnContent) { NativeFreeInplace(ele); } return eina_inarray_remove_at(Handle, idx); } /// /// Reverses members in the array. /// Since EFL 1.23. /// public void Reverse() { eina_inarray_reverse(Handle); } /// /// Returns a array containing all of the elements in proper sequence. /// Since EFL 1.23. /// /// A array public T[] ToArray() { int len = Length; var managed = new T[len]; for (int i = 0; i < len; ++i) { managed[i] = At(i); } return managed; } /// Appends all elements at the end of array. /// Since EFL 1.23. /// /// true on success, false otherwise. public bool Append(T[] values) { Contract.Requires(values != null, nameof(values)); foreach (T v in values) { if (Push(v) == -1) { return false; } } return true; } /// Gets an Iterator for this Array. /// Since EFL 1.23. /// public Eina.Iterator GetIterator() { return new Eina.Iterator(eina_inarray_iterator_new(Handle), true); } /// Gets an Iterator for this Array with reversed order. /// Since EFL 1.23. /// public Eina.Iterator GetReversedIterator() { return new Eina.Iterator(eina_inarray_iterator_reversed_new(Handle), true); } /// Gets an Enumerator for this Array. /// Since EFL 1.23. /// public IEnumerator GetEnumerator() { int len = Length; for (int i = 0; i < len; ++i) { yield return At(i); } } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return this.GetEnumerator(); } /// Gets an Accessor for this Array. /// Since EFL 1.23. /// public Eina.Accessor GetAccessor() { return new Eina.AccessorInArray(eina_inarray_accessor_new(Handle), Ownership.Managed); } } }