// -----------------------------------------------------------------------
//
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You 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.
//
//
// -----------------------------------------------------------------------
namespace Lucene.Net.Support.Threading
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
///
/// Provides Simulated GetData & SetData functionality for Threads.
///
///
///
/// is meant to provide functionality for storing data
/// in a thread similar to the way the full .NET framework does.
///
///
/// Silverlight does not support the GetData(LocalDataStoreSlot) /
/// SetData(LocalDataStoreSlot, object) for threads. The Windows
/// Mobile 7 version of Silverlight 4 does not even support the
/// ThreadStatic attribute much less the generic ConcurrentDictionary.
///
///
public static class ThreadData
{
private static readonly WeakDictionary threadSlots = new WeakDictionary();
private static readonly object slotsSyncRoot = new object();
private static readonly object hashSyncRoot = new object();
private static Dictionary hash;
///
/// Gets the hash.
///
/// The hash.
private static Dictionary Hash
{
get
{
lock (hashSyncRoot)
{
if (hash == null)
hash = new Dictionary();
}
return hash;
}
}
///
/// Allocates the data slot.
///
///
/// An instance of .
///
public static LocalDataStoreSlot AllocateDataSlot()
{
return new LocalDataStoreSlot(true);
}
///
/// Allocates the named data slot.
///
/// The name.
///
/// An instance of .
///
public static LocalDataStoreSlot AllocateNamedDataSlot(string name)
{
LocalDataStoreSlot slot;
lock (hashSyncRoot)
{
hash = Hash;
object value;
if (hash.TryGetValue(name, out value))
{
throw new ArgumentException("Named data slot already exists", "name");
}
slot = AllocateDataSlot();
hash.Add(name, slot);
}
return slot;
}
///
/// Frees the named data slot.
///
/// The name.
public static void FreeNamedDataSlot(string name)
{
lock (hashSyncRoot)
{
var store = Hash;
object value = null;
if (store.TryGetValue(name, out value))
{
store.Remove(name);
}
}
}
///
/// Gets the data.
///
/// The slot.
/// An instance of .
public static object GetData(LocalDataStoreSlot slot)
{
if (slot == null)
throw new ArgumentNullException("slot");
object data = null;
lock (slotsSyncRoot)
{
object[] slots = null;
threadSlots.TryGetValue(Thread.CurrentThread, out slots);
if (slots != null && slot.SlotId < slots.Length)
data = slots[slot.SlotId];
}
return data;
}
///
/// Frees the local slot data.
///
/// The slot.
/// if set to true [is thread].
///
/// Thrown when is true since the
/// storing data outside a thread context is currently not supported.
///
public static void FreeLocalSlotData(int slot, bool isThread)
{
if (!isThread)
throw new NotImplementedException("FreeLocalSlotData currently only supports thread contexts");
lock (slotsSyncRoot)
{
object[] slots = null;
var current = Thread.CurrentThread;
threadSlots.TryGetValue(Thread.CurrentThread, out slots);
if (slots != null && slot < slots.Length)
{
// TODO: write an extension method for arrays to RemoveAt();
object[] copy = new object[slots.Length - 1];
if (slot > 0)
Array.Copy(slots, 0, copy, 0, slot);
if (slot < (slots.Length - 1))
Array.Copy(slots, slot + 1, copy, slot, (slots.Length - slot - 1));
slots = copy;
threadSlots[current] = slots;
}
}
}
///
/// Sets the data.
///
/// The slot.
/// The data.
public static void SetData(LocalDataStoreSlot slot, object data)
{
lock (slotsSyncRoot)
{
object[] slots = null;
if (!threadSlots.TryGetValue(Thread.CurrentThread, out slots))
threadSlots[Thread.CurrentThread] = slots = new object[slot.SlotId + 2];
else if (slot.SlotId >= slots.Length)
{
object[] copy = new object[slot.SlotId + 2];
int cap = slots.Length;
if (copy.Length < cap)
cap = copy.Length;
// TODO: create a static method for CopyTo
Array.Copy(slots, slots.GetLowerBound(0), copy, copy.GetLowerBound(0), cap);
threadSlots[Thread.CurrentThread] = slots = copy;
}
slots[slot.SlotId] = data;
}
}
}
}