Browse Source

Implemented new CommandMap

tags/1.0-rc
RogueException 9 years ago
parent
commit
7723130713
3 changed files with 178 additions and 43 deletions
  1. +7
    -43
      src/Discord.Net.Commands/CommandService.cs
  2. +76
    -0
      src/Discord.Net.Commands/Map/CommandMap.cs
  3. +95
    -0
      src/Discord.Net.Commands/Map/CommandMapNode.cs

+ 7
- 43
src/Discord.Net.Commands/CommandService.cs View File

@@ -14,8 +14,8 @@ namespace Discord.Commands
{
private readonly SemaphoreSlim _moduleLock;
private readonly ConcurrentDictionary<object, Module> _modules;
private readonly ConcurrentDictionary<string, List<Command>> _map;
private readonly ConcurrentDictionary<Type, TypeReader> _typeReaders;
private readonly CommandMap _map;

public IEnumerable<Module> Modules => _modules.Select(x => x.Value);
public IEnumerable<Command> Commands => _modules.SelectMany(x => x.Value.Commands);
@@ -24,7 +24,7 @@ namespace Discord.Commands
{
_moduleLock = new SemaphoreSlim(1, 1);
_modules = new ConcurrentDictionary<object, Module>();
_map = new ConcurrentDictionary<string, List<Command>>();
_map = new CommandMap();
_typeReaders = new ConcurrentDictionary<Type, TypeReader>
{
[typeof(string)] = new GenericTypeReader((m, s) => Task.FromResult(TypeReaderResult.FromSuccess(s))),
@@ -160,11 +160,7 @@ namespace Discord.Commands
_modules[moduleInstance] = loadedModule;

foreach (var cmd in loadedModule.Commands)
{
var list = _map.GetOrAdd(cmd.Text, _ => new List<Command>());
lock (list)
list.Add(cmd);
}
_map.AddCommand(cmd);

return loadedModule;
}
@@ -222,14 +218,7 @@ namespace Discord.Commands
if (_modules.TryRemove(module, out unloadedModule))
{
foreach (var cmd in unloadedModule.Commands)
{
List<Command> list;
if (_map.TryGetValue(cmd.Text, out list))
{
lock (list)
list.Remove(cmd);
}
}
_map.RemoveCommand(cmd);
return true;
}
else
@@ -240,35 +229,10 @@ namespace Discord.Commands
public SearchResult Search(IMessage message, string input)
{
string lowerInput = input.ToLowerInvariant();

ImmutableArray<Command>.Builder matches = null;
List<Command> group;
int pos = -1;

while (true)
{
pos = input.IndexOf(' ', pos + 1);
string cmdText = pos == -1 ? input : input.Substring(0, pos);
if (!_map.TryGetValue(cmdText, out group))
break;

lock (group)
{
if (matches == null)
matches = ImmutableArray.CreateBuilder<Command>(group.Count);
for (int i = 0; i < group.Count; i++)
matches.Add(group[i]);
}

if (pos == -1)
{
pos = input.Length;
break;
}
}
var matches = _map.GetCommands(input).ToImmutableArray();
if (matches != null)
return SearchResult.FromSuccess(input, matches.ToImmutable());
if (matches.Length > 0)
return SearchResult.FromSuccess(input, matches);
else
return SearchResult.FromError(CommandError.UnknownCommand, "Unknown command.");
}


+ 76
- 0
src/Discord.Net.Commands/Map/CommandMap.cs View File

@@ -0,0 +1,76 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;

namespace Discord.Commands
{
internal class CommandMap
{
private readonly ConcurrentDictionary<string, CommandMapNode> _nodes;

public CommandMap()
{
_nodes = new ConcurrentDictionary<string, CommandMapNode>();
}

public void AddCommand(Command command)
{
string text = command.Text;
int nextSpace = text.IndexOf(' ');
string name;

lock (this)
{
if (nextSpace == -1)
name = command.Text;
else
name = command.Text.Substring(0, nextSpace);
var nextNode = _nodes.GetOrAdd(name, x => new CommandMapNode(x));
nextNode.AddCommand(nextSpace == -1 ? "" : text, nextSpace + 1, command);
}
}
public void RemoveCommand(Command command)
{
string text = command.Text;
int nextSpace = text.IndexOf(' ');
string name;

lock (this)
{
if (nextSpace == -1)
name = command.Text;
else
name = command.Text.Substring(0, nextSpace);

CommandMapNode nextNode;
if (_nodes.TryGetValue(name, out nextNode))
{
nextNode.AddCommand(nextSpace == -1 ? "" : text, nextSpace + 1, command);
if (nextNode.IsEmpty)
_nodes.TryRemove(name, out nextNode);
}
}
}

public IEnumerable<Command> GetCommands(string text)
{
int nextSpace = text.IndexOf(' ');
string name;

lock (this)
{
if (nextSpace == -1)
name = text;
else
name = text.Substring(0, nextSpace);

CommandMapNode nextNode;
if (_nodes.TryGetValue(name, out nextNode))
return nextNode.GetCommands(text, nextSpace + 1);
else
return Enumerable.Empty<Command>();
}
}
}
}

+ 95
- 0
src/Discord.Net.Commands/Map/CommandMapNode.cs View File

@@ -0,0 +1,95 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;

namespace Discord.Commands
{
internal class CommandMapNode
{
private readonly ConcurrentDictionary<string, CommandMapNode> _nodes;
private readonly string _name;
private ImmutableArray<Command> _commands;

public bool IsEmpty => _commands.Length == 0 && _nodes.Count == 0;

public CommandMapNode(string name)
{
_name = name;
_nodes = new ConcurrentDictionary<string, CommandMapNode>();
_commands = ImmutableArray.Create<Command>();
}

public void AddCommand(string text, int index, Command command)
{
int nextSpace = text.IndexOf(' ', index);
string name;

lock (this)
{
if (text == "")
_commands = _commands.Add(command);
else
{
if (nextSpace == -1)
name = text.Substring(index);
else
name = text.Substring(index, nextSpace - index);

var nextNode = _nodes.GetOrAdd(name, x => new CommandMapNode(x));
nextNode.AddCommand(nextSpace == -1 ? "" : text, nextSpace + 1, command);
}
}
}
public void RemoveCommand(string text, int index, Command command)
{
int nextSpace = text.IndexOf(' ', index);
string name;

lock (this)
{
if (text == "")
_commands = _commands.Remove(command);
else
{
if (nextSpace == -1)
name = text.Substring(index);
else
name = text.Substring(index, nextSpace - index);

CommandMapNode nextNode;
if (_nodes.TryGetValue(name, out nextNode))
{
nextNode.RemoveCommand(nextSpace == -1 ? "" : text, nextSpace + 1, command);
if (nextNode.IsEmpty)
_nodes.TryRemove(name, out nextNode);
}
}
}
}

public IEnumerable<Command> GetCommands(string text, int index)
{
int nextSpace = text.IndexOf(' ', index);
string name;

var commands = _commands;
for (int i = 0; i < commands.Length; i++)
yield return _commands[i];

if (text != "")
{
if (nextSpace == -1)
name = text.Substring(index);
else
name = text.Substring(index, nextSpace - index);

CommandMapNode nextNode;
if (_nodes.TryGetValue(name, out nextNode))
{
foreach (var cmd in nextNode.GetCommands(nextSpace == -1 ? "" : text, nextSpace + 1))
yield return cmd;
}
}
}
}
}

Loading…
Cancel
Save