diff options
author | Kangho Hur <kangho.hur@samsung.com> | 2017-03-24 14:29:22 +0900 |
---|---|---|
committer | Kangho Hur <kangho.hur@samsung.com> | 2017-03-24 14:47:36 +0900 |
commit | 161a8e0f544b44f848d4c68ac9637d3a8b3f2520 (patch) | |
tree | 9a61043f0e27ef4f9855fcc1fc70693b12f10f4f /Xamarin.Forms.Core | |
parent | 20daaa5702a27d1a9c7cf9dfacfdfa254ac0e5e3 (diff) | |
download | xamarin-forms-161a8e0f544b44f848d4c68ac9637d3a8b3f2520.tar.gz xamarin-forms-161a8e0f544b44f848d4c68ac9637d3a8b3f2520.tar.bz2 xamarin-forms-161a8e0f544b44f848d4c68ac9637d3a8b3f2520.zip |
Clean sync with 2.3.4-2
Change-Id: I6a7423d2690a1c30f46e0c128d9504a2464f8f0b
Diffstat (limited to 'Xamarin.Forms.Core')
19 files changed, 990 insertions, 291 deletions
diff --git a/Xamarin.Forms.Core/Accessibility.cs b/Xamarin.Forms.Core/Accessibility.cs deleted file mode 100644 index e866d318..00000000 --- a/Xamarin.Forms.Core/Accessibility.cs +++ /dev/null @@ -1,14 +0,0 @@ - -namespace Xamarin.Forms -{ - public class Accessibility - { - public static readonly BindableProperty HintProperty = BindableProperty.Create("Hint", typeof(string), typeof(Element), default(string)); - - public static readonly BindableProperty IsInAccessibleTreeProperty = BindableProperty.Create("IsInAccessibleTree", typeof(bool?), typeof(Element), null); - - public static readonly BindableProperty LabeledByProperty = BindableProperty.Create("LabeledBy", typeof(VisualElement), typeof(Element), default(VisualElement)); - - public static readonly BindableProperty NameProperty = BindableProperty.Create("Name", typeof(string), typeof(Element), default(string)); - } -} diff --git a/Xamarin.Forms.Core/Button.cs b/Xamarin.Forms.Core/Button.cs index bcd593ed..97d774c9 100644 --- a/Xamarin.Forms.Core/Button.cs +++ b/Xamarin.Forms.Core/Button.cs @@ -116,18 +116,13 @@ namespace Xamarin.Forms void IButtonController.SendClicked() { - Command?.Execute(CommandParameter); - Clicked?.Invoke(this, EventArgs.Empty); - } - - void IButtonController.SendPressed() - { - Pressed?.Invoke(this, EventArgs.Empty); - } + ICommand cmd = Command; + if (cmd != null) + cmd.Execute(CommandParameter); - void IButtonController.SendReleased() - { - Released?.Invoke(this, EventArgs.Empty); + EventHandler handler = Clicked; + if (handler != null) + handler(this, EventArgs.Empty); } public FontAttributes FontAttributes @@ -151,10 +146,6 @@ namespace Xamarin.Forms public event EventHandler Clicked; - public event EventHandler Pressed; - - public event EventHandler Released; - public Button() { _platformConfigurationRegistry = new Lazy<PlatformConfigurationRegistry<Button>>(() => new PlatformConfigurationRegistry<Button>(this)); diff --git a/Xamarin.Forms.Core/ConcurrentDictionary.cs b/Xamarin.Forms.Core/ConcurrentDictionary.cs new file mode 100644 index 00000000..a229c6fe --- /dev/null +++ b/Xamarin.Forms.Core/ConcurrentDictionary.cs @@ -0,0 +1,426 @@ +// ConcurrentDictionary.cs +// +// Copyright (c) 2009 Jérémie "Garuma" Laval +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace Xamarin.Forms +{ + internal class ConcurrentDictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IDictionary, ICollection, IEnumerable + { + readonly IEqualityComparer<TKey> _comparer; + + SplitOrderedList<TKey, KeyValuePair<TKey, TValue>> _internalDictionary; + + public ConcurrentDictionary() : this(EqualityComparer<TKey>.Default) + { + } + + public ConcurrentDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection) : this(collection, EqualityComparer<TKey>.Default) + { + } + + public ConcurrentDictionary(IEqualityComparer<TKey> comparer) + { + _comparer = comparer; + _internalDictionary = new SplitOrderedList<TKey, KeyValuePair<TKey, TValue>>(comparer); + } + + public ConcurrentDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer) : this(comparer) + { + foreach (KeyValuePair<TKey, TValue> pair in collection) + Add(pair.Key, pair.Value); + } + + // Parameters unused + public ConcurrentDictionary(int concurrencyLevel, int capacity) : this(EqualityComparer<TKey>.Default) + { + } + + public ConcurrentDictionary(int concurrencyLevel, IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer) : this(collection, comparer) + { + } + + // Parameters unused + public ConcurrentDictionary(int concurrencyLevel, int capacity, IEqualityComparer<TKey> comparer) : this(comparer) + { + } + + public bool IsEmpty + { + get { return Count == 0; } + } + + void ICollection.CopyTo(Array array, int startIndex) + { + var arr = array as KeyValuePair<TKey, TValue>[]; + if (arr == null) + return; + + CopyTo(arr, startIndex, Count); + } + + bool ICollection.IsSynchronized + { + get { return true; } + } + + object ICollection.SyncRoot + { + get { return this; } + } + + void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> pair) + { + Add(pair.Key, pair.Value); + } + + public void Clear() + { + // Pronk + _internalDictionary = new SplitOrderedList<TKey, KeyValuePair<TKey, TValue>>(_comparer); + } + + bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> pair) + { + return ContainsKey(pair.Key); + } + + void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int startIndex) + { + CopyTo(array, startIndex); + } + + public int Count + { + get { return _internalDictionary.Count; } + } + + bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly + { + get { return false; } + } + + bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> pair) + { + return Remove(pair.Key); + } + + void IDictionary.Add(object key, object value) + { + if (!(key is TKey) || !(value is TValue)) + throw new ArgumentException("key or value aren't of correct type"); + + Add((TKey)key, (TValue)value); + } + + bool IDictionary.Contains(object key) + { + if (!(key is TKey)) + return false; + + return ContainsKey((TKey)key); + } + + IDictionaryEnumerator IDictionary.GetEnumerator() + { + return new ConcurrentDictionaryEnumerator(GetEnumeratorInternal()); + } + + bool IDictionary.IsFixedSize + { + get { return false; } + } + + bool IDictionary.IsReadOnly + { + get { return false; } + } + + object IDictionary.this[object key] + { + get + { + if (!(key is TKey)) + throw new ArgumentException("key isn't of correct type", "key"); + + return this[(TKey)key]; + } + set + { + if (!(key is TKey) || !(value is TValue)) + throw new ArgumentException("key or value aren't of correct type"); + + this[(TKey)key] = (TValue)value; + } + } + + ICollection IDictionary.Keys + { + get { return (ICollection)Keys; } + } + + void IDictionary.Remove(object key) + { + if (!(key is TKey)) + return; + + Remove((TKey)key); + } + + ICollection IDictionary.Values + { + get { return (ICollection)Values; } + } + + void IDictionary<TKey, TValue>.Add(TKey key, TValue value) + { + Add(key, value); + } + + public bool ContainsKey(TKey key) + { + CheckKey(key); + KeyValuePair<TKey, TValue> dummy; + return _internalDictionary.Find(Hash(key), key, out dummy); + } + + public TValue this[TKey key] + { + get { return GetValue(key); } + set { AddOrUpdate(key, value, value); } + } + + public ICollection<TKey> Keys + { + get { return GetPart(kvp => kvp.Key); } + } + + bool IDictionary<TKey, TValue>.Remove(TKey key) + { + return Remove(key); + } + + public bool TryGetValue(TKey key, out TValue value) + { + CheckKey(key); + KeyValuePair<TKey, TValue> pair; + bool result = _internalDictionary.Find(Hash(key), key, out pair); + value = pair.Value; + + return result; + } + + public ICollection<TValue> Values + { + get { return GetPart(kvp => kvp.Value); } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumeratorInternal(); + } + + public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() + { + return GetEnumeratorInternal(); + } + + public TValue AddOrUpdate(TKey key, Func<TKey, TValue> addValueFactory, Func<TKey, TValue, TValue> updateValueFactory) + { + CheckKey(key); + if (addValueFactory == null) + throw new ArgumentNullException("addValueFactory"); + if (updateValueFactory == null) + throw new ArgumentNullException("updateValueFactory"); + return _internalDictionary.InsertOrUpdate(Hash(key), key, () => Make(key, addValueFactory(key)), e => Make(key, updateValueFactory(key, e.Value))).Value; + } + + public TValue AddOrUpdate(TKey key, TValue addValue, Func<TKey, TValue, TValue> updateValueFactory) + { + return AddOrUpdate(key, _ => addValue, updateValueFactory); + } + + public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory) + { + CheckKey(key); + return _internalDictionary.InsertOrGet(Hash(key), key, Make(key, default(TValue)), () => Make(key, valueFactory(key))).Value; + } + + public TValue GetOrAdd(TKey key, TValue value) + { + CheckKey(key); + return _internalDictionary.InsertOrGet(Hash(key), key, Make(key, value), null).Value; + } + + public KeyValuePair<TKey, TValue>[] ToArray() + { + // This is most certainly not optimum but there is + // not a lot of possibilities + + return new List<KeyValuePair<TKey, TValue>>(this).ToArray(); + } + + public bool TryAdd(TKey key, TValue value) + { + CheckKey(key); + return _internalDictionary.Insert(Hash(key), key, Make(key, value)); + } + + public bool TryRemove(TKey key, out TValue value) + { + CheckKey(key); + KeyValuePair<TKey, TValue> data; + bool result = _internalDictionary.Delete(Hash(key), key, out data); + value = data.Value; + return result; + } + + public bool TryUpdate(TKey key, TValue newValue, TValue comparisonValue) + { + CheckKey(key); + return _internalDictionary.CompareExchange(Hash(key), key, Make(key, newValue), e => e.Value.Equals(comparisonValue)); + } + + void Add(TKey key, TValue value) + { + while (!TryAdd(key, value)) + ; + } + + TValue AddOrUpdate(TKey key, TValue addValue, TValue updateValue) + { + CheckKey(key); + return _internalDictionary.InsertOrUpdate(Hash(key), key, Make(key, addValue), Make(key, updateValue)).Value; + } + + void CheckKey(TKey key) + { + if (key == null) + throw new ArgumentNullException("key"); + } + + void CopyTo(KeyValuePair<TKey, TValue>[] array, int startIndex) + { + CopyTo(array, startIndex, Count); + } + + void CopyTo(KeyValuePair<TKey, TValue>[] array, int startIndex, int num) + { + foreach (KeyValuePair<TKey, TValue> kvp in this) + { + array[startIndex++] = kvp; + + if (--num <= 0) + return; + } + } + + IEnumerator<KeyValuePair<TKey, TValue>> GetEnumeratorInternal() + { + return _internalDictionary.GetEnumerator(); + } + + ICollection<T> GetPart<T>(Func<KeyValuePair<TKey, TValue>, T> extractor) + { + var temp = new List<T>(); + + foreach (KeyValuePair<TKey, TValue> kvp in this) + temp.Add(extractor(kvp)); + + return new ReadOnlyCollection<T>(temp); + } + + TValue GetValue(TKey key) + { + TValue temp; + if (!TryGetValue(key, out temp)) + throw new KeyNotFoundException(key.ToString()); + return temp; + } + + uint Hash(TKey key) + { + return (uint)_comparer.GetHashCode(key); + } + + static KeyValuePair<T, V> Make<T, V>(T key, V value) + { + return new KeyValuePair<T, V>(key, value); + } + + bool Remove(TKey key) + { + TValue dummy; + + return TryRemove(key, out dummy); + } + + class ConcurrentDictionaryEnumerator : IDictionaryEnumerator + { + readonly IEnumerator<KeyValuePair<TKey, TValue>> _internalEnum; + + public ConcurrentDictionaryEnumerator(IEnumerator<KeyValuePair<TKey, TValue>> internalEnum) + { + _internalEnum = internalEnum; + } + + public DictionaryEntry Entry + { + get + { + KeyValuePair<TKey, TValue> current = _internalEnum.Current; + return new DictionaryEntry(current.Key, current.Value); + } + } + + public object Key + { + get { return _internalEnum.Current.Key; } + } + + public object Value + { + get { return _internalEnum.Current.Value; } + } + + public object Current + { + get { return Entry; } + } + + public bool MoveNext() + { + return _internalEnum.MoveNext(); + } + + public void Reset() + { + _internalEnum.Reset(); + } + } + } +}
\ No newline at end of file diff --git a/Xamarin.Forms.Core/Device.cs b/Xamarin.Forms.Core/Device.cs index 2987ea5a..506978a2 100644 --- a/Xamarin.Forms.Core/Device.cs +++ b/Xamarin.Forms.Core/Device.cs @@ -12,7 +12,6 @@ namespace Xamarin.Forms public const string Android = "Android"; public const string WinPhone = "WinPhone"; public const string Windows = "Windows"; - public const string macOS = "macOS"; public const string Tizen = "Tizen"; internal static DeviceInfo info; @@ -23,10 +22,8 @@ namespace Xamarin.Forms [Obsolete("Use RuntimePlatform instead.")] #pragma warning disable 0618 - public static TargetPlatform OS - { - get - { + public static TargetPlatform OS { + get { TargetPlatform platform; if (Enum.TryParse(RuntimePlatform, out platform)) return platform; @@ -180,4 +177,4 @@ namespace Xamarin.Forms public static readonly Style CaptionStyle = new Style(typeof(Label)) { BaseResourceKey = CaptionStyleKey }; } } -} +}
\ No newline at end of file diff --git a/Xamarin.Forms.Core/IButtonController.cs b/Xamarin.Forms.Core/IButtonController.cs index b7e3bc41..c88907b0 100644 --- a/Xamarin.Forms.Core/IButtonController.cs +++ b/Xamarin.Forms.Core/IButtonController.cs @@ -3,7 +3,5 @@ namespace Xamarin.Forms public interface IButtonController : IViewController { void SendClicked(); - void SendPressed(); - void SendReleased(); } }
\ No newline at end of file diff --git a/Xamarin.Forms.Core/INavigationPageController.cs b/Xamarin.Forms.Core/INavigationPageController.cs index ab057510..eddbe750 100644 --- a/Xamarin.Forms.Core/INavigationPageController.cs +++ b/Xamarin.Forms.Core/INavigationPageController.cs @@ -7,9 +7,7 @@ namespace Xamarin.Forms { public interface INavigationPageController { - Page Peek(int depth = 0); - - IEnumerable<Page> Pages { get; } + Stack<Page> StackCopy { get; } int StackDepth { get; } diff --git a/Xamarin.Forms.Core/ListStringTypeConverter.cs b/Xamarin.Forms.Core/ListStringTypeConverter.cs index 69aa53fc..647f0143 100644 --- a/Xamarin.Forms.Core/ListStringTypeConverter.cs +++ b/Xamarin.Forms.Core/ListStringTypeConverter.cs @@ -3,7 +3,6 @@ using System.Linq; namespace Xamarin.Forms { - [Xaml.ProvideCompiled("Xamarin.Forms.Core.XamlC.ListStringTypeConverter")] public class ListStringTypeConverter : TypeConverter { public override object ConvertFromInvariantString(string value) diff --git a/Xamarin.Forms.Core/ListView.cs b/Xamarin.Forms.Core/ListView.cs index 8f234cfd..0751e1c2 100644 --- a/Xamarin.Forms.Core/ListView.cs +++ b/Xamarin.Forms.Core/ListView.cs @@ -71,7 +71,7 @@ namespace Xamarin.Forms public ListView([Parameter("CachingStrategy")] ListViewCachingStrategy cachingStrategy) : this() { - if (Device.RuntimePlatform == Device.Android || Device.RuntimePlatform == Device.iOS || Device.RuntimePlatform == Device.macOS) + if (Device.RuntimePlatform == Device.Android || Device.RuntimePlatform == Device.iOS) CachingStrategy = cachingStrategy; } diff --git a/Xamarin.Forms.Core/MessagingCenter.cs b/Xamarin.Forms.Core/MessagingCenter.cs index d5753e1d..b6a167da 100644 --- a/Xamarin.Forms.Core/MessagingCenter.cs +++ b/Xamarin.Forms.Core/MessagingCenter.cs @@ -2,28 +2,12 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Runtime.CompilerServices; namespace Xamarin.Forms { - public interface IMessagingCenter + public static class MessagingCenter { - void Send<TSender, TArgs>(TSender sender, string message, TArgs args) where TSender : class; - - void Send<TSender>(TSender sender, string message) where TSender : class; - - void Subscribe<TSender, TArgs>(object subscriber, string message, Action<TSender, TArgs> callback, TSender source = null) where TSender : class; - - void Subscribe<TSender>(object subscriber, string message, Action<TSender> callback, TSender source = null) where TSender : class; - - void Unsubscribe<TSender, TArgs>(object subscriber, string message) where TSender : class; - - void Unsubscribe<TSender>(object subscriber, string message) where TSender : class; - } - - public class MessagingCenter : IMessagingCenter - { - public static IMessagingCenter Instance { get; } = new MessagingCenter(); - class Sender : Tuple<string, Type, Type> { public Sender(string message, Type senderType, Type argType) : base(message, senderType, argType) @@ -35,8 +19,8 @@ namespace Xamarin.Forms class MaybeWeakReference { - WeakReference DelegateWeakReference { get; } - object DelegateStrongReference { get; } + WeakReference DelegateWeakReference { get; set; } + object DelegateStrongReference { get; set; } readonly bool _isStrongReference; @@ -100,16 +84,11 @@ namespace Xamarin.Forms } } - readonly Dictionary<Sender, List<Subscription>> _subscriptions = + static readonly Dictionary<Sender, List<Subscription>> s_subscriptions = new Dictionary<Sender, List<Subscription>>(); public static void Send<TSender, TArgs>(TSender sender, string message, TArgs args) where TSender : class { - Instance.Send(sender, message, args); - } - - void IMessagingCenter.Send<TSender, TArgs>(TSender sender, string message, TArgs args) - { if (sender == null) throw new ArgumentNullException(nameof(sender)); InnerSend(message, typeof(TSender), typeof(TArgs), sender, args); @@ -117,11 +96,6 @@ namespace Xamarin.Forms public static void Send<TSender>(TSender sender, string message) where TSender : class { - Instance.Send(sender, message); - } - - void IMessagingCenter.Send<TSender>(TSender sender, string message) - { if (sender == null) throw new ArgumentNullException(nameof(sender)); InnerSend(message, typeof(TSender), null, sender, null); @@ -129,11 +103,6 @@ namespace Xamarin.Forms public static void Subscribe<TSender, TArgs>(object subscriber, string message, Action<TSender, TArgs> callback, TSender source = null) where TSender : class { - Instance.Subscribe(subscriber, message, callback, source); - } - - void IMessagingCenter.Subscribe<TSender, TArgs>(object subscriber, string message, Action<TSender, TArgs> callback, TSender source) - { if (subscriber == null) throw new ArgumentNullException(nameof(subscriber)); if (callback == null) @@ -152,11 +121,6 @@ namespace Xamarin.Forms public static void Subscribe<TSender>(object subscriber, string message, Action<TSender> callback, TSender source = null) where TSender : class { - Instance.Subscribe(subscriber, message, callback, source); - } - - void IMessagingCenter.Subscribe<TSender>(object subscriber, string message, Action<TSender> callback, TSender source) - { if (subscriber == null) throw new ArgumentNullException(nameof(subscriber)); if (callback == null) @@ -175,32 +139,27 @@ namespace Xamarin.Forms public static void Unsubscribe<TSender, TArgs>(object subscriber, string message) where TSender : class { - Instance.Unsubscribe<TSender, TArgs>(subscriber, message); - } - - void IMessagingCenter.Unsubscribe<TSender, TArgs>(object subscriber, string message) - { InnerUnsubscribe(message, typeof(TSender), typeof(TArgs), subscriber); } public static void Unsubscribe<TSender>(object subscriber, string message) where TSender : class { - Instance.Unsubscribe<TSender>(subscriber, message); + InnerUnsubscribe(message, typeof(TSender), null, subscriber); } - void IMessagingCenter.Unsubscribe<TSender>(object subscriber, string message) + internal static void ClearSubscribers() { - InnerUnsubscribe(message, typeof(TSender), null, subscriber); + s_subscriptions.Clear(); } - void InnerSend(string message, Type senderType, Type argType, object sender, object args) + static void InnerSend(string message, Type senderType, Type argType, object sender, object args) { if (message == null) throw new ArgumentNullException(nameof(message)); var key = new Sender(message, senderType, argType); - if (!_subscriptions.ContainsKey(key)) + if (!s_subscriptions.ContainsKey(key)) return; - List<Subscription> subcriptions = _subscriptions[key]; + List<Subscription> subcriptions = s_subscriptions[key]; if (subcriptions == null || !subcriptions.Any()) return; // should not be reachable @@ -219,24 +178,24 @@ namespace Xamarin.Forms } } - void InnerSubscribe(object subscriber, string message, Type senderType, Type argType, object target, MethodInfo methodInfo, Filter filter) + static void InnerSubscribe(object subscriber, string message, Type senderType, Type argType, object target, MethodInfo methodInfo, Filter filter) { if (message == null) throw new ArgumentNullException(nameof(message)); var key = new Sender(message, senderType, argType); var value = new Subscription(subscriber, target, methodInfo, filter); - if (_subscriptions.ContainsKey(key)) + if (s_subscriptions.ContainsKey(key)) { - _subscriptions[key].Add(value); + s_subscriptions[key].Add(value); } else { var list = new List<Subscription> { value }; - _subscriptions[key] = list; + s_subscriptions[key] = list; } } - void InnerUnsubscribe(string message, Type senderType, Type argType, object subscriber) + static void InnerUnsubscribe(string message, Type senderType, Type argType, object subscriber) { if (subscriber == null) throw new ArgumentNullException(nameof(subscriber)); @@ -244,19 +203,11 @@ namespace Xamarin.Forms throw new ArgumentNullException(nameof(message)); var key = new Sender(message, senderType, argType); - if (!_subscriptions.ContainsKey(key)) + if (!s_subscriptions.ContainsKey(key)) return; - _subscriptions[key].RemoveAll(sub => sub.CanBeRemoved() || sub.Subscriber.Target == subscriber); - if (!_subscriptions[key].Any()) - _subscriptions.Remove(key); - } - - // This is a bit gross; it only exists to support the unit tests in PageTests - // because the implementations of ActionSheet, Alert, and IsBusy are all very - // tightly coupled to the MessagingCenter singleton - internal static void ClearSubscribers() - { - (Instance as MessagingCenter)?._subscriptions.Clear(); + s_subscriptions[key].RemoveAll(sub => sub.CanBeRemoved() || sub.Subscriber.Target == subscriber); + if (!s_subscriptions[key].Any()) + s_subscriptions.Remove(key); } } }
\ No newline at end of file diff --git a/Xamarin.Forms.Core/NavigationPage.cs b/Xamarin.Forms.Core/NavigationPage.cs index 7663d1bf..7b393b9c 100644 --- a/Xamarin.Forms.Core/NavigationPage.cs +++ b/Xamarin.Forms.Core/NavigationPage.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; using Xamarin.Forms.Internals; @@ -28,10 +27,7 @@ namespace Xamarin.Forms static readonly BindablePropertyKey CurrentPagePropertyKey = BindableProperty.CreateReadOnly("CurrentPage", typeof(Page), typeof(NavigationPage), null); public static readonly BindableProperty CurrentPageProperty = CurrentPagePropertyKey.BindableProperty; - - static readonly BindablePropertyKey RootPagePropertyKey = BindableProperty.CreateReadOnly(nameof(RootPage), typeof(Page), typeof(NavigationPage), null); - public static readonly BindableProperty RootPageProperty = RootPagePropertyKey.BindableProperty; - + public NavigationPage() { _platformConfigurationRegistry = new Lazy<PlatformConfigurationRegistry<NavigationPage>>(() => new PlatformConfigurationRegistry<NavigationPage>(this)); @@ -65,23 +61,17 @@ namespace Xamarin.Forms internal Task CurrentNavigationTask { get; set; } - Page INavigationPageController.Peek(int depth) + Stack<Page> INavigationPageController.StackCopy { - if (depth < 0) - { - return null; - } - - if (PageController.InternalChildren.Count <= depth) + get { - return null; + var result = new Stack<Page>(PageController.InternalChildren.Count); + foreach (Page page in PageController.InternalChildren) + result.Push(page); + return result; } - - return (Page)PageController.InternalChildren[PageController.InternalChildren.Count - depth - 1]; } - IEnumerable<Page> INavigationPageController.Pages => PageController.InternalChildren.Cast<Page>(); - int INavigationPageController.StackDepth { get { return PageController.InternalChildren.Count; } @@ -95,12 +85,6 @@ namespace Xamarin.Forms private set { SetValue(CurrentPagePropertyKey, value); } } - public Page RootPage - { - get { return (Page)GetValue(RootPageProperty); } - private set { SetValue(RootPagePropertyKey, value); } - } - public static string GetBackButtonTitle(BindableObject page) { return (string)page.GetValue(BackButtonTitleProperty); @@ -313,14 +297,8 @@ namespace Xamarin.Forms void InsertPageBefore(Page page, Page before) { - if (page == null) - throw new ArgumentNullException($"{nameof(page)} cannot be null."); - - if (before == null) - throw new ArgumentNullException($"{nameof(before)} cannot be null."); - if (!PageController.InternalChildren.Contains(before)) - throw new ArgumentException($"{nameof(before)} must be a child of the NavigationPage", nameof(before)); + throw new ArgumentException("before must be a child of the NavigationPage", "before"); if (PageController.InternalChildren.Contains(page)) throw new ArgumentException("Cannot insert page which is already in the navigation stack"); @@ -331,9 +309,6 @@ namespace Xamarin.Forms int index = PageController.InternalChildren.IndexOf(before); PageController.InternalChildren.Insert(index, page); - if (index == 0) - RootPage = page; - // Shouldn't be required? if (Width > 0 && Height > 0) ForceLayout(); @@ -344,13 +319,15 @@ namespace Xamarin.Forms if (((INavigationPageController)this).StackDepth == 1) return; - Element[] childrenToRemove = PageController.InternalChildren.Skip(1).ToArray(); - foreach (Element child in childrenToRemove) + var root = (Page)PageController.InternalChildren.First(); + + var childrenToRemove = PageController.InternalChildren.ToArray().Where(c => c != root); + foreach (var child in childrenToRemove) PageController.InternalChildren.Remove(child); - CurrentPage = RootPage; + CurrentPage = root; - var args = new NavigationRequestedEventArgs(RootPage, animated); + var args = new NavigationRequestedEventArgs(root, animated); EventHandler<NavigationRequestedEventArgs> requestPopToRoot = PopToRootRequestedInternal; if (requestPopToRoot != null) @@ -361,7 +338,8 @@ namespace Xamarin.Forms await args.Task; } - PoppedToRoot?.Invoke(this, new PoppedToRootEventArgs(RootPage, childrenToRemove.OfType<Page>().ToList())); + if (PoppedToRoot != null) + PoppedToRoot(this, new PoppedToRootEventArgs(root, childrenToRemove.OfType<Page>().ToList())); } async Task PushAsyncInner(Page page, bool animated) @@ -382,29 +360,24 @@ namespace Xamarin.Forms await args.Task; } - Pushed?.Invoke(this, args); + if (Pushed != null) + Pushed(this, args); } void PushPage(Page page) { PageController.InternalChildren.Add(page); - if (PageController.InternalChildren.Count == 1) - RootPage = page; - CurrentPage = page; } void RemovePage(Page page) { - if (page == null) - throw new ArgumentNullException($"{nameof(page)} cannot be null."); - - if (page == CurrentPage && CurrentPage == RootPage) + if (page == CurrentPage && ((INavigationPageController)this).StackDepth <= 1) throw new InvalidOperationException("Cannot remove root page when it is also the currently displayed page."); if (page == CurrentPage) { - Log.Warning("NavigationPage", "RemovePage called for CurrentPage object. This can result in undesired behavior, consider calling PopAsync instead."); + Log.Warning("NavigationPage", "RemovePage called for CurrentPage object. This can result in undesired behavior, consider called PopAsync instead."); PopAsync(); return; } @@ -413,11 +386,10 @@ namespace Xamarin.Forms throw new ArgumentException("Page to remove must be contained on this Navigation Page"); EventHandler<NavigationRequestedEventArgs> handler = RemovePageRequestedInternal; - handler?.Invoke(this, new NavigationRequestedEventArgs(page, true)); + if (handler != null) + handler(this, new NavigationRequestedEventArgs(page, true)); PageController.InternalChildren.Remove(page); - if (RootPage == page) - RootPage = (Page)PageController.InternalChildren.First(); } void SafePop() diff --git a/Xamarin.Forms.Core/PlatformConfiguration/ExtensionPoints.cs b/Xamarin.Forms.Core/PlatformConfiguration/ExtensionPoints.cs index fbddfeb7..b74e9b9a 100644 --- a/Xamarin.Forms.Core/PlatformConfiguration/ExtensionPoints.cs +++ b/Xamarin.Forms.Core/PlatformConfiguration/ExtensionPoints.cs @@ -5,5 +5,4 @@ namespace Xamarin.Forms.PlatformConfiguration public sealed class iOS : IConfigPlatform { } public sealed class Windows : IConfigPlatform { } public sealed class Tizen : IConfigPlatform { } - public sealed class macOS : IConfigPlatform { } } diff --git a/Xamarin.Forms.Core/PlatformConfiguration/macOSSpecific/TabbedPage.cs b/Xamarin.Forms.Core/PlatformConfiguration/macOSSpecific/TabbedPage.cs deleted file mode 100644 index 3c51805b..00000000 --- a/Xamarin.Forms.Core/PlatformConfiguration/macOSSpecific/TabbedPage.cs +++ /dev/null @@ -1,50 +0,0 @@ -namespace Xamarin.Forms.PlatformConfiguration.macOSSpecific -{ - using FormsElement = Forms.TabbedPage; - - public static class TabbedPage - { - #region TabsStyle - public static readonly BindableProperty TabsStyleProperty = BindableProperty.Create("TabsStyle", typeof(TabsStyle), typeof(TabbedPage), TabsStyle.Default); - - public static TabsStyle GetTabsStyle(BindableObject element) - { - return (TabsStyle)element.GetValue(TabsStyleProperty); - } - - public static void SetTabsStyle(BindableObject element, TabsStyle value) - { - element.SetValue(TabsStyleProperty, value); - } - - public static TabsStyle GetTabsStyle(this IPlatformElementConfiguration<macOS, FormsElement> config) - { - return GetTabsStyle(config.Element); - } - - public static IPlatformElementConfiguration<macOS, FormsElement> SetShowTabs(this IPlatformElementConfiguration<macOS, FormsElement> config, TabsStyle value) - { - SetTabsStyle(config.Element, value); - return config; - } - - public static IPlatformElementConfiguration<macOS, FormsElement> ShowTabsOnNavigation(this IPlatformElementConfiguration<macOS, FormsElement> config) - { - SetTabsStyle(config.Element, TabsStyle.OnNavigation); - return config; - } - - public static IPlatformElementConfiguration<macOS, FormsElement> ShowTabs(this IPlatformElementConfiguration<macOS, FormsElement> config) - { - SetTabsStyle(config.Element, TabsStyle.Default); - return config; - } - - public static IPlatformElementConfiguration<macOS, FormsElement> HideTabs(this IPlatformElementConfiguration<macOS, FormsElement> config) - { - SetTabsStyle(config.Element, TabsStyle.Hidden); - return config; - } - #endregion - } -} diff --git a/Xamarin.Forms.Core/PlatformConfiguration/macOSSpecific/TabsStyle.cs b/Xamarin.Forms.Core/PlatformConfiguration/macOSSpecific/TabsStyle.cs deleted file mode 100644 index 0b498ae5..00000000 --- a/Xamarin.Forms.Core/PlatformConfiguration/macOSSpecific/TabsStyle.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -namespace Xamarin.Forms -{ - public enum TabsStyle - { - Default = 0, - Hidden = 1, - Icons = 2, - OnNavigation = 3, - OnBottom = 4 - } -} diff --git a/Xamarin.Forms.Core/Properties/AssemblyInfo.cs b/Xamarin.Forms.Core/Properties/AssemblyInfo.cs index 7ba35cd3..2f686176 100644 --- a/Xamarin.Forms.Core/Properties/AssemblyInfo.cs +++ b/Xamarin.Forms.Core/Properties/AssemblyInfo.cs @@ -28,7 +28,7 @@ using Xamarin.Forms.Internals; [assembly: InternalsVisibleTo("Xamarin.Forms.Platform.WinRT.Tablet")] [assembly: InternalsVisibleTo("Xamarin.Forms.Platform.WinRT.Phone")] [assembly: InternalsVisibleTo("Xamarin.Forms.Platform.WP8")] -[assembly: InternalsVisibleTo("Xamarin.Forms.Platform.macOS")] +[assembly: InternalsVisibleTo("Xamarin.Forms.Platform.MacOS")] [assembly: InternalsVisibleTo("Xamarin.Forms.Platform.Tizen")] [assembly: InternalsVisibleTo("iOSUnitTests")] [assembly: InternalsVisibleTo("Xamarin.Forms.Controls")] @@ -49,7 +49,6 @@ using Xamarin.Forms.Internals; [assembly: InternalsVisibleTo("Xamarin.Forms.Core.iOS.UITests")] [assembly: InternalsVisibleTo("Xamarin.Forms.Core.Android.UITests")] [assembly: InternalsVisibleTo("Xamarin.Forms.Core.Windows.UITests")] -[assembly: InternalsVisibleTo("Xamarin.Forms.Core.macOS.UITests")] [assembly: InternalsVisibleTo("Xamarin.Forms.iOS.UITests")] [assembly: InternalsVisibleTo("Xamarin.Forms.Android.UITests")] [assembly: InternalsVisibleTo("Xamarin.Forms.Loader")] @@ -61,4 +60,4 @@ using Xamarin.Forms.Internals; [assembly: InternalsVisibleTo("Xamarin.Forms.CarouselView")] [assembly: Preserve] -[assembly: XmlnsDefinition("http://xamarin.com/schemas/2014/forms", "Xamarin.Forms")] +[assembly: XmlnsDefinition("http://xamarin.com/schemas/2014/forms", "Xamarin.Forms")]
\ No newline at end of file diff --git a/Xamarin.Forms.Core/RelativeLayout.cs b/Xamarin.Forms.Core/RelativeLayout.cs index 2b835013..b3a1b615 100644 --- a/Xamarin.Forms.Core/RelativeLayout.cs +++ b/Xamarin.Forms.Core/RelativeLayout.cs @@ -8,13 +8,13 @@ namespace Xamarin.Forms { public class RelativeLayout : Layout<View> { - public static readonly BindableProperty XConstraintProperty = BindableProperty.CreateAttached("XConstraint", typeof(Constraint), typeof(RelativeLayout), null, propertyChanged: ConstraintChanged); + public static readonly BindableProperty XConstraintProperty = BindableProperty.CreateAttached("XConstraint", typeof(Constraint), typeof(RelativeLayout), null); - public static readonly BindableProperty YConstraintProperty = BindableProperty.CreateAttached("YConstraint", typeof(Constraint), typeof(RelativeLayout), null, propertyChanged: ConstraintChanged); + public static readonly BindableProperty YConstraintProperty = BindableProperty.CreateAttached("YConstraint", typeof(Constraint), typeof(RelativeLayout), null); - public static readonly BindableProperty WidthConstraintProperty = BindableProperty.CreateAttached("WidthConstraint", typeof(Constraint), typeof(RelativeLayout), null, propertyChanged: ConstraintChanged); + public static readonly BindableProperty WidthConstraintProperty = BindableProperty.CreateAttached("WidthConstraint", typeof(Constraint), typeof(RelativeLayout), null); - public static readonly BindableProperty HeightConstraintProperty = BindableProperty.CreateAttached("HeightConstraint", typeof(Constraint), typeof(RelativeLayout), null, propertyChanged: ConstraintChanged); + public static readonly BindableProperty HeightConstraintProperty = BindableProperty.CreateAttached("HeightConstraint", typeof(Constraint), typeof(RelativeLayout), null); public static readonly BindableProperty BoundsConstraintProperty = BindableProperty.CreateAttached("BoundsConstraint", typeof(BoundsConstraint), typeof(RelativeLayout), null); @@ -72,25 +72,6 @@ namespace Xamarin.Forms } } - static void ConstraintChanged(BindableObject bindable, object oldValue, object newValue) - { - View view = bindable as View; - - (view?.Parent as RelativeLayout)?.UpdateBoundsConstraint(view); - } - - void UpdateBoundsConstraint(View view) - { - if (GetBoundsConstraint(view) == null) - return; // Bounds constraint hasn't been calculated yet, no need to update just yet - - CreateBoundsFromConstraints(view, GetXConstraint(view), GetYConstraint(view), GetWidthConstraint(view), GetHeightConstraint(view)); - - _childrenInSolveOrder = null; // New constraints may have impact on solve order - - InvalidateLayout(); - } - public static BoundsConstraint GetBoundsConstraint(BindableObject bindable) { return (BoundsConstraint)bindable.GetValue(BoundsConstraintProperty); @@ -121,26 +102,6 @@ namespace Xamarin.Forms bindable.SetValue(BoundsConstraintProperty, value); } - public static void SetHeightConstraint(BindableObject bindable, Constraint value) - { - bindable.SetValue(HeightConstraintProperty, value); - } - - public static void SetWidthConstraint(BindableObject bindable, Constraint value) - { - bindable.SetValue(WidthConstraintProperty, value); - } - - public static void SetXConstraint(BindableObject bindable, Constraint value) - { - bindable.SetValue(XConstraintProperty, value); - } - - public static void SetYConstraint(BindableObject bindable, Constraint value) - { - bindable.SetValue(YConstraintProperty, value); - } - protected override void LayoutChildren(double x, double y, double width, double height) { foreach (View child in ChildrenInSolveOrder) @@ -287,13 +248,13 @@ namespace Xamarin.Forms static Rectangle SolveView(View view) { BoundsConstraint boundsConstraint = GetBoundsConstraint(view); + var result = new Rectangle(); if (boundsConstraint == null) { throw new Exception("BoundsConstraint should not be null at this point"); } - - var result = boundsConstraint.Compute(); + result = boundsConstraint.Compute(); return result; } @@ -319,7 +280,7 @@ namespace Xamarin.Forms public void Add(View view, Expression<Func<Rectangle>> bounds) { if (bounds == null) - throw new ArgumentNullException(nameof(bounds)); + throw new ArgumentNullException("bounds"); SetBoundsConstraint(view, BoundsConstraint.FromExpression(bounds)); base.Add(view); @@ -347,14 +308,7 @@ namespace Xamarin.Forms public void Add(View view, Constraint xConstraint = null, Constraint yConstraint = null, Constraint widthConstraint = null, Constraint heightConstraint = null) { - view.BatchBegin(); - - RelativeLayout.SetXConstraint(view, xConstraint); - RelativeLayout.SetYConstraint(view, yConstraint); - RelativeLayout.SetWidthConstraint(view, widthConstraint); - RelativeLayout.SetHeightConstraint(view, heightConstraint); - - view.BatchCommit(); + Parent.CreateBoundsFromConstraints(view, xConstraint, yConstraint, widthConstraint, heightConstraint); base.Add(view); } diff --git a/Xamarin.Forms.Core/ResourceDictionary.cs b/Xamarin.Forms.Core/ResourceDictionary.cs index a213dee5..ed3ea7f5 100644 --- a/Xamarin.Forms.Core/ResourceDictionary.cs +++ b/Xamarin.Forms.Core/ResourceDictionary.cs @@ -72,8 +72,6 @@ namespace Xamarin.Forms public void Add(string key, object value) { - if (ContainsKey(key)) - throw new ArgumentException($"A resource with the key '{key}' is already present in the ResourceDictionary."); _innerDictionary.Add(key, value); OnValueChanged(key, value); } diff --git a/Xamarin.Forms.Core/SplitOrderedList.cs b/Xamarin.Forms.Core/SplitOrderedList.cs new file mode 100644 index 00000000..6f423210 --- /dev/null +++ b/Xamarin.Forms.Core/SplitOrderedList.cs @@ -0,0 +1,497 @@ +// SplitOrderedList.cs +// +// Copyright (c) 2010 Jérémie "Garuma" Laval +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +using System; +using System.Collections.Generic; +using System.Threading; + +namespace Xamarin.Forms +{ + internal class SplitOrderedList<TKey, T> + { + const int MaxLoad = 5; + const uint BucketSize = 512; + + static readonly byte[] ReverseTable = + { + 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, 4, + 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, + 50, 178, 114, 242, 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, 14, 142, 78, 206, 46, 174, 110, + 238, 30, 158, 94, 222, 62, 190, 126, 254, 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, 5, 133, 69, + 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, + 115, 243, 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, 15, 143, 79, 207, 47, 175, 111, 239, 31, + 159, 95, 223, 63, 191, 127, 255 + }; + + static readonly byte[] LogTable = + { + 0xFF, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7 + }; + + readonly IEqualityComparer<TKey> _comparer; + + readonly Node _head; + readonly Node _tail; + + Node[] _buckets = new Node[BucketSize]; + int _count; + int _size = 2; + + SimpleRwLock _slim = new SimpleRwLock(); + + public SplitOrderedList(IEqualityComparer<TKey> comparer) + { + _comparer = comparer; + _head = new Node().Init(0); + _tail = new Node().Init(ulong.MaxValue); + _head.Next = _tail; + SetBucket(0, _head); + } + + public int Count + { + get { return _count; } + } + + public bool CompareExchange(uint key, TKey subKey, T data, Func<T, bool> check) + { + Node node; + uint b = key % (uint)_size; + Node bucket; + + if ((bucket = GetBucket(b)) == null) + bucket = InitializeBucket(b); + + if (!ListFind(ComputeRegularKey(key), subKey, bucket, out node)) + return false; + + if (!check(node.Data)) + return false; + + node.Data = data; + + return true; + } + + public bool Delete(uint key, TKey subKey, out T data) + { + uint b = key % (uint)_size; + Node bucket; + + if ((bucket = GetBucket(b)) == null) + bucket = InitializeBucket(b); + + if (!ListDelete(bucket, ComputeRegularKey(key), subKey, out data)) + return false; + + Interlocked.Decrement(ref _count); + return true; + } + + public bool Find(uint key, TKey subKey, out T data) + { + Node node; + uint b = key % (uint)_size; + data = default(T); + Node bucket; + + if ((bucket = GetBucket(b)) == null) + bucket = InitializeBucket(b); + + if (!ListFind(ComputeRegularKey(key), subKey, bucket, out node)) + return false; + + data = node.Data; + + return !node.Marked; + } + + public IEnumerator<T> GetEnumerator() + { + Node node = _head.Next; + + while (node != _tail) + { + while (node.Marked || (node.Key & 1) == 0) + { + node = node.Next; + if (node == _tail) + yield break; + } + yield return node.Data; + node = node.Next; + } + } + + public bool Insert(uint key, TKey subKey, T data) + { + Node current; + return InsertInternal(key, subKey, data, null, out current); + } + + public T InsertOrGet(uint key, TKey subKey, T data, Func<T> dataCreator) + { + Node current; + InsertInternal(key, subKey, data, dataCreator, out current); + return current.Data; + } + + public T InsertOrUpdate(uint key, TKey subKey, Func<T> addGetter, Func<T, T> updateGetter) + { + Node current; + bool result = InsertInternal(key, subKey, default(T), addGetter, out current); + + if (result) + return current.Data; + + // FIXME: this should have a CAS-like behavior + return current.Data = updateGetter(current.Data); + } + + public T InsertOrUpdate(uint key, TKey subKey, T addValue, T updateValue) + { + Node current; + if (InsertInternal(key, subKey, addValue, null, out current)) + return current.Data; + + // FIXME: this should have a CAS-like behavior + return current.Data = updateValue; + } + + // When we run out of space for bucket storage, we use a lock-based array resize + void CheckSegment(uint segment, bool readLockTaken) + { + if (segment < _buckets.Length) + return; + + if (readLockTaken) + _slim.ExitReadLock(); + try + { + _slim.EnterWriteLock(); + while (segment >= _buckets.Length) + Array.Resize(ref _buckets, _buckets.Length * 2); + } + finally + { + _slim.ExitWriteLock(); + } + if (readLockTaken) + _slim.EnterReadLock(); + } + + // Reverse integer bits + static ulong ComputeDummyKey(uint key) + { + return (ulong)(((uint)ReverseTable[key & 0xff] << 24) | ((uint)ReverseTable[(key >> 8) & 0xff] << 16) | ((uint)ReverseTable[(key >> 16) & 0xff] << 8) | ReverseTable[(key >> 24) & 0xff]) << 1; + } + + // Reverse integer bits and make sure LSB is set + static ulong ComputeRegularKey(uint key) + { + return ComputeDummyKey(key) | 1; + } + + // Bucket storage is abstracted in a simple two-layer tree to avoid too much memory resize + Node GetBucket(uint index) + { + if (index >= _buckets.Length) + return null; + return _buckets[index]; + } + + // Turn v's MSB off + static uint GetParent(uint v) + { + uint t, tt; + + // Find MSB position in v + int pos = (tt = v >> 16) > 0 ? (t = tt >> 8) > 0 ? 24 + LogTable[t] : 16 + LogTable[tt] : (t = v >> 8) > 0 ? 8 + LogTable[t] : LogTable[v]; + + return (uint)(v & ~(1 << pos)); + } + + Node InitializeBucket(uint b) + { + Node current; + uint parent = GetParent(b); + Node bucket; + + if ((bucket = GetBucket(parent)) == null) + bucket = InitializeBucket(parent); + + Node dummy = new Node().Init(ComputeDummyKey(b)); + if (!ListInsert(dummy, bucket, out current, null)) + return current; + + return SetBucket(b, dummy); + } + + bool InsertInternal(uint key, TKey subKey, T data, Func<T> dataCreator, out Node current) + { + Node node = new Node().Init(ComputeRegularKey(key), subKey, data); + + uint b = key % (uint)_size; + Node bucket; + + if ((bucket = GetBucket(b)) == null) + bucket = InitializeBucket(b); + + if (!ListInsert(node, bucket, out current, dataCreator)) + return false; + + int csize = _size; + if (Interlocked.Increment(ref _count) / csize > MaxLoad && (csize & 0x40000000) == 0) + Interlocked.CompareExchange(ref _size, 2 * csize, csize); + + current = node; + + return true; + } + + bool ListDelete(Node startPoint, ulong key, TKey subKey, out T data) + { + Node rightNode = null, rightNodeNext = null, leftNode = null; + data = default(T); + Node markedNode = null; + + do + { + rightNode = ListSearch(key, subKey, ref leftNode, startPoint); + if (rightNode == _tail || rightNode.Key != key || !_comparer.Equals(subKey, rightNode.SubKey)) + return false; + + data = rightNode.Data; + rightNodeNext = rightNode.Next; + + if (!rightNodeNext.Marked) + { + if (markedNode == null) + markedNode = new Node(); + markedNode.Init(rightNodeNext); + + if (Interlocked.CompareExchange(ref rightNode.Next, markedNode, rightNodeNext) == rightNodeNext) + break; + } + } while (true); + + if (Interlocked.CompareExchange(ref leftNode.Next, rightNodeNext, rightNode) != rightNode) + ListSearch(rightNode.Key, subKey, ref leftNode, startPoint); + + return true; + } + + bool ListFind(ulong key, TKey subKey, Node startPoint, out Node data) + { + Node rightNode = null, leftNode = null; + data = null; + + rightNode = ListSearch(key, subKey, ref leftNode, startPoint); + data = rightNode; + + return rightNode != _tail && rightNode.Key == key && _comparer.Equals(subKey, rightNode.SubKey); + } + + bool ListInsert(Node newNode, Node startPoint, out Node current, Func<T> dataCreator) + { + ulong key = newNode.Key; + Node rightNode = null, leftNode = null; + + do + { + rightNode = current = ListSearch(key, newNode.SubKey, ref leftNode, startPoint); + if (rightNode != _tail && rightNode.Key == key && _comparer.Equals(newNode.SubKey, rightNode.SubKey)) + return false; + + newNode.Next = rightNode; + if (dataCreator != null) + newNode.Data = dataCreator(); + if (Interlocked.CompareExchange(ref leftNode.Next, newNode, rightNode) == rightNode) + return true; + } while (true); + } + + Node ListSearch(ulong key, TKey subKey, ref Node left, Node h) + { + Node leftNodeNext = null, rightNode = null; + + do + { + Node t = h; + Node tNext = t.Next; + do + { + if (!tNext.Marked) + { + left = t; + leftNodeNext = tNext; + } + t = tNext.Marked ? tNext.Next : tNext; + if (t == _tail) + break; + + tNext = t.Next; + } while (tNext.Marked || t.Key < key || (tNext.Key == key && !_comparer.Equals(subKey, t.SubKey))); + + rightNode = t; + + if (leftNodeNext == rightNode) + { + if (rightNode != _tail && rightNode.Next.Marked) + continue; + return rightNode; + } + + if (Interlocked.CompareExchange(ref left.Next, rightNode, leftNodeNext) == leftNodeNext) + { + if (rightNode != _tail && rightNode.Next.Marked) + continue; + return rightNode; + } + } while (true); + } + + Node SetBucket(uint index, Node node) + { + try + { + _slim.EnterReadLock(); + CheckSegment(index, true); + + Interlocked.CompareExchange(ref _buckets[index], node, null); + return _buckets[index]; + } + finally + { + _slim.ExitReadLock(); + } + } + + class Node + { + public T Data; + public ulong Key; + public bool Marked; + public Node Next; + public TKey SubKey; + + public Node Init(ulong key, TKey subKey, T data) + { + Key = key; + SubKey = subKey; + Data = data; + + Marked = false; + Next = null; + + return this; + } + + // Used to create dummy node + public Node Init(ulong key) + { + Key = key; + Data = default(T); + + Next = null; + Marked = false; + SubKey = default(TKey); + + return this; + } + + // Used to create marked node + public Node Init(Node wrapped) + { + Marked = true; + Next = wrapped; + + Key = 0; + Data = default(T); + SubKey = default(TKey); + + return this; + } + } + + struct SimpleRwLock + { + const int RwWait = 1; + const int RwWrite = 2; + const int RwRead = 4; + + int _rwlock; + + public void EnterReadLock() + { + var sw = new SpinWait(); + do + { + while ((_rwlock & (RwWrite | RwWait)) > 0) + sw.SpinOnce(); + + if ((Interlocked.Add(ref _rwlock, RwRead) & (RwWait | RwWait)) == 0) + return; + + Interlocked.Add(ref _rwlock, -RwRead); + } while (true); + } + + public void ExitReadLock() + { + Interlocked.Add(ref _rwlock, -RwRead); + } + + public void EnterWriteLock() + { + var sw = new SpinWait(); + do + { + int state = _rwlock; + if (state < RwWrite) + { + if (Interlocked.CompareExchange(ref _rwlock, RwWrite, state) == state) + return; + state = _rwlock; + } + // We register our interest in taking the Write lock (if upgradeable it's already done) + while ((state & RwWait) == 0 && Interlocked.CompareExchange(ref _rwlock, state | RwWait, state) != state) + state = _rwlock; + // Before falling to sleep + while (_rwlock > RwWait) + sw.SpinOnce(); + } while (true); + } + + public void ExitWriteLock() + { + Interlocked.Add(ref _rwlock, -RwWrite); + } + } + } +}
\ No newline at end of file diff --git a/Xamarin.Forms.Core/TargetPlatform.cs b/Xamarin.Forms.Core/TargetPlatform.cs index ff34d83a..6125695f 100644 --- a/Xamarin.Forms.Core/TargetPlatform.cs +++ b/Xamarin.Forms.Core/TargetPlatform.cs @@ -9,6 +9,6 @@ namespace Xamarin.Forms iOS, Android, WinPhone, - Windows + Windows, } } diff --git a/Xamarin.Forms.Core/Xamarin.Forms.Core.csproj b/Xamarin.Forms.Core/Xamarin.Forms.Core.csproj index b2c9c745..5efcf42e 100644 --- a/Xamarin.Forms.Core/Xamarin.Forms.Core.csproj +++ b/Xamarin.Forms.Core/Xamarin.Forms.Core.csproj @@ -50,7 +50,6 @@ </PropertyGroup> <ItemGroup> <Compile Include="AbsoluteLayoutFlags.cs" /> - <Compile Include="Accessibility.cs" /> <Compile Include="ActionSheetArguments.cs" /> <Compile Include="AlertArguments.cs" /> <Compile Include="AnimatableKey.cs" /> @@ -244,6 +243,7 @@ <Compile Include="Properties\GlobalAssemblyInfo.cs" /> <Compile Include="PropertyChangingEventArgs.cs" /> <Compile Include="IValueConverter.cs" /> + <Compile Include="ConcurrentDictionary.cs" /> <Compile Include="PropertyChangingEventHandler.cs" /> <Compile Include="ReadOnlyCastingList.cs" /> <Compile Include="ReadOnlyListAdapter.cs" /> @@ -265,6 +265,7 @@ <Compile Include="SeparatorVisibility.cs" /> <Compile Include="SizeRequest.cs" /> <Compile Include="Span.cs" /> + <Compile Include="SplitOrderedList.cs" /> <Compile Include="StackOrientation.cs" /> <Compile Include="StreamWrapper.cs" /> <Compile Include="SynchronizedList.cs" /> @@ -455,8 +456,6 @@ <Compile Include="ProvideCompiledAttribute.cs" /> <Compile Include="TypedBinding.cs" /> <Compile Include="XmlnsDefinitionAttribute.cs" /> - <Compile Include="PlatformConfiguration\macOSSpecific\TabbedPage.cs" /> - <Compile Include="PlatformConfiguration\macOSSpecific\TabsStyle.cs" /> </ItemGroup> <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" /> <ItemGroup> @@ -471,7 +470,4 @@ </PostBuildEvent> </PropertyGroup> <ItemGroup /> - <ItemGroup> - <Folder Include="PlatformConfiguration\macOSSpecific\" /> - </ItemGroup> -</Project> +</Project>
\ No newline at end of file |