mirror of
https://github.com/ICDSystems/ICD.Common.Utils.git
synced 2026-01-26 19:04:50 +00:00
Compare commits
303 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11004085c5 | ||
|
|
6ca015a561 | ||
|
|
73b1c4819c | ||
|
|
f913af6efe | ||
|
|
099517df7d | ||
|
|
6a7b58f50f | ||
|
|
2273d5b3a1 | ||
|
|
aa17f29305 | ||
|
|
e65578584a | ||
|
|
96d2df8871 | ||
|
|
b4d82a855e | ||
|
|
83bc344ab3 | ||
|
|
0821dcb3ca | ||
|
|
b6f64bb9b2 | ||
|
|
6ae110a997 | ||
|
|
efdb48f2c3 | ||
|
|
9d02ee0022 | ||
|
|
8c0416f70e | ||
|
|
0f27d68edf | ||
|
|
f8fc68e08f | ||
|
|
fc4ae67e40 | ||
|
|
0f618198b5 | ||
|
|
9a6f197aa0 | ||
|
|
45ee3e70b0 | ||
|
|
b09f614ef5 | ||
|
|
027c9ffe82 | ||
|
|
dc1b60e629 | ||
|
|
091ad10068 | ||
|
|
71bb320057 | ||
|
|
e6b0fd5f7b | ||
|
|
2a2bff2e92 | ||
|
|
9c07b3da04 | ||
|
|
438b3d48e4 | ||
|
|
629ceec84e | ||
|
|
bb41d59a4b | ||
|
|
c23d81e023 | ||
|
|
18abe78550 | ||
|
|
f33218f7a6 | ||
|
|
4938dad882 | ||
|
|
5900f5974b | ||
|
|
81f7eb9c66 | ||
|
|
440c1c62f1 | ||
|
|
63b590a9ea | ||
|
|
f8c88630fc | ||
|
|
3f1f9611ec | ||
|
|
47c611a0b4 | ||
|
|
e388f35efb | ||
|
|
89061b5cbf | ||
|
|
ff6f15d3ef | ||
|
|
02e6fe9f8c | ||
|
|
edb5534b9d | ||
|
|
6af3e5b2ff | ||
|
|
65f76402cc | ||
|
|
5700cf4ce2 | ||
|
|
7c238b9fef | ||
|
|
6eda848410 | ||
|
|
7b44867f34 | ||
|
|
149f480add | ||
|
|
0f5632ced8 | ||
|
|
9df5f7ae37 | ||
|
|
6e056c9dcc | ||
|
|
7add461a1a | ||
|
|
cb3677bd72 | ||
|
|
69ad4bb240 | ||
|
|
1a868d5a7d | ||
|
|
bb6110931a | ||
|
|
909ebfbc97 | ||
|
|
3d068aeb68 | ||
|
|
1f6915a825 | ||
|
|
00e7fd6a6b | ||
|
|
e3f356a5db | ||
|
|
2d401959b6 | ||
|
|
7cc5a47d6a | ||
|
|
8c160c77c4 | ||
|
|
65c50e8e90 | ||
|
|
3a2fc0eef7 | ||
|
|
1be852685d | ||
|
|
6201184fab | ||
|
|
e8acb42bb9 | ||
|
|
d3d812265e | ||
|
|
b915401109 | ||
|
|
3e3a4e33cb | ||
|
|
b680bab67a | ||
|
|
7666021925 | ||
|
|
7b6092c291 | ||
|
|
f7740aaea2 | ||
|
|
c31b2b556b | ||
|
|
8866a3e1e6 | ||
|
|
e3273934a7 | ||
|
|
0152259a25 | ||
|
|
98c3f17602 | ||
|
|
bb3fba100d | ||
|
|
9adad373f6 | ||
|
|
844f8b7b46 | ||
|
|
43d7ea944e | ||
|
|
6526b2b811 | ||
|
|
ead365e251 | ||
|
|
f24e6d2597 | ||
|
|
311f2dfaf4 | ||
|
|
1c38d9f04a | ||
|
|
02c18d152f | ||
|
|
fc482ec685 | ||
|
|
d649fb9dc4 | ||
|
|
4d76abe046 | ||
|
|
d6d3bfa9e0 | ||
|
|
536742a1c6 | ||
|
|
dc824b2034 | ||
|
|
0cc588ce15 | ||
|
|
b996a295f6 | ||
|
|
4312ad1a61 | ||
|
|
7792b01629 | ||
|
|
4953e40f9e | ||
|
|
69f872ced1 | ||
|
|
7e3aef4cb3 | ||
|
|
a6fbd5a6d2 | ||
|
|
6f67064d34 | ||
|
|
723759f805 | ||
|
|
59f4411620 | ||
|
|
243e285948 | ||
|
|
198bf8dac0 | ||
|
|
78f5c4a7b6 | ||
|
|
c0ed7f9b26 | ||
|
|
6d08ee3bef | ||
|
|
2b376bff47 | ||
|
|
9f0e66e4a1 | ||
|
|
4c93515f83 | ||
|
|
9ad49540d2 | ||
|
|
cbf7a3d79c | ||
|
|
5a4d3cabac | ||
|
|
dc0e65125a | ||
|
|
9d732ef4b2 | ||
|
|
ecdb4f4fb5 | ||
|
|
6f5188909b | ||
|
|
3fa089b85e | ||
|
|
fef667191b | ||
|
|
28abb69c85 | ||
|
|
0bf88240b2 | ||
|
|
294afd1834 | ||
|
|
475f381991 | ||
|
|
1460bf2924 | ||
|
|
ab58ba721e | ||
|
|
d7bfb07c2c | ||
|
|
33b1d29781 | ||
|
|
78c20201ab | ||
|
|
66f4e797ed | ||
|
|
94ac37b32a | ||
|
|
22978e90c4 | ||
|
|
995a57f8e4 | ||
|
|
d6d767d8f9 | ||
|
|
0931d6f1ec | ||
|
|
24859aaa31 | ||
|
|
798e9cc0a7 | ||
|
|
1dac1bfb67 | ||
|
|
829c24b667 | ||
|
|
715c198763 | ||
|
|
d8741773c5 | ||
|
|
26b924dd48 | ||
|
|
8892e6e223 | ||
|
|
23afa8e025 | ||
|
|
7d1cc3139f | ||
|
|
30ea6ced9e | ||
|
|
3041d0f402 | ||
|
|
f4693df048 | ||
|
|
736c2aee33 | ||
|
|
40342e2d9e | ||
|
|
5756d9654b | ||
|
|
b2ca43baf1 | ||
|
|
f36b9f7856 | ||
|
|
bcf13ef972 | ||
|
|
100b8e4753 | ||
|
|
134ee85067 | ||
|
|
c054a9d752 | ||
|
|
ef19e20d67 | ||
|
|
3fd344a308 | ||
|
|
17e7f4d3c9 | ||
|
|
87d1f4da16 | ||
|
|
88a4801f8e | ||
|
|
c55e35ac6e | ||
|
|
24601b0ef2 | ||
|
|
4fa46ff5a0 | ||
|
|
827ab2cd42 | ||
|
|
158c261d19 | ||
|
|
c607d1254e | ||
|
|
e90914664f | ||
|
|
fc855d407b | ||
|
|
e3a4713b3b | ||
|
|
f85896e947 | ||
|
|
131e2f87f4 | ||
|
|
4a330637a7 | ||
|
|
fa124a0afc | ||
|
|
72fd823643 | ||
|
|
644388edad | ||
|
|
cbb05c8b79 | ||
|
|
066c9f93a7 | ||
|
|
9aa7459b0f | ||
|
|
7557e01c9f | ||
|
|
f8a813c97b | ||
|
|
be6a6de65a | ||
|
|
ffe3e67241 | ||
|
|
141d911eb0 | ||
|
|
d6abf3fdf6 | ||
|
|
46a1ea09b6 | ||
|
|
2dc705d335 | ||
|
|
0700a357dd | ||
|
|
5fb7636ed4 | ||
|
|
196c2a535a | ||
|
|
db50ada952 | ||
|
|
087b04fd62 | ||
|
|
ea73351d39 | ||
|
|
ca1fae29b0 | ||
|
|
1916c2b750 | ||
|
|
3af2544e70 | ||
|
|
20e8aa93f2 | ||
|
|
3937902f38 | ||
|
|
021d5781a3 | ||
|
|
b429e4bc53 | ||
|
|
4a203e2449 | ||
|
|
d41203b856 | ||
|
|
2f21379e52 | ||
|
|
f60de4321b | ||
|
|
bd2ea606ae | ||
|
|
1f20c07e94 | ||
|
|
1be588b86a | ||
|
|
488df297fc | ||
|
|
80a4d94358 | ||
|
|
6a40f3ce18 | ||
|
|
d564a0a423 | ||
|
|
a9a544c433 | ||
|
|
2e0837f5c8 | ||
|
|
77be0ec477 | ||
|
|
524cdc3e31 | ||
|
|
1d6e8d55ca | ||
|
|
3ba5f11587 | ||
|
|
fb7a6e27b8 | ||
|
|
fffc8e4a60 | ||
|
|
1d7ada87c5 | ||
|
|
3a4438ec1e | ||
|
|
21ce86de0f | ||
|
|
3cb29452a2 | ||
|
|
114a5e4ec7 | ||
|
|
a9d411dcfd | ||
|
|
e708ef9603 | ||
|
|
aae4fb6185 | ||
|
|
8401ab1852 | ||
|
|
27760f2282 | ||
|
|
80a0ca26c5 | ||
|
|
b9ec2f3222 | ||
|
|
a6ad52d492 | ||
|
|
64e11db0bc | ||
|
|
d01e9345d5 | ||
|
|
466dc6deb5 | ||
|
|
ad47c890a8 | ||
|
|
108317212c | ||
|
|
4a411e8990 | ||
|
|
4cd28a8a12 | ||
|
|
470c35cab7 | ||
|
|
a372d97868 | ||
|
|
f208ec521b | ||
|
|
347cf70b6c | ||
|
|
1076795fae | ||
|
|
7d059bc605 | ||
|
|
dd270adf9e | ||
|
|
efb5e014ec | ||
|
|
083280cc64 | ||
|
|
e222ce424b | ||
|
|
ad7176506d | ||
|
|
e4e3e9b91a | ||
|
|
1721116908 | ||
|
|
d8489d31b6 | ||
|
|
a8552ea0e3 | ||
|
|
e700650735 | ||
|
|
ed9c017856 | ||
|
|
0ee1b440ee | ||
|
|
4184f85826 | ||
|
|
42cc8c2cfc | ||
|
|
6b37db3530 | ||
|
|
ad8fa216a5 | ||
|
|
ef415bb20f | ||
|
|
fe614ae8ad | ||
|
|
2d4bc57ed8 | ||
|
|
c048c4fc65 | ||
|
|
2e2eebd95f | ||
|
|
e21830a7d5 | ||
|
|
f53607018c | ||
|
|
e0176741d2 | ||
|
|
742b7e99aa | ||
|
|
cf0c71d39b | ||
|
|
376f9c0837 | ||
|
|
8b1c53ebe1 | ||
|
|
2e0b0da87f | ||
|
|
8311fe5c9d | ||
|
|
fb41d76a9c | ||
|
|
8f107aa209 | ||
|
|
2024dc0171 | ||
|
|
923866dbdf | ||
|
|
a14b4a5803 | ||
|
|
fac2610b83 | ||
|
|
0ef0286a9f | ||
|
|
d084553600 | ||
|
|
2b14a6b65c | ||
|
|
043a50669a | ||
|
|
b58220d3c7 | ||
|
|
03de74a494 |
201
CHANGELOG.md
201
CHANGELOG.md
@@ -6,6 +6,207 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [9.9.0] - 2019-09-16
|
||||
### Added
|
||||
- Added a method for converting 24 hour to 12 hour format
|
||||
- Added a method for determining if a culture uses 24 hour format
|
||||
- Added math util method for modulus
|
||||
- Added TimeSpan extension methods for cycling hours and minutes without modifying the day
|
||||
- Added a dictionary extension method for getting or adding a new value via func
|
||||
- Added CultureInfo extensions for converting between 12 hour and 24 hour time formatting
|
||||
- Added environment methods for setting the current date and time
|
||||
- Added BinarySearch extension method for all IList types
|
||||
- Added PathUtils methods to get ProgramData directory
|
||||
|
||||
### Changed
|
||||
- The Root Config path in Net Standard will now be the ICD.Connect folder in the current environments ProgramData directory
|
||||
- Fixed a bug where CultureInfo was not being cloned correctly
|
||||
- List AddSorted extensions now work for all IList types
|
||||
|
||||
## [9.8.0] - 2019-09-03
|
||||
### Added
|
||||
- Added Public API Properties to get the program install date based on the creation date of core dll file for NetStandard and SimplSharp
|
||||
- Implemented processor utils for NetStandard to get the system uptime and the program uptime
|
||||
- Added methods for deserializing an XML array
|
||||
|
||||
### Changed
|
||||
- Fixed a bug where ANSI color encoded strings with percentages were being scrambled
|
||||
- Improvements to JSON DateTime parsing, particularly in Net Standard
|
||||
|
||||
## [9.7.0] - 2019-08-15
|
||||
### Added
|
||||
- Added logger timestamps to non simplsharp programs
|
||||
- Added Net Standard Support for JSON DateTime formats
|
||||
- Added EmailValidation class
|
||||
|
||||
### Changed
|
||||
- JSON dict serialization serializes keys instead of converting to property name
|
||||
|
||||
## [9.6.0] - 2019-07-03
|
||||
### Added
|
||||
- Added RecursionUtils method to get a single clique given a starting node
|
||||
- Breadth First Search can now search graphs in addition to trees
|
||||
- Added StartOfDay and EndOfDay DateTime extension methods
|
||||
|
||||
### Changed
|
||||
- Fixed bug in IcdUriBuilder where Query property behaved differently to UriBuilder
|
||||
- Throwing an exception when attempting to read a non-primitive JSON token as a string
|
||||
|
||||
## [9.5.0] - 2019-06-10
|
||||
### Added
|
||||
- Added Shim to read a list from xml with no root element
|
||||
- Added a URI query builder
|
||||
|
||||
### Changed
|
||||
- Fixed JSON DateTime parsing in .Net Standard
|
||||
- Fixed threading exception in TypeExtensions
|
||||
- Fixes for platform-agnostic culture handling
|
||||
|
||||
## [9.4.0] - 2019-05-10
|
||||
### Added
|
||||
- Added extension method for peeking queues
|
||||
- Added extension method for getting or adding a new item to a dictionary
|
||||
- Added methods for serializing additional types, arrays and dictionaries to JSON
|
||||
- AbstractGenericJsonConverter exposes virtual methods for overriding object serialization/deserialization
|
||||
- Added RemoveRange method to IcdHashSet
|
||||
- Added IcdCultureInfo and CultureInfo database for localization
|
||||
|
||||
### Changed
|
||||
- IcdUriBuilder constructors behave closer to UriBuilder, Host defaults to "localhost"
|
||||
|
||||
## [9.3.0] - 2019-04-16
|
||||
### Added
|
||||
- Added SPlusUtils with ConvertToInt method taking LowWord/HighWord ushorts
|
||||
- Added JsonReader extension methods for reading DateTimes
|
||||
- Added JsonReader extension methods for writing properties
|
||||
- IcdStreamWriter exposes WriteLine(string)
|
||||
- Added ProgramLogsPath to PathUtils
|
||||
|
||||
### Changed
|
||||
- Fixes for VC4 compatibility
|
||||
- Fixed JSON DateTime parsing for timezone information
|
||||
- Small reflection optimizations
|
||||
|
||||
## [9.2.0] - 2019-03-01
|
||||
### Added
|
||||
- Added Type IsAssignableTo extension shim
|
||||
- Added constructor to BiDictionary to instantiate from an existing dict
|
||||
|
||||
### Changed
|
||||
- Fixed bug preventing deserialization of XML lists
|
||||
- Crestron ConsoleResponse uses PrintLine instead of Print
|
||||
- Use PrintLine instead of ConsoleResponse on Crestron server
|
||||
|
||||
## [9.1.0] - 2019-02-07
|
||||
### Added
|
||||
- Added SubscribeEvent shim for delegate callbacks
|
||||
- Extension method for reading JSON token as a GUID
|
||||
- Added ToStringJsonConverter
|
||||
|
||||
### Changed
|
||||
- Significantly reduced size of JSON serialized Types
|
||||
- Small logging optimizations
|
||||
|
||||
## [9.0.0] - 2019-01-29
|
||||
### Added
|
||||
- IcdConsole.OnConsolePrint event
|
||||
|
||||
### Changed
|
||||
- Better VC-4 support for IcdConsole
|
||||
- JSON refactoring for simpler deserialization
|
||||
|
||||
## [8.7.1] - 2019-08-22
|
||||
### Changed
|
||||
- Fixed a bug with the IcdOrderedDict index setter that was creating additional values
|
||||
|
||||
## [8.7.0] - 2019-06-24
|
||||
### Added
|
||||
- IcdXmlException exposes line number and position properties
|
||||
|
||||
## [8.6.1] - 2019-06-14
|
||||
### Changed
|
||||
- Fixed a bug where stopped timers on NetStandard would still have a periodic callback duration
|
||||
|
||||
## [8.6.0] - 2019-06-14
|
||||
### Changed
|
||||
- Overhaul of RangeAttribute remap methods to better avoid overflows
|
||||
|
||||
## [8.5.0] - 2019-06-06
|
||||
### Added
|
||||
- Adding features to IcdEnvironment for tracking program initialization state
|
||||
|
||||
## [8.4.1] - 2019-06-05
|
||||
### Changed
|
||||
- Caching the program/processor start time and calculating the uptime from those values instead of polling the crestron processor
|
||||
|
||||
## [8.4.0] - 2019-05-15
|
||||
### Added
|
||||
- Added GUID utils for generating seeded GUIDs
|
||||
- Added extension method for getting stable hashcodes from strings
|
||||
- Added environment and processor utilities for determining DNS status and hostname
|
||||
|
||||
### Changed
|
||||
- RangeAttribute improvements for better type safety
|
||||
- PathUtils breaking out ProgramConfigDirectory and CommonConfigDirectory from the full paths
|
||||
|
||||
## [8.3.3] - 2019-05-24
|
||||
### Added
|
||||
- Added empty, placeholder interface for ICD Attributes
|
||||
|
||||
## [8.3.2] - 2019-05-02
|
||||
### Changed
|
||||
- Fixed PriorityQueue IndexOutOfRange exception when an inner queue becomes depleted
|
||||
|
||||
## [8.3.1] - 2019-04-05
|
||||
### Changed
|
||||
- Fixed FormatException when parsing some JSON DateTimes
|
||||
|
||||
## [8.3.0] - 2019-01-25
|
||||
### Added
|
||||
- Added SimplSharpProMono to eRuntimeEnvironment enum
|
||||
- Added path support for SimplSharpProMono environment
|
||||
- Added GetApplicationRootDirectory for all platforms
|
||||
|
||||
### Changed
|
||||
- Small fixes for better VC4 support
|
||||
|
||||
## [8.2.0] - 2019-01-10
|
||||
### Added
|
||||
- Added TryGetPortForScheme method to UriExtensions
|
||||
- Added range attribute for clarifying numeric fields, properties and parameters
|
||||
|
||||
### Changed
|
||||
- IcdHashSet preserves comparer when an operation creates a new IcdHashSet
|
||||
- Fixed bug where XML fragments on Net Standard were being prepended with a document header
|
||||
|
||||
## [8.1.0] - 2019-01-02
|
||||
### Added
|
||||
- Added GetAttributeAsEnum xml utils method
|
||||
- Adding short parsing methods to XML utils
|
||||
- Added methods to IcdUriBuilder for appending path
|
||||
- Added RegexUtils method for replacing a single group in a match
|
||||
|
||||
## [8.0.0] - 2018-11-20
|
||||
### Added
|
||||
- XML TryGetAttribute methods
|
||||
|
||||
### Changed
|
||||
- Performance improvements when working with xml attributes
|
||||
- Fixed NullReferenceException when writing null strings to CSV
|
||||
- Fixed bug with string formatting console input on Net Standard
|
||||
|
||||
### Removed
|
||||
- Removed IcdXmlAttribute
|
||||
|
||||
## [7.1.0] - 2018-11-08
|
||||
### Added
|
||||
- IcdXmlTextWriter exposes WriteStartDocument and WriteEndDocument
|
||||
- AttributeUtils method for getting properties with the given attribute type
|
||||
|
||||
### Changed
|
||||
- EnumerableExtensions performance improvements
|
||||
- Fixed bug in StringExtensions when removing a sequence of characters from a string
|
||||
|
||||
## [7.0.0] - 2018-10-30
|
||||
### Changed
|
||||
- Micro-optimizations in string and XML manipulations
|
||||
|
||||
86
ICD.Common.Utils.Tests/Attributes/RangeAttributeTest.cs
Normal file
86
ICD.Common.Utils.Tests/Attributes/RangeAttributeTest.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using RangeAttribute = ICD.Common.Utils.Attributes.RangeAttribute;
|
||||
|
||||
namespace ICD.Common.Utils.Tests.Attributes
|
||||
{
|
||||
[TestFixture]
|
||||
public sealed class RangeAttributeTest : AbstractIcdAttributeTest<RangeAttribute>
|
||||
{
|
||||
#region Properties
|
||||
|
||||
[TestCase(1)]
|
||||
[TestCase(1.0f)]
|
||||
[TestCase(1.0)]
|
||||
public void MinTest(object min)
|
||||
{
|
||||
Assert.AreEqual(min, new RangeAttribute(min, min).Min);
|
||||
}
|
||||
|
||||
[TestCase(1)]
|
||||
[TestCase(1.0f)]
|
||||
[TestCase(1.0)]
|
||||
public void MaxTest(object max)
|
||||
{
|
||||
Assert.AreEqual(max, new RangeAttribute(max, max).Max);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
[TestCase((double)0, (double)0)]
|
||||
[TestCase((double)1, (double)1)]
|
||||
[TestCase(ushort.MaxValue, double.MaxValue)]
|
||||
[TestCase(short.MinValue, double.MinValue)]
|
||||
public void RemapToDoubleTest(object value, double expected)
|
||||
{
|
||||
Assert.AreEqual(expected, RangeAttribute.RemapToDouble(value));
|
||||
}
|
||||
|
||||
[TestCase((double)0, typeof(ushort), (ushort)32767)]
|
||||
[TestCase(double.MinValue, typeof(ushort), ushort.MinValue)]
|
||||
[TestCase(double.MaxValue, typeof(ushort), ushort.MaxValue)]
|
||||
public void RemapFromDoubleTest(double value, Type type, object expected)
|
||||
{
|
||||
Assert.AreEqual(expected, RangeAttribute.RemapFromDouble(value, type));
|
||||
}
|
||||
|
||||
[TestCase(short.MinValue, typeof(ushort), ushort.MinValue)]
|
||||
[TestCase(short.MaxValue, typeof(ushort), short.MaxValue)]
|
||||
public static void Clamp(object value, Type type, object expected)
|
||||
{
|
||||
Assert.AreEqual(expected, RangeAttribute.Clamp(value, type));
|
||||
}
|
||||
|
||||
[TestCase(double.MinValue, typeof(ushort), ushort.MinValue)]
|
||||
[TestCase(double.MaxValue, typeof(ushort), ushort.MaxValue)]
|
||||
public void Clamp(double value, Type type, double expected)
|
||||
{
|
||||
Assert.AreEqual(expected, RangeAttribute.Clamp(value, type));
|
||||
}
|
||||
|
||||
[TestCase(short.MinValue, typeof(ushort), ushort.MinValue)]
|
||||
[TestCase(short.MaxValue, typeof(ushort), ushort.MaxValue)]
|
||||
public void RemapTest(object value, Type type, object expected)
|
||||
{
|
||||
Assert.AreEqual(expected, RangeAttribute.Remap(value, type));
|
||||
}
|
||||
|
||||
[TestCase(0, 100, ushort.MaxValue, typeof(ushort), ushort.MaxValue)]
|
||||
[TestCase(0, 100, ushort.MaxValue, typeof(short), short.MaxValue)]
|
||||
public void ClampMinMaxThenRemapTest(object min, object max, object value, Type type, object expected)
|
||||
{
|
||||
Assert.AreEqual(expected, new RangeAttribute(min, max).ClampMinMaxThenRemap(value, type));
|
||||
}
|
||||
|
||||
[TestCase(0, 100, ushort.MaxValue, 100)]
|
||||
[TestCase(0, 100, ushort.MinValue, 0)]
|
||||
public void RemapMinMaxTest(object min, object max, object value, object expected)
|
||||
{
|
||||
Assert.AreEqual(expected, new RangeAttribute(min, max).RemapMinMax(value));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using ICD.Common.Utils.Collections;
|
||||
using ICD.Common.Utils.EventArguments;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace ICD.Common.Utils.Tests.Collections
|
||||
{
|
||||
[TestFixture]
|
||||
public sealed class AsyncEventQueueTest
|
||||
{
|
||||
[Test]
|
||||
public void ItemDequeuedFeedbackTest()
|
||||
{
|
||||
Assert.Inconclusive();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CountTest()
|
||||
{
|
||||
using (AsyncEventQueue<int> queue = new AsyncEventQueue<int>())
|
||||
{
|
||||
queue.OnItemDequeued +=
|
||||
(sender, args) =>
|
||||
{
|
||||
ThreadingUtils.Sleep(200);
|
||||
};
|
||||
|
||||
Assert.AreEqual(0, queue.Count);
|
||||
|
||||
for (int index = 0; index < 5; index++)
|
||||
queue.Enqueue(index);
|
||||
|
||||
Assert.AreEqual(5, queue.Count);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EnqueueTest()
|
||||
{
|
||||
using (AsyncEventQueue<int> queue = new AsyncEventQueue<int>())
|
||||
{
|
||||
List<GenericEventArgs<int>> eventArgs = new List<GenericEventArgs<int>>();
|
||||
queue.OnItemDequeued +=
|
||||
(sender, args) =>
|
||||
{
|
||||
eventArgs.Add(args);
|
||||
};
|
||||
|
||||
Assert.AreEqual(0, eventArgs.Count);
|
||||
|
||||
for (int index = 0; index < 5; index++)
|
||||
queue.Enqueue(index);
|
||||
|
||||
ThreadingUtils.Sleep(500);
|
||||
|
||||
Assert.AreEqual(5, eventArgs.Count);
|
||||
|
||||
Assert.AreEqual(0, eventArgs[0].Data);
|
||||
Assert.AreEqual(1, eventArgs[1].Data);
|
||||
Assert.AreEqual(2, eventArgs[2].Data);
|
||||
Assert.AreEqual(3, eventArgs[3].Data);
|
||||
Assert.AreEqual(4, eventArgs[4].Data);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ClearTest()
|
||||
{
|
||||
using (AsyncEventQueue<int> queue = new AsyncEventQueue<int>())
|
||||
{
|
||||
queue.OnItemDequeued +=
|
||||
(sender, args) =>
|
||||
{
|
||||
ThreadingUtils.Sleep(200);
|
||||
};
|
||||
|
||||
Assert.AreEqual(0, queue.Count);
|
||||
|
||||
for (int index = 0; index < 5; index++)
|
||||
queue.Enqueue(index);
|
||||
|
||||
Assert.AreEqual(5, queue.Count);
|
||||
|
||||
queue.Clear();
|
||||
|
||||
Assert.AreEqual(0, queue.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,16 +69,26 @@ namespace ICD.Common.Utils.Tests.Collections
|
||||
[Test]
|
||||
public void IndexerTest()
|
||||
{
|
||||
IcdOrderedDictionary<int, int> dict = new IcdOrderedDictionary<int, int>
|
||||
{
|
||||
{0, 0},
|
||||
{1, 10},
|
||||
{-1, -10}
|
||||
};
|
||||
// ReSharper disable UseObjectOrCollectionInitializer
|
||||
IcdOrderedDictionary<int, int> dict = new IcdOrderedDictionary<int, int>();
|
||||
// ReSharper restore UseObjectOrCollectionInitializer
|
||||
|
||||
dict[0] = 0;
|
||||
dict[1] = 10;
|
||||
dict[-1] = -10;
|
||||
dict[-1] = -11;
|
||||
|
||||
Assert.AreEqual(0, dict[0]);
|
||||
Assert.AreEqual(10, dict[1]);
|
||||
Assert.AreEqual(-10, dict[-1]);
|
||||
Assert.AreEqual(-11, dict[-1]);
|
||||
|
||||
Assert.AreEqual(3, dict.Count);
|
||||
|
||||
int[] expectedKeys = {-1, 0, 1 };
|
||||
int[] expectedValues = {-11, 0, 10};
|
||||
|
||||
Assert.AreEqual(expectedKeys, dict.Keys.ToArray());
|
||||
Assert.AreEqual(expectedValues, dict.Values.ToArray());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -168,6 +168,29 @@ namespace ICD.Common.Utils.Tests.Collections
|
||||
Assert.AreEqual(0, queue.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryDequeueTest()
|
||||
{
|
||||
PriorityQueue<int> queue = new PriorityQueue<int>();
|
||||
queue.Enqueue(10, 1);
|
||||
queue.Enqueue(20, 2);
|
||||
queue.Enqueue(30, 3);
|
||||
|
||||
int output;
|
||||
|
||||
Assert.IsTrue(queue.TryDequeue(out output));
|
||||
Assert.AreEqual(10, output);
|
||||
|
||||
Assert.IsTrue(queue.TryDequeue(out output));
|
||||
Assert.AreEqual(20, output);
|
||||
|
||||
Assert.IsTrue(queue.TryDequeue(out output));
|
||||
Assert.AreEqual(30, output);
|
||||
|
||||
Assert.IsFalse(queue.TryDequeue(out output));
|
||||
Assert.AreEqual(0, output);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetEnumeratorTest()
|
||||
{
|
||||
|
||||
17
ICD.Common.Utils.Tests/DateTimeUtilsTest.cs
Normal file
17
ICD.Common.Utils.Tests/DateTimeUtilsTest.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace ICD.Common.Utils.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public sealed class DateTimeUtilsTest
|
||||
{
|
||||
[TestCase(1, 1)]
|
||||
[TestCase(0, 12)]
|
||||
[TestCase(12, 12)]
|
||||
[TestCase(23, 11)]
|
||||
public void To12HourTest(int hour, int expected)
|
||||
{
|
||||
Assert.AreEqual(expected, DateTimeUtils.To12Hour(hour));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,16 +3,16 @@
|
||||
namespace ICD.Common.Utils.Tests.Extensions
|
||||
{
|
||||
[TestFixture]
|
||||
public sealed class DateTimeExtensionsTest
|
||||
{
|
||||
[Test]
|
||||
public static void ToShortTimeStringTest()
|
||||
{
|
||||
Assert.Inconclusive();
|
||||
}
|
||||
public sealed class DateTimeExtensionsTest
|
||||
{
|
||||
[Test]
|
||||
public void ToShortTimeStringTest()
|
||||
{
|
||||
Assert.Inconclusive();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public static void ToLongTimeStringWithMillisecondsTest()
|
||||
public void ToLongTimeStringWithMillisecondsTest()
|
||||
{
|
||||
Assert.Inconclusive();
|
||||
}
|
||||
|
||||
@@ -335,9 +335,9 @@ namespace ICD.Common.Utils.Tests.Extensions
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ToDictionaryIntTest()
|
||||
public void ToIndexedDictionaryTest()
|
||||
{
|
||||
Dictionary<int, int> values = new[] {1, 2, 3}.ToDictionary();
|
||||
Dictionary<int, int> values = new[] {1, 2, 3}.ToIndexedDictionary();
|
||||
|
||||
Assert.AreEqual(3, values.Count);
|
||||
Assert.AreEqual(1, values[0]);
|
||||
@@ -346,9 +346,9 @@ namespace ICD.Common.Utils.Tests.Extensions
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ToDictionaryUIntTest()
|
||||
public void ToIndexedDictionaryUIntTest()
|
||||
{
|
||||
Dictionary<uint, int> values = new[] {1, 2, 3}.ToDictionaryUInt();
|
||||
Dictionary<uint, int> values = new[] {1, 2, 3}.ToIndexedDictionaryUInt();
|
||||
|
||||
Assert.AreEqual(3, values.Count);
|
||||
Assert.AreEqual(1, values[0]);
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
using ICD.Common.Utils.IO;
|
||||
using Newtonsoft.Json;
|
||||
using NUnit.Framework;
|
||||
|
||||
@@ -17,6 +18,36 @@ namespace ICD.Common.Utils.Tests.Extensions
|
||||
Assert.Inconclusive();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReadObjectTest()
|
||||
{
|
||||
const string json =
|
||||
"{\"name\":\"Test\",\"help\":\"Test test.\",\"type\":\"System.String, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e\",\"value\":\"Test\"}";
|
||||
|
||||
Dictionary<string, string> expected = new Dictionary<string, string>
|
||||
{
|
||||
{"name", "Test"},
|
||||
{"help", "Test test."},
|
||||
{"type", "System.String, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e"},
|
||||
{"value", "Test"}
|
||||
};
|
||||
|
||||
Dictionary<string, string> deserialized = new Dictionary<string, string>();
|
||||
|
||||
using (IcdStringReader textReader = new IcdStringReader(json))
|
||||
{
|
||||
using (JsonReader reader = new JsonTextReader(textReader.WrappedTextReader))
|
||||
{
|
||||
JsonSerializer serializer = new JsonSerializer();
|
||||
|
||||
reader.Read();
|
||||
reader.ReadObject(serializer, (p, r, s) => deserialized.Add(p, (string)r.Value));
|
||||
}
|
||||
}
|
||||
|
||||
Assert.IsTrue(deserialized.DictionaryEqual(expected));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValueAsIntTest()
|
||||
{
|
||||
@@ -78,53 +109,5 @@ namespace ICD.Common.Utils.Tests.Extensions
|
||||
|
||||
Assert.IsTrue(deserialized.SequenceEqual(new[] {1, 2, 3, 4}));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeDictionaryTest()
|
||||
{
|
||||
Dictionary<int, string> dict = new Dictionary<int, string>
|
||||
{
|
||||
{1, "Item 1"},
|
||||
{10, "Item 2"},
|
||||
{15, "Item 3"}
|
||||
};
|
||||
|
||||
JsonSerializer serializer = new JsonSerializer();
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
using (StringWriter stringWriter = new StringWriter(stringBuilder))
|
||||
{
|
||||
using (JsonWriter writer = new JsonTextWriter(stringWriter))
|
||||
{
|
||||
serializer.SerializeDictionary(writer, dict);
|
||||
}
|
||||
}
|
||||
|
||||
string json = stringBuilder.ToString();
|
||||
Assert.AreEqual("{\"1\":\"Item 1\",\"10\":\"Item 2\",\"15\":\"Item 3\"}", json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeDictionaryTest()
|
||||
{
|
||||
const string json = "{\"1\":\"Item 1\",\"10\":\"Item 2\",\"15\":\"Item 3\"}";
|
||||
|
||||
JsonSerializer serializer = new JsonSerializer();
|
||||
Dictionary<int, string> deserialized;
|
||||
|
||||
using (StringReader stringReader = new StringReader(json))
|
||||
{
|
||||
using (JsonReader reader = new JsonTextReader(stringReader))
|
||||
{
|
||||
reader.Read();
|
||||
deserialized = serializer.DeserializeDictionary<int, string>(reader).ToDictionary();
|
||||
}
|
||||
}
|
||||
|
||||
Assert.AreEqual(3, deserialized.Count);
|
||||
Assert.AreEqual("Item 1", deserialized[1]);
|
||||
Assert.AreEqual("Item 2", deserialized[10]);
|
||||
Assert.AreEqual("Item 3", deserialized[15]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
using NUnit.Framework;
|
||||
|
||||
@@ -43,82 +42,6 @@ namespace ICD.Common.Utils.Tests.Extensions
|
||||
Assert.AreEqual(1, testList[3]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PadRightTest()
|
||||
{
|
||||
List<int> testList = new List<int>();
|
||||
testList.PadRight(10);
|
||||
|
||||
Assert.AreEqual(10, testList.Count);
|
||||
Assert.AreEqual(0, testList.Sum());
|
||||
|
||||
testList = new List<int>
|
||||
{
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
};
|
||||
|
||||
testList.PadRight(10);
|
||||
|
||||
Assert.AreEqual(10, testList.Count);
|
||||
Assert.AreEqual(15, testList.Sum());
|
||||
|
||||
testList = new List<int>
|
||||
{
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
};
|
||||
|
||||
testList.PadRight(1);
|
||||
|
||||
Assert.AreEqual(5, testList.Count);
|
||||
Assert.AreEqual(15, testList.Sum());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PadRightDefaultTest()
|
||||
{
|
||||
List<int> testList = new List<int>();
|
||||
testList.PadRight(10, 1);
|
||||
|
||||
Assert.AreEqual(10, testList.Count);
|
||||
Assert.AreEqual(10, testList.Sum());
|
||||
|
||||
testList = new List<int>
|
||||
{
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
};
|
||||
|
||||
testList.PadRight(10, 1);
|
||||
|
||||
Assert.AreEqual(10, testList.Count);
|
||||
Assert.AreEqual(20, testList.Sum());
|
||||
|
||||
testList = new List<int>
|
||||
{
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
};
|
||||
|
||||
testList.PadRight(1, 1);
|
||||
|
||||
Assert.AreEqual(5, testList.Count);
|
||||
Assert.AreEqual(15, testList.Sum());
|
||||
}
|
||||
|
||||
private sealed class InverseComparer : IComparer<int>
|
||||
{
|
||||
public int Compare(int x, int y)
|
||||
|
||||
@@ -1,73 +1,82 @@
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace ICD.Common.Utils.Tests.Extensions
|
||||
{
|
||||
[TestFixture]
|
||||
public sealed class StringExtensionsTest
|
||||
{
|
||||
[Test]
|
||||
public void IndexOfTest()
|
||||
{
|
||||
string first;
|
||||
Assert.AreEqual(5, "test1test3test2".IndexOf(new[] { "test2", "test3" }, out first));
|
||||
Assert.AreEqual("test3", first);
|
||||
}
|
||||
[TestFixture]
|
||||
public sealed class StringExtensionsTest
|
||||
{
|
||||
[Test]
|
||||
public void IndexOfTest()
|
||||
{
|
||||
string first;
|
||||
Assert.AreEqual(5, "test1test3test2".IndexOf(new[] {"test2", "test3"}, out first));
|
||||
Assert.AreEqual("test3", first);
|
||||
}
|
||||
|
||||
[TestCase(true, "12345", '1')]
|
||||
[TestCase(false, "12345", '2')]
|
||||
public void StartsWithTest(bool expected, string value, char character)
|
||||
{
|
||||
Assert.AreEqual(expected, value.StartsWith(character));
|
||||
}
|
||||
[TestCase(true, "12345", '1')]
|
||||
[TestCase(false, "12345", '2')]
|
||||
public void StartsWithTest(bool expected, string value, char character)
|
||||
{
|
||||
Assert.AreEqual(expected, value.StartsWith(character));
|
||||
}
|
||||
|
||||
[TestCase(true, "12345", '5')]
|
||||
[TestCase(false, "12345", '2')]
|
||||
public void EndsWithTest(bool expected, string value, char character)
|
||||
{
|
||||
Assert.AreEqual(expected, value.EndsWith(character));
|
||||
}
|
||||
[TestCase(true, "12345", '5')]
|
||||
[TestCase(false, "12345", '2')]
|
||||
public void EndsWithTest(bool expected, string value, char character)
|
||||
{
|
||||
Assert.AreEqual(expected, value.EndsWith(character));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SplitCharCountTest()
|
||||
{
|
||||
string[] split = "123-456-789-0".Split('-', 2).ToArray();
|
||||
[Test]
|
||||
public void SplitCharCountTest()
|
||||
{
|
||||
string[] split = "123-456-789-0".Split('-', 2).ToArray();
|
||||
|
||||
Assert.AreEqual(2, split.Length);
|
||||
Assert.AreEqual("123", split[0]);
|
||||
Assert.AreEqual("456-789-0", split[1]);
|
||||
}
|
||||
Assert.AreEqual(2, split.Length);
|
||||
Assert.AreEqual("123", split[0]);
|
||||
Assert.AreEqual("456-789-0", split[1]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SplitChunksizeTest()
|
||||
{
|
||||
string[] split = "1234567890".Split(3).ToArray();
|
||||
[Test]
|
||||
public void SplitChunksizeTest()
|
||||
{
|
||||
string[] split = "1234567890".Split(3).ToArray();
|
||||
|
||||
Assert.AreEqual(4, split.Length);
|
||||
Assert.AreEqual("123", split[0]);
|
||||
Assert.AreEqual("456", split[1]);
|
||||
Assert.AreEqual("789", split[2]);
|
||||
Assert.AreEqual("0", split[3]);
|
||||
}
|
||||
Assert.AreEqual(4, split.Length);
|
||||
Assert.AreEqual("123", split[0]);
|
||||
Assert.AreEqual("456", split[1]);
|
||||
Assert.AreEqual("789", split[2]);
|
||||
Assert.AreEqual("0", split[3]);
|
||||
}
|
||||
|
||||
[TestCase("12345", " 12 3 4 \t 5\n")]
|
||||
public void RemoveWhitespaceTest(string expected, string value)
|
||||
{
|
||||
Assert.AreEqual(expected, value.RemoveWhitespace());
|
||||
}
|
||||
[TestCase("12345", " 12 3 4 \t 5\n")]
|
||||
public void RemoveWhitespaceTest(string expected, string value)
|
||||
{
|
||||
Assert.AreEqual(expected, value.RemoveWhitespace());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RemoveCharactersTest()
|
||||
{
|
||||
Assert.AreEqual("13457890", "1234567890".Remove(new[] { '2', '6' }));
|
||||
}
|
||||
[TestCase("1234567890", "12345", "67890")]
|
||||
[TestCase("foobarfoobar", "bar", "foofoo")]
|
||||
public void RemoveStringTest(string value, string other, string expected)
|
||||
{
|
||||
Assert.AreEqual(expected, value.Remove(other));
|
||||
}
|
||||
|
||||
[TestCase(true, "27652")]
|
||||
[TestCase(false, "a27652")]
|
||||
public void IsNumericTest(bool expected, string value)
|
||||
{
|
||||
Assert.AreEqual(expected, value.IsNumeric());
|
||||
}
|
||||
}
|
||||
[TestCase("1234567890", new[] {'2', '6'}, "13457890")]
|
||||
[TestCase("912529434324", new[] {'-', '(', ')', '.', '+'}, "912529434324")]
|
||||
public void RemoveCharactersTest(string value, IEnumerable<char> characters, string expected)
|
||||
{
|
||||
Assert.AreEqual(expected, value.Remove(characters));
|
||||
}
|
||||
|
||||
[TestCase(true, "27652")]
|
||||
[TestCase(false, "a27652")]
|
||||
public void IsNumericTest(bool expected, string value)
|
||||
{
|
||||
Assert.AreEqual(expected, value.IsNumeric());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
43
ICD.Common.Utils.Tests/Extensions/TimeSpanExtensionsTest.cs
Normal file
43
ICD.Common.Utils.Tests/Extensions/TimeSpanExtensionsTest.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace ICD.Common.Utils.Tests.Extensions
|
||||
{
|
||||
[TestFixture]
|
||||
public sealed class TimeSpanExtensionsTest
|
||||
{
|
||||
[Test]
|
||||
public void ToReadableStringTest()
|
||||
{
|
||||
Assert.Inconclusive();
|
||||
}
|
||||
|
||||
[TestCase(0, 0, 0)]
|
||||
[TestCase(12, 1, 13)]
|
||||
[TestCase(23, 1, 0)]
|
||||
[TestCase(6, -12, 18)]
|
||||
public void AddHoursAndWrapTest(int hours, int addHours, int expectedHours)
|
||||
{
|
||||
Assert.AreEqual(expectedHours, new TimeSpan(hours, 0, 0).AddHoursAndWrap(addHours).Hours);
|
||||
}
|
||||
|
||||
[TestCase(0, 0, 0)]
|
||||
[TestCase(12, 1, 13)]
|
||||
[TestCase(23, 1, 12)]
|
||||
[TestCase(6, -12, 6)]
|
||||
public void AddHoursAndWrap12Hour(int hours, int addHours, int expectedHours)
|
||||
{
|
||||
Assert.AreEqual(expectedHours, new TimeSpan(hours, 0, 0).AddHoursAndWrap12Hour(addHours).Hours);
|
||||
}
|
||||
|
||||
[TestCase(0, 0, 0)]
|
||||
[TestCase(30, 1, 31)]
|
||||
[TestCase(59, 1, 0)]
|
||||
[TestCase(30, -60, 30)]
|
||||
public void AddMinutesAndWrap(int minutes, int addMinutes, int expectedMinutes)
|
||||
{
|
||||
Assert.AreEqual(expectedMinutes, new TimeSpan(0, minutes, 0).AddMinutesAndWrap(addMinutes).Minutes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -155,6 +155,22 @@ namespace ICD.Common.Utils.Tests.Extensions
|
||||
Assert.AreEqual(expected, type.GetNameWithoutGenericArity());
|
||||
}
|
||||
|
||||
[TestCase(typeof(int), "System.Int32")]
|
||||
[TestCase(typeof(int?), "System.Nullable`1[[System.Int32]]")]
|
||||
[TestCase(typeof(KeyValuePair<int, string>), "System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]")]
|
||||
[TestCase(typeof(List<>), "System.Collections.Generic.List`1")]
|
||||
public void GetMinimalNameTest(Type type, string expected)
|
||||
{
|
||||
Assert.AreEqual(expected, type.GetMinimalName());
|
||||
}
|
||||
|
||||
[TestCase(typeof(int), "System.Int32, System.Private.CoreLib")]
|
||||
[TestCase(typeof(int?), "System.Nullable`1[[System.Int32, System.Private.CoreLib]], System.Private.CoreLib")]
|
||||
public void GetNameWithoutAssemblyDetailsTest(Type type, string expected)
|
||||
{
|
||||
Assert.AreEqual(expected, type.GetNameWithoutAssemblyDetails());
|
||||
}
|
||||
|
||||
[TestCase(typeof(string), "string")]
|
||||
[TestCase(typeof(int?), "int?")]
|
||||
[TestCase(typeof(List<int?>), "List<int?>")]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ICD.Common.Utils.Xml;
|
||||
using NUnit.Framework;
|
||||
@@ -49,10 +50,10 @@ namespace ICD.Common.Utils.Tests.Extensions
|
||||
|
||||
reader.ReadToNextElement();
|
||||
|
||||
IcdXmlAttribute[] attributes = reader.GetAttributes().ToArray();
|
||||
KeyValuePair<string, string>[] attributes = reader.GetAttributes().ToArray();
|
||||
Assert.AreEqual(2, attributes.Length);
|
||||
Assert.AreEqual("attr1", attributes[0].Name);
|
||||
Assert.AreEqual("attr2", attributes[1].Name);
|
||||
Assert.AreEqual("attr1", attributes[0].Key);
|
||||
Assert.AreEqual("attr2", attributes[1].Key);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
@@ -19,9 +20,9 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
|
||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -37,10 +37,11 @@ namespace ICD.Common.Utils.Tests
|
||||
Assert.AreEqual(port, new IcdUriBuilder {Port = port}.Port);
|
||||
}
|
||||
|
||||
[TestCase("test")]
|
||||
public void QueryTest(string query)
|
||||
[TestCase("?test", "test")]
|
||||
[TestCase("??test", "?test")]
|
||||
public void QueryTest(string expected, string query)
|
||||
{
|
||||
Assert.AreEqual(query, new IcdUriBuilder {Query = query}.Query);
|
||||
Assert.AreEqual(expected, new IcdUriBuilder {Query = query}.Query);
|
||||
}
|
||||
|
||||
[TestCase("test")]
|
||||
@@ -63,14 +64,17 @@ namespace ICD.Common.Utils.Tests
|
||||
|
||||
#endregion
|
||||
|
||||
[TestCase("http://localhost/", null, null, null, null, (ushort)0, null, null, null)]
|
||||
[TestCase("http://localhost:80/", null, null, null, null, (ushort)80, null, null, null)]
|
||||
[TestCase("http://username@localhost/", null, null, null, null, (ushort)0, null, null, "username")]
|
||||
[TestCase("http://localhost/", null, null, "password", null, (ushort)0, null, null, null)]
|
||||
[TestCase("https://localhost/", null, null, null, null, (ushort)0, null, "https", null)]
|
||||
[TestCase("http://localhost/test", null, null, null, "test", (ushort)0, null, null, null)]
|
||||
[TestCase("http://localhost/test", null, null, null, "/test", (ushort)0, null, null, null)]
|
||||
[TestCase("http://localhost//test", null, null, null, "//test", (ushort)0, null, null, null)]
|
||||
[TestCase("/", null, null, null, null, (ushort)0, null, null, null)]
|
||||
[TestCase("http:///", null, null, null, null, (ushort)0, null, "http", null)]
|
||||
[TestCase("http://localhost:80/", null, "localhost", null, null, (ushort)80, null, "http", null)]
|
||||
[TestCase("http://username@localhost/", null, "localhost", null, null, (ushort)0, null, "http", "username")]
|
||||
[TestCase("http://localhost/", null, "localhost", "password", null, (ushort)0, null, "http", null)]
|
||||
[TestCase("https://localhost/", null, "localhost", null, null, (ushort)0, null, "https", null)]
|
||||
[TestCase("http://localhost/test", null, "localhost", null, "test", (ushort)0, null, "http", null)]
|
||||
[TestCase("http://localhost/test", null, "localhost", null, "/test", (ushort)0, null, "http", null)]
|
||||
[TestCase("http://localhost//test", null, "localhost", null, "//test", (ushort)0, null, "http", null)]
|
||||
[TestCase("http://localhost/test?a=b", null, "localhost", null, "/test", (ushort)0, "a=b", "http", null)]
|
||||
[TestCase("http://localhost/test??a=b", null, "localhost", null, "/test", (ushort)0, "?a=b", "http", null)]
|
||||
public void ToStringTest(string expected, string fragment, string address, string password, string path, ushort port,
|
||||
string query, string scheme, string userName)
|
||||
{
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using ICD.Common.Utils.IO;
|
||||
using ICD.Common.Utils.Json;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace ICD.Common.Utils.Tests.Json
|
||||
@@ -11,25 +10,7 @@ namespace ICD.Common.Utils.Tests.Json
|
||||
public sealed class JsonUtilsTest
|
||||
{
|
||||
[Test]
|
||||
public void CacheTypeTest()
|
||||
{
|
||||
Assert.Inconclusive();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParseDateTimeTest()
|
||||
{
|
||||
Assert.Inconclusive();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryParseDateTimeTest()
|
||||
{
|
||||
Assert.Inconclusive();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PrintTest()
|
||||
public void FormatTest()
|
||||
{
|
||||
Assert.Inconclusive();
|
||||
}
|
||||
@@ -141,32 +122,6 @@ namespace ICD.Common.Utils.Tests.Json
|
||||
Assert.AreEqual("test message", messageName);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeTypeTest()
|
||||
{
|
||||
const string json = "{\"test\":10}";
|
||||
|
||||
JObject root = JObject.Parse(json);
|
||||
JToken token = root["test"];
|
||||
|
||||
int value = (int)JsonUtils.Deserialize(typeof(int), token);
|
||||
|
||||
Assert.AreEqual(10, value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeTestSerializerTest()
|
||||
{
|
||||
const string json = "{\"test\":10}";
|
||||
|
||||
JObject root = JObject.Parse(json);
|
||||
JToken token = root["test"];
|
||||
|
||||
int value = (int)JsonUtils.Deserialize(typeof(int), token, new JsonSerializer());
|
||||
|
||||
Assert.AreEqual(10, value);
|
||||
}
|
||||
|
||||
public sealed class TestSerializable
|
||||
{
|
||||
private const string PROPERTY_NAME = "Test";
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ICD.Common.Properties;
|
||||
|
||||
namespace ICD.Common.Utils.Tests
|
||||
{
|
||||
[TestFixture, UsedImplicitly]
|
||||
[TestFixture]
|
||||
public sealed class MathUtilsTest
|
||||
{
|
||||
[Test, UsedImplicitly]
|
||||
[Test]
|
||||
public void ClampTest()
|
||||
{
|
||||
Assert.AreEqual(MathUtils.Clamp(-10, 0, 0), 0);
|
||||
@@ -24,9 +23,13 @@ namespace ICD.Common.Utils.Tests
|
||||
Assert.AreEqual(MathUtils.Clamp(20, 10, 10), 10);
|
||||
}
|
||||
|
||||
[Test, UsedImplicitly]
|
||||
[Test]
|
||||
public void MapRangeTest()
|
||||
{
|
||||
Assert.AreEqual(5, MathUtils.MapRange(-100, 100, 0, 10, 0));
|
||||
Assert.AreEqual(7, MathUtils.MapRange(-100, 100, 0, 10, 50));
|
||||
Assert.AreEqual(10, MathUtils.MapRange(-100, 100, 0, 10, 100));
|
||||
|
||||
Assert.AreEqual(0, MathUtils.MapRange(0, 100, 0, 10, 0));
|
||||
Assert.AreEqual(5, MathUtils.MapRange(0, 100, 0, 10, 50));
|
||||
Assert.AreEqual(10, MathUtils.MapRange(0, 100, 0, 10, 100));
|
||||
@@ -36,7 +39,7 @@ namespace ICD.Common.Utils.Tests
|
||||
Assert.AreEqual(100, MathUtils.MapRange(0, 10, 0, 100, 10));
|
||||
}
|
||||
|
||||
[Test, UsedImplicitly]
|
||||
[Test]
|
||||
public void GetRangesTest()
|
||||
{
|
||||
IEnumerable<int> values = new [] { 1, 3, 5, 6, 7, 8, 9, 10, 12 };
|
||||
@@ -57,11 +60,21 @@ namespace ICD.Common.Utils.Tests
|
||||
Assert.AreEqual(12, ranges[3][1]);
|
||||
}
|
||||
|
||||
[Test, UsedImplicitly]
|
||||
[Test]
|
||||
public void RoundToNearestTest()
|
||||
{
|
||||
IEnumerable<int> values = new [] { 0, 15, 30, 45 };
|
||||
Assert.AreEqual(15, MathUtils.RoundToNearest(21, values));
|
||||
}
|
||||
|
||||
[TestCase(10, 10, 0)]
|
||||
[TestCase(-10, 10, 0)]
|
||||
[TestCase(9, 3, 0)]
|
||||
[TestCase(3, 2, 1)]
|
||||
[TestCase(-3, 2, 1)]
|
||||
public void ModulusTest(int value, int mod, int expected)
|
||||
{
|
||||
Assert.AreEqual(expected, MathUtils.Modulus(value, mod));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,6 +127,24 @@ namespace ICD.Common.Utils.Tests
|
||||
Assert.IsTrue(clique.Contains(6));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetCliqueSingleNodeTest()
|
||||
{
|
||||
int[] clique = RecursionUtils.GetClique(1, n => s_CliqueGraph[n]).ToArray();
|
||||
|
||||
Assert.AreEqual(4, clique.Length);
|
||||
Assert.IsTrue(clique.Contains(1));
|
||||
Assert.IsTrue(clique.Contains(2));
|
||||
Assert.IsTrue(clique.Contains(3));
|
||||
Assert.IsTrue(clique.Contains(4));
|
||||
|
||||
clique = RecursionUtils.GetClique(5, n => s_CliqueGraph[n]).ToArray();
|
||||
|
||||
Assert.AreEqual(2, clique.Length);
|
||||
Assert.IsTrue(clique.Contains(5));
|
||||
Assert.IsTrue(clique.Contains(6));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BreadthFirstSearchTest()
|
||||
{
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.EventArguments;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
#if SIMPLSHARP
|
||||
using Crestron.SimplSharp.Reflection;
|
||||
#else
|
||||
@@ -149,5 +151,75 @@ namespace ICD.Common.Utils.Tests
|
||||
// Everything else
|
||||
Assert.AreEqual(10, ReflectionUtils.ChangeType("10", typeof(int)));
|
||||
}
|
||||
|
||||
#region Subscription Tests
|
||||
|
||||
[Test]
|
||||
public void SubscribeEventTest()
|
||||
{
|
||||
EventInfo eventInfo = GetType().GetEvent("OnIncrementCount", BindingFlags.Instance | BindingFlags.Public);
|
||||
|
||||
Delegate del = ReflectionUtils.SubscribeEvent<IntEventArgs>(this, eventInfo, IncrementCount);
|
||||
|
||||
Assert.NotNull(del);
|
||||
|
||||
m_Count = 0;
|
||||
OnIncrementCount.Raise(this, new IntEventArgs(10));
|
||||
|
||||
Assert.AreEqual(10, m_Count);
|
||||
|
||||
OnIncrementCount = null;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SubscribeEventMethodInfoTest()
|
||||
{
|
||||
EventInfo eventInfo = GetType().GetEvent("OnIncrementCount", BindingFlags.Instance | BindingFlags.Public);
|
||||
MethodInfo methodInfo =
|
||||
GetType().GetMethod("IncrementCount", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
Delegate del = ReflectionUtils.SubscribeEvent(this, eventInfo, this, methodInfo);
|
||||
|
||||
Assert.NotNull(del);
|
||||
|
||||
m_Count = 0;
|
||||
OnIncrementCount.Raise(this, new IntEventArgs(10));
|
||||
|
||||
Assert.AreEqual(10, m_Count);
|
||||
|
||||
OnIncrementCount = null;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UnsubscribeEventTest()
|
||||
{
|
||||
EventInfo eventInfo = GetType().GetEvent("OnIncrementCount", BindingFlags.Instance | BindingFlags.Public);
|
||||
MethodInfo methodInfo =
|
||||
GetType().GetMethod("IncrementCount", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
Delegate del = ReflectionUtils.SubscribeEvent(this, eventInfo, this, methodInfo);
|
||||
|
||||
Assert.NotNull(del);
|
||||
|
||||
m_Count = 0;
|
||||
|
||||
ReflectionUtils.UnsubscribeEvent(this, eventInfo, del);
|
||||
|
||||
OnIncrementCount.Raise(this, new IntEventArgs(10));
|
||||
|
||||
Assert.AreEqual(0, m_Count);
|
||||
}
|
||||
|
||||
// Event has to be public
|
||||
public event EventHandler<IntEventArgs> OnIncrementCount;
|
||||
|
||||
private int m_Count;
|
||||
|
||||
private void IncrementCount(object sender, IntEventArgs args)
|
||||
{
|
||||
m_Count += args.Data;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
38
ICD.Common.Utils.Tests/RegexUtilsTest.cs
Normal file
38
ICD.Common.Utils.Tests/RegexUtilsTest.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace ICD.Common.Utils.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public sealed class RegexUtilsTest
|
||||
{
|
||||
[Test]
|
||||
public static void MatchesTest()
|
||||
{
|
||||
Assert.Inconclusive();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public static void MatchesOptionsTest()
|
||||
{
|
||||
Assert.Inconclusive();
|
||||
}
|
||||
|
||||
[TestCase(@"[assembly: AssemblyFileVersion(""1.2.3"")][assembly: AssemblyFileVersion(""1.2.3"")]",
|
||||
@"[assembly: AssemblyFileVersion(""2.0.3.0"")][assembly: AssemblyFileVersion(""2.0.3.0"")]",
|
||||
@"AssemblyFileVersion\(""(?<version>(\d+\.?){4})""\)",
|
||||
"version",
|
||||
"1.2.3")]
|
||||
public static void ReplaceGroupTest(string expected, string input, string pattern, string groupName,
|
||||
string replacement)
|
||||
{
|
||||
string result = RegexUtils.ReplaceGroup(input, pattern, groupName, replacement);
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public static void ReplaceGroupFuncTest()
|
||||
{
|
||||
Assert.Inconclusive();
|
||||
}
|
||||
}
|
||||
}
|
||||
17
ICD.Common.Utils.Tests/Timers/IcdStopwatchTest.cs
Normal file
17
ICD.Common.Utils.Tests/Timers/IcdStopwatchTest.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using ICD.Common.Utils.Timers;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace ICD.Common.Utils.Tests.Timers
|
||||
{
|
||||
[TestFixture]
|
||||
public sealed class IcdStopwatchTest
|
||||
{
|
||||
[Test]
|
||||
public void ConstructorTest()
|
||||
{
|
||||
var stopwatch = new IcdStopwatch();
|
||||
ThreadingUtils.Sleep(100);
|
||||
Assert.AreEqual(0, stopwatch.ElapsedMilliseconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.Xml;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace ICD.Common.Utils.Tests.Xml
|
||||
{
|
||||
[TestFixture]
|
||||
public sealed class IcdXmlAttributeTest
|
||||
{
|
||||
[Test, UsedImplicitly]
|
||||
public void ValueAsIntTest()
|
||||
{
|
||||
IcdXmlAttribute attribute = new IcdXmlAttribute("test", "12");
|
||||
Assert.AreEqual("12", attribute.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
35
ICD.Common.Utils.Tests/Xml/IcdXmlConvertTest.cs
Normal file
35
ICD.Common.Utils.Tests/Xml/IcdXmlConvertTest.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System.Linq;
|
||||
using ICD.Common.Utils.Xml;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace ICD.Common.Utils.Tests.Xml
|
||||
{
|
||||
[TestFixture]
|
||||
public sealed class IcdXmlConvertTest
|
||||
{
|
||||
[Test]
|
||||
public void DeserializeArrayGenericTest()
|
||||
{
|
||||
const string xml = @"<A>
|
||||
<B>1</B>
|
||||
<B>2</B>
|
||||
</A>";
|
||||
|
||||
using (IcdXmlReader reader = new IcdXmlReader(xml))
|
||||
{
|
||||
// Read to the first element
|
||||
reader.Read();
|
||||
|
||||
int[] values = IcdXmlConvert.DeserializeArray<int>(reader).ToArray();
|
||||
|
||||
Assert.AreEqual(new[] {1, 2}, values);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializeArrayTest()
|
||||
{
|
||||
Assert.Inconclusive();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,12 +56,12 @@ namespace ICD.Common.Utils.Tests.Xml
|
||||
{
|
||||
reader.ReadToNextElement();
|
||||
|
||||
IcdXmlAttribute[] attributes = reader.GetAttributes().ToArray();
|
||||
KeyValuePair<string, string>[] attributes = reader.GetAttributes().ToArray();
|
||||
|
||||
Assert.AreEqual(2, attributes.Length);
|
||||
Assert.AreEqual("attr1", attributes[0].Name);
|
||||
Assert.AreEqual("attr1", attributes[0].Key);
|
||||
Assert.AreEqual("1", attributes[0].Value);
|
||||
Assert.AreEqual("attr2", attributes[1].Name);
|
||||
Assert.AreEqual("attr2", attributes[1].Key);
|
||||
Assert.AreEqual("2", attributes[1].Value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.Collections;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
using ICD.Common.Utils.Services;
|
||||
using ICD.Common.Utils.Services.Logging;
|
||||
#if SIMPLSHARP
|
||||
using Crestron.SimplSharp.Reflection;
|
||||
#else
|
||||
@@ -20,175 +17,6 @@ namespace ICD.Common.Utils
|
||||
/// </summary>
|
||||
public static class AttributeUtils
|
||||
{
|
||||
// Avoid caching the same assembly multiple times.
|
||||
private static readonly IcdHashSet<Assembly> s_CachedAssemblies;
|
||||
private static readonly IcdHashSet<Type> s_CachedTypes;
|
||||
|
||||
private static readonly Dictionary<Attribute, MethodInfo> s_AttributeToMethodCache;
|
||||
private static readonly Dictionary<Attribute, Type> s_AttributeToTypeCache;
|
||||
private static readonly Dictionary<Type, IcdHashSet<Attribute>> s_TypeToAttributesCache;
|
||||
|
||||
private static ILoggerService Logger { get { return ServiceProvider.TryGetService<ILoggerService>(); } }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
static AttributeUtils()
|
||||
{
|
||||
s_CachedAssemblies = new IcdHashSet<Assembly>();
|
||||
s_CachedTypes = new IcdHashSet<Type>();
|
||||
|
||||
s_AttributeToMethodCache = new Dictionary<Attribute, MethodInfo>();
|
||||
s_AttributeToTypeCache = new Dictionary<Attribute, Type>();
|
||||
s_TypeToAttributesCache = new Dictionary<Type, IcdHashSet<Attribute>>();
|
||||
}
|
||||
|
||||
#region Caching
|
||||
|
||||
/// <summary>
|
||||
/// Pre-emptively caches the given assemblies for lookup.
|
||||
/// </summary>
|
||||
/// <param name="assemblies"></param>
|
||||
public static void CacheAssemblies(IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
if (assemblies == null)
|
||||
throw new ArgumentNullException("assemblies");
|
||||
|
||||
foreach (Assembly assembly in assemblies)
|
||||
CacheAssembly(assembly);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pre-emptively caches the given assembly for lookup.
|
||||
/// </summary>
|
||||
/// <param name="assembly"></param>
|
||||
public static bool CacheAssembly(Assembly assembly)
|
||||
{
|
||||
if (assembly == null)
|
||||
throw new ArgumentNullException("assembly");
|
||||
|
||||
if (s_CachedAssemblies.Contains(assembly))
|
||||
return true;
|
||||
|
||||
#if SIMPLSHARP
|
||||
CType[] types;
|
||||
#else
|
||||
Type[] types;
|
||||
#endif
|
||||
try
|
||||
{
|
||||
types = assembly.GetTypes();
|
||||
}
|
||||
#if STANDARD
|
||||
catch (ReflectionTypeLoadException e)
|
||||
{
|
||||
foreach (Exception inner in e.LoaderExceptions)
|
||||
{
|
||||
if (inner is System.IO.FileNotFoundException)
|
||||
{
|
||||
Logger.AddEntry(eSeverity.Error,
|
||||
"{0} failed to cache assembly {1} - Could not find one or more dependencies by path",
|
||||
typeof(AttributeUtils).Name, assembly.GetName().Name);
|
||||
continue;
|
||||
}
|
||||
|
||||
Logger.AddEntry(eSeverity.Error, inner, "{0} failed to cache assembly {1}", typeof(AttributeUtils).Name,
|
||||
assembly.GetName().Name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
catch (TypeLoadException e)
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
Logger.AddEntry(eSeverity.Error, e, "{0} failed to cache assembly {1}", typeof(AttributeUtils).Name,
|
||||
assembly.GetName().Name);
|
||||
#else
|
||||
Logger.AddEntry(eSeverity.Error, e, "{0} failed to cache assembly {1} - could not load type {2}",
|
||||
typeof(AttributeUtils).Name, assembly.GetName().Name, e.TypeName);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var type in types)
|
||||
CacheType(type);
|
||||
|
||||
s_CachedAssemblies.Add(assembly);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pre-emptively caches the given type for lookup.
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
#if SIMPLSHARP
|
||||
public static void CacheType(CType type)
|
||||
#else
|
||||
public static void CacheType(Type type)
|
||||
#endif
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
if (s_CachedTypes.Contains(type))
|
||||
return;
|
||||
s_CachedTypes.Add(type);
|
||||
|
||||
MethodInfo[] methods;
|
||||
|
||||
try
|
||||
{
|
||||
s_TypeToAttributesCache[type] = new IcdHashSet<Attribute>(type.GetCustomAttributes<Attribute>(false));
|
||||
foreach (Attribute attribute in s_TypeToAttributesCache[type])
|
||||
s_AttributeToTypeCache[attribute] = type;
|
||||
|
||||
methods = type.GetMethods();
|
||||
}
|
||||
// GetMethods for Open Generic Types is not supported.
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Not sure why this happens :/
|
||||
catch (InvalidProgramException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (MethodInfo method in methods)
|
||||
CacheMethod(method);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Caches the method.
|
||||
/// </summary>
|
||||
/// <param name="method"></param>
|
||||
private static void CacheMethod(MethodInfo method)
|
||||
{
|
||||
if (method == null)
|
||||
throw new ArgumentNullException("method");
|
||||
|
||||
foreach (Attribute attribute in ReflectionExtensions.GetCustomAttributes<Attribute>(method, false))
|
||||
s_AttributeToMethodCache[attribute] = method;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Lookup
|
||||
|
||||
/// <summary>
|
||||
/// Gets the class attributes of the given generic type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<T> GetClassAttributes<T>()
|
||||
where T : Attribute
|
||||
{
|
||||
return s_AttributeToTypeCache.Select(kvp => kvp.Key)
|
||||
.OfType<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the first attribute on the given class type matching the generic type.
|
||||
/// </summary>
|
||||
@@ -197,12 +25,24 @@ namespace ICD.Common.Utils
|
||||
/// <returns></returns>
|
||||
[CanBeNull]
|
||||
public static T GetClassAttribute<T>(Type type)
|
||||
where T : Attribute
|
||||
{
|
||||
return GetClassAttribute<T>(type, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the first attribute on the given class type matching the generic type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="inherit"></param>
|
||||
/// <returns></returns>
|
||||
[CanBeNull]
|
||||
public static T GetClassAttribute<T>(Type type, bool inherit)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
return GetClassAttributes<T>(type).FirstOrDefault();
|
||||
return GetClassAttributes<T>(type, inherit).FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -212,72 +52,56 @@ namespace ICD.Common.Utils
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<T> GetClassAttributes<T>(Type type)
|
||||
where T : Attribute
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
return GetClassAttributes(type).OfType<T>();
|
||||
return GetClassAttributes<T>(type, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the attributes on the given class.
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Attribute> GetClassAttributes(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
CacheType(type);
|
||||
|
||||
IcdHashSet<Attribute> attributes;
|
||||
|
||||
return s_TypeToAttributesCache.TryGetValue(type, out attributes)
|
||||
? attributes.ToArray(attributes.Count)
|
||||
: Enumerable.Empty<Attribute>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type with the given attribute.
|
||||
/// </summary>
|
||||
/// <param name="attribute"></param>
|
||||
/// <returns></returns>
|
||||
public static Type GetClass(Attribute attribute)
|
||||
{
|
||||
if (attribute == null)
|
||||
throw new ArgumentNullException("attribute");
|
||||
|
||||
return s_AttributeToTypeCache[attribute];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all of the cached method attributes of the given type.
|
||||
/// Gets the attributes on the given class type matching the generic type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="inherit"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<T> GetMethodAttributes<T>()
|
||||
where T : Attribute
|
||||
public static IEnumerable<T> GetClassAttributes<T>(Type type, bool inherit)
|
||||
{
|
||||
return s_AttributeToMethodCache.Select(p => p.Key)
|
||||
.OfType<T>()
|
||||
.ToArray();
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
// ReSharper disable InvokeAsExtensionMethod
|
||||
return ReflectionExtensions.GetCustomAttributes<T>(
|
||||
#if SIMPLSHARP
|
||||
(CType)
|
||||
#endif
|
||||
type, inherit);
|
||||
// ReSharper restore InvokeAsExtensionMethod
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the cached method for the given attribute.
|
||||
/// Returns the properties on the given instance with property attributes of the given type.
|
||||
/// </summary>
|
||||
/// <param name="attribute"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="instance"></param>
|
||||
/// <param name="inherit"></param>
|
||||
/// <returns></returns>
|
||||
public static MethodInfo GetMethod(Attribute attribute)
|
||||
public static IEnumerable<PropertyInfo> GetProperties<T>(object instance, bool inherit)
|
||||
{
|
||||
if (attribute == null)
|
||||
throw new ArgumentNullException("attribute");
|
||||
if (instance == null)
|
||||
throw new ArgumentNullException("instance");
|
||||
|
||||
return s_AttributeToMethodCache[attribute];
|
||||
return instance.GetType()
|
||||
#if SIMPLSHARP
|
||||
.GetCType()
|
||||
#else
|
||||
.GetTypeInfo()
|
||||
#endif
|
||||
.GetProperties()
|
||||
// ReSharper disable InvokeAsExtensionMethod
|
||||
.Where(p => ReflectionExtensions.GetCustomAttributes<T>(p, inherit).Any());
|
||||
// ReSharper restore InvokeAsExtensionMethod
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace ICD.Common.Utils.Attributes
|
||||
/// <summary>
|
||||
/// AbstractIcdAttribute is the base class for all ICD attributes.
|
||||
/// </summary>
|
||||
public abstract class AbstractIcdAttribute : Attribute
|
||||
public abstract class AbstractIcdAttribute : Attribute, IIcdAttribute
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
6
ICD.Common.Utils/Attributes/IIcdAttribute.cs
Normal file
6
ICD.Common.Utils/Attributes/IIcdAttribute.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace ICD.Common.Utils.Attributes
|
||||
{
|
||||
public interface IIcdAttribute
|
||||
{
|
||||
}
|
||||
}
|
||||
520
ICD.Common.Utils/Attributes/RangeAttribute.cs
Normal file
520
ICD.Common.Utils/Attributes/RangeAttribute.cs
Normal file
@@ -0,0 +1,520 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
|
||||
namespace ICD.Common.Utils.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the valid ranges for a given value if that range is not equal to the range of the data type.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property |
|
||||
AttributeTargets.Field |
|
||||
AttributeTargets.Parameter |
|
||||
AttributeTargets.ReturnValue)]
|
||||
public sealed class RangeAttribute : AbstractIcdAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Remaps from the source numeric min/max to double min/max.
|
||||
/// </summary>
|
||||
private static readonly Dictionary<Type, Func<double, double>> s_Clamp =
|
||||
new Dictionary<Type, Func<double, double>>
|
||||
{
|
||||
// Duh
|
||||
{typeof(double), o => o},
|
||||
|
||||
// Signed
|
||||
{typeof(short), o => o < short.MinValue ? short.MinValue : o > short.MaxValue ? short.MaxValue : o},
|
||||
{typeof(int), o => o < int.MinValue ? int.MinValue : o > int.MaxValue ? int.MaxValue : o},
|
||||
{typeof(long), o => o < long.MinValue ? long.MinValue : o > long.MaxValue ? long.MaxValue : o},
|
||||
{typeof(float),o => o < float.MinValue ? float.MinValue : o > float.MaxValue ? float.MaxValue : o},
|
||||
{typeof(decimal), o => o < (double)decimal.MinValue ? (double)decimal.MinValue : o > (double)decimal.MaxValue ? (double)decimal.MaxValue : o},
|
||||
|
||||
// Unsigned
|
||||
{typeof(ushort), o => o < ushort.MinValue ? ushort.MinValue : o > ushort.MaxValue ? ushort.MaxValue : o},
|
||||
{typeof(uint), o => o < uint.MinValue ? uint.MinValue : o > uint.MaxValue ? uint.MaxValue : o},
|
||||
{typeof(ulong), o => o < ulong.MinValue ? ulong.MinValue : o > ulong.MaxValue ? ulong.MaxValue : o},
|
||||
{typeof(byte), o => o < byte.MinValue ? byte.MinValue : o > byte.MaxValue ? byte.MaxValue : o}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Remaps from the source numeric min/max to double min/max.
|
||||
/// </summary>
|
||||
private static readonly Dictionary<Type, Func<object, double>> s_RemapToDouble =
|
||||
new Dictionary<Type, Func<object, double>>
|
||||
{
|
||||
// Duh
|
||||
{ typeof(double), o => (double)o},
|
||||
|
||||
// Signed - Clamping prevents an overflow due to loss of precision
|
||||
{ typeof(short), o => MathUtils.Clamp(Convert.ToDouble(o) / short.MaxValue, -1, 1) * double.MaxValue},
|
||||
{ typeof(int), o => MathUtils.Clamp(Convert.ToDouble(o) / int.MaxValue, -1, 1) * double.MaxValue},
|
||||
{ typeof(long), o => MathUtils.Clamp(Convert.ToDouble(o) / long.MaxValue, -1, 1) * double.MaxValue},
|
||||
{ typeof(float), o => MathUtils.Clamp(Convert.ToDouble(o) / float.MaxValue, -1, 1) * double.MaxValue},
|
||||
{ typeof(decimal), o => MathUtils.Clamp(Convert.ToDouble(o) / (double)decimal.MaxValue, -1, 1) * double.MaxValue},
|
||||
|
||||
// Unsigned
|
||||
{ typeof(ushort), o => MathUtils.Clamp((Convert.ToDouble(o) / ushort.MaxValue - 0.5) * 2, -1, 1) * double.MaxValue},
|
||||
{ typeof(uint), o => MathUtils.Clamp((Convert.ToDouble(o) / uint.MaxValue - 0.5) * 2, -1, 1) * double.MaxValue},
|
||||
{ typeof(ulong), o => MathUtils.Clamp((Convert.ToDouble(o) / ulong.MaxValue - 0.5) * 2, -1, 1) * double.MaxValue},
|
||||
{ typeof(byte), o => MathUtils.Clamp((Convert.ToDouble(o) / byte.MaxValue - 0.5) * 2, -1, 1) * double.MaxValue}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Remaps from the double min/max to target numeric min/max.
|
||||
/// </summary>
|
||||
private static readonly Dictionary<Type, Func<double, object>> s_RemapFromDouble =
|
||||
new Dictionary<Type, Func<double, object>>
|
||||
{
|
||||
// Duh
|
||||
{typeof(double), v => v},
|
||||
|
||||
// Signed
|
||||
{typeof(short), v => (short)(v / double.MaxValue * short.MaxValue)},
|
||||
{typeof(int), v => (int)(v / double.MaxValue * int.MaxValue)},
|
||||
{typeof(long), v => (long)(v / double.MaxValue * long.MaxValue)},
|
||||
{typeof(float), v => (float)(v / double.MaxValue * float.MaxValue)},
|
||||
{typeof(decimal), v => (decimal)(v / double.MaxValue) * decimal.MaxValue},
|
||||
|
||||
// Unsigned
|
||||
{typeof(ushort), v => (ushort)((v / double.MaxValue + 1) / 2 * ushort.MaxValue)},
|
||||
{typeof(uint), v => (uint)((v / double.MaxValue + 1) / 2 * uint.MaxValue)},
|
||||
{typeof(ulong), v => (ulong)((v / double.MaxValue + 1) / 2 * ulong.MaxValue)},
|
||||
{typeof(byte), v => (byte)((v / double.MaxValue + 1) / 2 * byte.MaxValue)}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the min value of a given numeric type as a double.
|
||||
/// </summary>
|
||||
private static readonly Dictionary<Type, double> s_MinAsDouble =
|
||||
new Dictionary<Type, double>
|
||||
{
|
||||
// Duh
|
||||
{typeof(double), double.MinValue},
|
||||
|
||||
// Signed
|
||||
{typeof(short), Convert.ToDouble(short.MinValue)},
|
||||
{typeof(int), Convert.ToDouble(int.MinValue)},
|
||||
{typeof(long), Convert.ToDouble(long.MinValue)},
|
||||
{typeof(float), Convert.ToDouble(float.MinValue)},
|
||||
{typeof(decimal), Convert.ToDouble(decimal.MinValue)},
|
||||
|
||||
// Unsigned
|
||||
{typeof(ushort), Convert.ToDouble(ushort.MinValue)},
|
||||
{typeof(uint), Convert.ToDouble(uint.MinValue)},
|
||||
{typeof(ulong), Convert.ToDouble(ulong.MinValue)},
|
||||
{typeof(byte), Convert.ToDouble(byte.MinValue)}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the min value of a given numeric type as a double.
|
||||
/// </summary>
|
||||
private static readonly Dictionary<Type, double> s_MaxAsDouble =
|
||||
new Dictionary<Type, double>
|
||||
{
|
||||
// Duh
|
||||
{typeof(double), double.MaxValue},
|
||||
|
||||
// Signed
|
||||
{typeof(short), Convert.ToDouble(short.MaxValue)},
|
||||
{typeof(int), Convert.ToDouble(int.MaxValue)},
|
||||
{typeof(long), Convert.ToDouble(long.MaxValue)},
|
||||
{typeof(float), Convert.ToDouble(float.MaxValue)},
|
||||
{typeof(decimal), Convert.ToDouble(decimal.MaxValue)},
|
||||
|
||||
// Unsigned
|
||||
{typeof(ushort), Convert.ToDouble(ushort.MaxValue)},
|
||||
{typeof(uint), Convert.ToDouble(uint.MaxValue)},
|
||||
{typeof(ulong), Convert.ToDouble(ulong.MaxValue)},
|
||||
{typeof(byte), Convert.ToDouble(byte.MaxValue)}
|
||||
};
|
||||
|
||||
private readonly object m_Min;
|
||||
private readonly object m_Max;
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the min value for this range.
|
||||
/// </summary>
|
||||
public object Min { get { return m_Min; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the max value for this range.
|
||||
/// </summary>
|
||||
public object Max { get { return m_Max; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
public RangeAttribute(ushort min, ushort max)
|
||||
: this((object)min, (object)max)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
public RangeAttribute(short min, short max)
|
||||
: this((object)min, (object)max)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
public RangeAttribute(uint min, uint max)
|
||||
: this((object)min, (object)max)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
public RangeAttribute(int min, int max)
|
||||
: this((object)min, (object)max)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
public RangeAttribute(ulong min, ulong max)
|
||||
: this((object)min, (object)max)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
public RangeAttribute(long min, long max)
|
||||
: this((object)min, (object)max)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
public RangeAttribute(float min, float max)
|
||||
: this((object)min, (object)max)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
public RangeAttribute(double min, double max)
|
||||
: this((object)min, (object)max)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
public RangeAttribute(byte min, byte max)
|
||||
: this((object)min, (object)max)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
public RangeAttribute(sbyte min, sbyte max)
|
||||
: this((object)min, (object)max)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
public RangeAttribute(decimal min, decimal max)
|
||||
: this((object)min, (object)max)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
public RangeAttribute(object min, object max)
|
||||
{
|
||||
if (min == null)
|
||||
throw new ArgumentNullException("min");
|
||||
|
||||
if (max == null)
|
||||
throw new ArgumentNullException("max");
|
||||
|
||||
if (min.GetType() != max.GetType())
|
||||
throw new ArgumentException("Min and Max types do not match");
|
||||
|
||||
if (!min.GetType().IsNumeric())
|
||||
throw new ArgumentException("Given types are not numeric");
|
||||
|
||||
m_Min = min;
|
||||
m_Max = max;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Remaps the given numeric value from its min/max range into double min/max range.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static double RemapToDouble(object value)
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException("value");
|
||||
|
||||
Func<object, double> remap;
|
||||
if (!s_RemapToDouble.TryGetValue(value.GetType(), out remap))
|
||||
throw new NotSupportedException("Value type is not supported.");
|
||||
|
||||
return remap(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remaps the given double value from its min/max range into the target type min/max range.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static object RemapFromDouble(double value, Type type)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
Func<double, object> remap;
|
||||
if (!s_RemapFromDouble.TryGetValue(type, out remap))
|
||||
throw new NotSupportedException("Value type is not supported.");
|
||||
|
||||
return remap(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clamps the given numeric value into the valid ranges of the target numeric type.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static object Clamp(object value, Type type)
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException("value");
|
||||
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
if (!type.IsNumeric())
|
||||
throw new ArgumentException("Target type is not numeric");
|
||||
|
||||
if (!value.GetType().IsNumeric())
|
||||
throw new ArgumentException("Source value is not numeric");
|
||||
|
||||
double doubleValue = Convert.ToDouble(value);
|
||||
double clamped = Clamp(doubleValue, type);
|
||||
|
||||
return Convert.ChangeType(clamped, value.GetType(), CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clamps the given double value into the valid ranges of the target numeric type.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static double Clamp(double value, Type type)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
Func<double, double> clamp;
|
||||
if (!s_Clamp.TryGetValue(type, out clamp))
|
||||
throw new NotSupportedException("Value type is not supported.");
|
||||
|
||||
return clamp(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remaps the numeric value into the min-max range of the target numeric type.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static object Remap(object value, Type type)
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException("value");
|
||||
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
if (!type.IsNumeric())
|
||||
throw new ArgumentException("Target type is not numeric");
|
||||
|
||||
if (!value.GetType().IsNumeric())
|
||||
throw new ArgumentException("Source value is not numeric");
|
||||
|
||||
double intermediate = RemapToDouble(value);
|
||||
return RemapFromDouble(intermediate, type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clamps the given numeric value to the defined min/max then remaps to the target numeric type.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public object ClampMinMaxThenRemap(object value, Type type)
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException("value");
|
||||
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
if (!type.IsNumeric())
|
||||
throw new ArgumentException("Target type is not numeric");
|
||||
|
||||
if (!value.GetType().IsNumeric())
|
||||
throw new ArgumentException("Source value is not numeric");
|
||||
|
||||
double min = Convert.ToDouble(Min);
|
||||
double max = Convert.ToDouble(Max);
|
||||
double doubleValue = Convert.ToDouble(value);
|
||||
|
||||
double clamped = MathUtils.Clamp(doubleValue, min, max);
|
||||
object remapped = RemapMinMax(clamped, type);
|
||||
|
||||
return Convert.ChangeType(remapped, value.GetType(), CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remaps the given numeric value to the defined min/max.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public object RemapMinMax(object value)
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException("value");
|
||||
|
||||
if (!value.GetType().IsNumeric())
|
||||
throw new ArgumentException("Source value is not numeric");
|
||||
|
||||
double sourceMin = GetMinAsDouble(value.GetType());
|
||||
double sourceMax = GetMaxAsDouble(value.GetType());
|
||||
|
||||
double targetMin = Convert.ToDouble(Min);
|
||||
double targetMax = Convert.ToDouble(Max);
|
||||
|
||||
double doubleValue = Convert.ToDouble(value);
|
||||
|
||||
double remapped = MathUtils.MapRange(sourceMin, sourceMax, targetMin, targetMax, doubleValue);
|
||||
|
||||
return Convert.ChangeType(remapped, value.GetType(), CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
private object RemapMinMax(object value, Type type)
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException("value");
|
||||
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
if (!type.IsNumeric())
|
||||
throw new ArgumentException("Target type is not numeric");
|
||||
|
||||
if (!value.GetType().IsNumeric())
|
||||
throw new ArgumentException("Source value is not numeric");
|
||||
|
||||
double sourceMin = Convert.ToDouble(Min);
|
||||
double sourceMax = Convert.ToDouble(Max);
|
||||
|
||||
double targetMin = GetMinAsDouble(type);
|
||||
double targetMax = GetMaxAsDouble(type);
|
||||
|
||||
double doubleValue = Convert.ToDouble(value);
|
||||
|
||||
double remapped = MathUtils.MapRange(sourceMin, sourceMax, targetMin, targetMax, doubleValue);
|
||||
|
||||
return Convert.ChangeType(remapped, type, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets the min value for the given numeric type as a double.
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
private static double GetMinAsDouble(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
if (!type.IsNumeric())
|
||||
throw new ArgumentException("Target type is not numeric");
|
||||
|
||||
double min;
|
||||
if (!s_MinAsDouble.TryGetValue(type, out min))
|
||||
throw new NotSupportedException("Type is not supported.");
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the max value for the given numeric type as a double.
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
private static double GetMaxAsDouble(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
if (!type.IsNumeric())
|
||||
throw new ArgumentException("Target type is not numeric");
|
||||
|
||||
double max;
|
||||
if (!s_MaxAsDouble.TryGetValue(type, out max))
|
||||
throw new NotSupportedException("Type is not supported.");
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using ICD.Common.Utils.EventArguments;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
|
||||
namespace ICD.Common.Utils.Collections
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a buffer for storing items to be raised in order in a new thread.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public sealed class AsyncEventQueue<T> : IEnumerable<T>, ICollection, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Raised to handle to the next item in the queue.
|
||||
/// </summary>
|
||||
public event EventHandler<GenericEventArgs<T>> OnItemDequeued;
|
||||
|
||||
private readonly Queue<T> m_Queue;
|
||||
|
||||
private readonly SafeCriticalSection m_QueueSection;
|
||||
private readonly SafeCriticalSection m_ProcessSection;
|
||||
|
||||
#region Properties
|
||||
|
||||
public int Count { get { return m_QueueSection.Execute(() => m_Queue.Count); } }
|
||||
|
||||
bool ICollection.IsSynchronized { get { return true; } }
|
||||
|
||||
object ICollection.SyncRoot { get { return this; } }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
public AsyncEventQueue()
|
||||
{
|
||||
m_Queue = new Queue<T>();
|
||||
|
||||
m_QueueSection = new SafeCriticalSection();
|
||||
m_ProcessSection = new SafeCriticalSection();
|
||||
}
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Release resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
OnItemDequeued = null;
|
||||
|
||||
Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enqueues the given item and begins processing the queue.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
public void Enqueue(T item)
|
||||
{
|
||||
m_QueueSection.Execute(() => m_Queue.Enqueue(item));
|
||||
|
||||
ThreadingUtils.SafeInvoke(ProcessQueue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the queued items.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
m_QueueSection.Execute(() => m_Queue.Clear());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Dequeues and raises each item in sequence.
|
||||
/// </summary>
|
||||
private void ProcessQueue()
|
||||
{
|
||||
if (!m_ProcessSection.TryEnter())
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
T item;
|
||||
while (m_Queue.Dequeue(out item))
|
||||
OnItemDequeued.Raise(this, new GenericEventArgs<T>(item));
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_ProcessSection.Leave();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IEnumerable/ICollection
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return m_QueueSection.Execute(() => m_Queue.ToList(m_Queue.Count).GetEnumerator());
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
void ICollection.CopyTo(Array array, int index)
|
||||
{
|
||||
m_QueueSection.Enter();
|
||||
|
||||
try
|
||||
{
|
||||
foreach (T item in this)
|
||||
{
|
||||
array.SetValue(item, index);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_QueueSection.Leave();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -30,9 +30,24 @@ namespace ICD.Common.Utils.Collections
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
public BiDictionary()
|
||||
: this(null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="dict"></param>
|
||||
public BiDictionary(Dictionary<TKey, TValue> dict)
|
||||
{
|
||||
m_KeyToValue = new Dictionary<TKey, TValue>();
|
||||
m_ValueToKey = new Dictionary<TValue, TKey>();
|
||||
|
||||
if (dict == null)
|
||||
return;
|
||||
|
||||
foreach (KeyValuePair<TKey, TValue> kvp in dict)
|
||||
Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
|
||||
#region Methods
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
|
||||
namespace ICD.Common.Utils.Collections
|
||||
{
|
||||
@@ -95,7 +96,7 @@ namespace ICD.Common.Utils.Collections
|
||||
if (set == null)
|
||||
throw new ArgumentNullException("set");
|
||||
|
||||
IcdHashSet<T> unionSet = new IcdHashSet<T>(this);
|
||||
IcdHashSet<T> unionSet = new IcdHashSet<T>(m_Dict.Comparer, this);
|
||||
unionSet.AddRange(set);
|
||||
|
||||
return unionSet;
|
||||
@@ -112,7 +113,7 @@ namespace ICD.Common.Utils.Collections
|
||||
if (set == null)
|
||||
throw new ArgumentNullException("set");
|
||||
|
||||
IcdHashSet<T> subtractSet = new IcdHashSet<T>(this);
|
||||
IcdHashSet<T> subtractSet = new IcdHashSet<T>(m_Dict.Comparer, this);
|
||||
|
||||
foreach (T item in set)
|
||||
subtractSet.Remove(item);
|
||||
@@ -131,7 +132,7 @@ namespace ICD.Common.Utils.Collections
|
||||
if (set == null)
|
||||
throw new ArgumentNullException("set");
|
||||
|
||||
IcdHashSet<T> intersectionSet = new IcdHashSet<T>();
|
||||
IcdHashSet<T> intersectionSet = new IcdHashSet<T>(m_Dict.Comparer);
|
||||
|
||||
foreach (T item in set.Where(Contains))
|
||||
intersectionSet.Add(item);
|
||||
@@ -150,7 +151,7 @@ namespace ICD.Common.Utils.Collections
|
||||
if (set == null)
|
||||
throw new ArgumentNullException("set");
|
||||
|
||||
IcdHashSet<T> output = new IcdHashSet<T>(this);
|
||||
IcdHashSet<T> output = new IcdHashSet<T>(m_Dict.Comparer, this);
|
||||
|
||||
foreach (T item in set)
|
||||
{
|
||||
@@ -228,7 +229,7 @@ namespace ICD.Common.Utils.Collections
|
||||
public bool SetEquals(IcdHashSet<T> set)
|
||||
{
|
||||
if (set == null)
|
||||
return Count == 0;
|
||||
throw new ArgumentNullException("set");
|
||||
|
||||
return Count == set.Count && set.All(Contains);
|
||||
}
|
||||
@@ -328,6 +329,18 @@ namespace ICD.Common.Utils.Collections
|
||||
return m_Dict.Remove(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes each of the items in the sequence from the collection.
|
||||
/// </summary>
|
||||
/// <param name="items"></param>
|
||||
public void RemoveRange(IEnumerable<T> items)
|
||||
{
|
||||
if (items == null)
|
||||
throw new ArgumentNullException("items");
|
||||
|
||||
m_Dict.RemoveAll(items);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IEnumerable<T>
|
||||
|
||||
@@ -32,13 +32,8 @@ namespace ICD.Common.Utils.Collections
|
||||
if (key == null)
|
||||
throw new ArgumentNullException("key");
|
||||
|
||||
if (!ContainsKey(key))
|
||||
{
|
||||
int index = m_OrderedKeys.AddSorted(key, m_Comparer);
|
||||
m_ValuesOrderedByKey.Insert(index, value);
|
||||
}
|
||||
|
||||
m_Dictionary[key] = value;
|
||||
Remove(key);
|
||||
Add(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,9 +104,12 @@ namespace ICD.Common.Utils.Collections
|
||||
throw new ArgumentNullException("key");
|
||||
|
||||
if (m_Dictionary.ContainsKey(key))
|
||||
throw new ArgumentException("An item with the same key has already been added.", "key");
|
||||
throw new ArgumentOutOfRangeException("key", "An item with the same key has already been added.");
|
||||
|
||||
this[key] = value;
|
||||
int index = m_OrderedKeys.AddSorted(key, m_Comparer);
|
||||
m_ValuesOrderedByKey.Insert(index, value);
|
||||
|
||||
m_Dictionary[key] = value;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace ICD.Common.Utils.Collections
|
||||
if (!m_PriorityToQueue.TryGetValue(priority, out queue))
|
||||
{
|
||||
queue = new List<T>();
|
||||
m_PriorityToQueue[priority] = queue;
|
||||
m_PriorityToQueue.Add(priority, queue);
|
||||
}
|
||||
|
||||
queue.Add(item);
|
||||
@@ -97,7 +97,7 @@ namespace ICD.Common.Utils.Collections
|
||||
if (!m_PriorityToQueue.TryGetValue(priority, out queue))
|
||||
{
|
||||
queue = new List<T>();
|
||||
m_PriorityToQueue[priority] = queue;
|
||||
m_PriorityToQueue.Add(priority, queue);
|
||||
}
|
||||
|
||||
queue.Insert(0, item);
|
||||
@@ -136,7 +136,7 @@ namespace ICD.Common.Utils.Collections
|
||||
|
||||
bool inserted = false;
|
||||
|
||||
foreach (KeyValuePair<int, List<T>> kvp in m_PriorityToQueue)
|
||||
foreach (KeyValuePair<int, List<T>> kvp in m_PriorityToQueue.ToArray())
|
||||
{
|
||||
int[] removeIndices =
|
||||
kvp.Value
|
||||
@@ -166,6 +166,9 @@ namespace ICD.Common.Utils.Collections
|
||||
|
||||
inserted = true;
|
||||
}
|
||||
|
||||
if (kvp.Value.Count == 0)
|
||||
m_PriorityToQueue.Remove(kvp.Key);
|
||||
}
|
||||
|
||||
if (!inserted)
|
||||
@@ -194,24 +197,30 @@ namespace ICD.Common.Utils.Collections
|
||||
[PublicAPI]
|
||||
public bool TryDequeue(out T output)
|
||||
{
|
||||
output = default(T);
|
||||
while (true)
|
||||
{
|
||||
output = default(T);
|
||||
|
||||
KeyValuePair<int, List<T>> kvp;
|
||||
if (!m_PriorityToQueue.TryFirst(out kvp))
|
||||
return false;
|
||||
KeyValuePair<int, List<T>> kvp;
|
||||
if (!m_PriorityToQueue.TryFirst(out kvp))
|
||||
return false;
|
||||
|
||||
int priority = kvp.Key;
|
||||
List<T> queue = kvp.Value;
|
||||
int priority = kvp.Key;
|
||||
List<T> queue = kvp.Value;
|
||||
|
||||
output = queue[0];
|
||||
queue.RemoveAt(0);
|
||||
bool found = queue.TryFirst(out output);
|
||||
if (found)
|
||||
{
|
||||
queue.RemoveAt(0);
|
||||
m_Count--;
|
||||
}
|
||||
|
||||
if (queue.Count == 0)
|
||||
m_PriorityToQueue.Remove(priority);
|
||||
if (queue.Count == 0)
|
||||
m_PriorityToQueue.Remove(priority);
|
||||
|
||||
m_Count--;
|
||||
|
||||
return true;
|
||||
if (found)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -233,10 +242,7 @@ namespace ICD.Common.Utils.Collections
|
||||
public void CopyTo(Array array, int index)
|
||||
{
|
||||
foreach (T item in this)
|
||||
{
|
||||
array.SetValue(item, index);
|
||||
index++;
|
||||
}
|
||||
array.SetValue(item, index++);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -56,7 +56,16 @@ namespace ICD.Common.Utils.Collections
|
||||
{
|
||||
OnItemDequeued = null;
|
||||
|
||||
m_DequeueTimer.Dispose();
|
||||
m_QueueSection.Enter();
|
||||
|
||||
try
|
||||
{
|
||||
m_DequeueTimer.Dispose();
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_QueueSection.Leave();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
|
||||
namespace ICD.Common.Utils.Collections
|
||||
{
|
||||
@@ -16,8 +15,6 @@ namespace ICD.Common.Utils.Collections
|
||||
private readonly LinkedList<TContents> m_Collection;
|
||||
private int m_MaxSize;
|
||||
|
||||
private readonly SafeCriticalSection m_CollectionLock;
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
@@ -41,13 +38,13 @@ namespace ICD.Common.Utils.Collections
|
||||
/// <summary>
|
||||
/// Gets the number of items in the collection.
|
||||
/// </summary>
|
||||
public int Count { get { return m_CollectionLock.Execute(() => m_Collection.Count); } }
|
||||
public int Count { get { return m_Collection.Count; } }
|
||||
|
||||
/// <summary>
|
||||
/// The IsSynchronized Boolean property returns True if the
|
||||
/// collection is designed to be thread safe; otherwise, it returns False.
|
||||
/// </summary>
|
||||
public bool IsSynchronized { get { return true; } }
|
||||
public bool IsSynchronized { get { return false; } }
|
||||
|
||||
/// <summary>
|
||||
/// The SyncRoot property returns an object, which is used for synchronizing
|
||||
@@ -64,7 +61,6 @@ namespace ICD.Common.Utils.Collections
|
||||
/// <param name="maxSize"></param>
|
||||
public ScrollQueue(int maxSize)
|
||||
{
|
||||
m_CollectionLock = new SafeCriticalSection();
|
||||
m_Collection = new LinkedList<TContents>();
|
||||
MaxSize = maxSize;
|
||||
}
|
||||
@@ -76,7 +72,7 @@ namespace ICD.Common.Utils.Collections
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
m_CollectionLock.Execute(() => m_Collection.Clear());
|
||||
m_Collection.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -86,17 +82,8 @@ namespace ICD.Common.Utils.Collections
|
||||
[PublicAPI]
|
||||
public void Enqueue(TContents item)
|
||||
{
|
||||
m_CollectionLock.Enter();
|
||||
|
||||
try
|
||||
{
|
||||
m_Collection.AddLast(item);
|
||||
Trim();
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_CollectionLock.Leave();
|
||||
}
|
||||
m_Collection.AddLast(item);
|
||||
Trim();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -106,18 +93,9 @@ namespace ICD.Common.Utils.Collections
|
||||
[PublicAPI]
|
||||
public TContents Dequeue()
|
||||
{
|
||||
m_CollectionLock.Enter();
|
||||
|
||||
try
|
||||
{
|
||||
TContents output = m_Collection.First.Value;
|
||||
m_Collection.RemoveFirst();
|
||||
return output;
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_CollectionLock.Leave();
|
||||
}
|
||||
TContents output = Peek();
|
||||
m_Collection.RemoveFirst();
|
||||
return output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -127,7 +105,7 @@ namespace ICD.Common.Utils.Collections
|
||||
[PublicAPI]
|
||||
public TContents Peek()
|
||||
{
|
||||
return m_CollectionLock.Execute(() => m_Collection.First.Value);
|
||||
return m_Collection.First.Value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -141,24 +119,15 @@ namespace ICD.Common.Utils.Collections
|
||||
|
||||
public IEnumerator<TContents> GetEnumerator()
|
||||
{
|
||||
return m_CollectionLock.Execute(() => m_Collection.ToList(Count).GetEnumerator());
|
||||
return m_Collection.GetEnumerator();
|
||||
}
|
||||
|
||||
void ICollection.CopyTo(Array myArr, int index)
|
||||
{
|
||||
m_CollectionLock.Enter();
|
||||
|
||||
try
|
||||
foreach (TContents item in m_Collection)
|
||||
{
|
||||
foreach (TContents item in m_Collection)
|
||||
{
|
||||
myArr.SetValue(item, index);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_CollectionLock.Leave();
|
||||
myArr.SetValue(item, index);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,17 +140,8 @@ namespace ICD.Common.Utils.Collections
|
||||
/// </summary>
|
||||
private void Trim()
|
||||
{
|
||||
m_CollectionLock.Enter();
|
||||
|
||||
try
|
||||
{
|
||||
while (Count > MaxSize)
|
||||
m_Collection.RemoveFirst();
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_CollectionLock.Leave();
|
||||
}
|
||||
while (Count > MaxSize)
|
||||
m_Collection.RemoveFirst();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -28,6 +28,9 @@ namespace ICD.Common.Utils
|
||||
|
||||
public static string FormatAnsi(this eConsoleColor extends, string data)
|
||||
{
|
||||
// % needs to be escaped or weird things happen
|
||||
data = string.IsNullOrEmpty(data) ? data : data.Replace("%", "%%");
|
||||
|
||||
return string.Format("{0}{1}{2}", extends.ToAnsiPrefix(), data, CONSOLE_RESET);
|
||||
}
|
||||
|
||||
|
||||
@@ -79,6 +79,8 @@ namespace ICD.Common.Utils.Csv
|
||||
[PublicAPI]
|
||||
public void AppendValue(string value)
|
||||
{
|
||||
value = value ?? string.Empty;
|
||||
|
||||
if (!m_NewLine)
|
||||
m_Writer.WrappedTextWriter.Write(m_Seperator);
|
||||
|
||||
|
||||
BIN
ICD.Common.Utils/CultureInfo.sqlite
Normal file
BIN
ICD.Common.Utils/CultureInfo.sqlite
Normal file
Binary file not shown.
15
ICD.Common.Utils/DateTimeUtils.cs
Normal file
15
ICD.Common.Utils/DateTimeUtils.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace ICD.Common.Utils
|
||||
{
|
||||
public static class DateTimeUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts the hour in 24 hour format to 12 hour format (1 through 12).
|
||||
/// </summary>
|
||||
/// <param name="hour"></param>
|
||||
/// <returns></returns>
|
||||
public static int To12Hour(int hour)
|
||||
{
|
||||
return MathUtils.Modulus(hour + 11, 12) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
14
ICD.Common.Utils/Email/EmailValidation.cs
Normal file
14
ICD.Common.Utils/Email/EmailValidation.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace ICD.Common.Utils.Email
|
||||
{
|
||||
public static class EmailValidation
|
||||
{
|
||||
private const string EMAIL_REGEX = @"(?:[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*|""(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*"")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])";
|
||||
|
||||
public static bool IsValidEmailAddress(string emailAddress)
|
||||
{
|
||||
return emailAddress != null && Regex.IsMatch(emailAddress, EMAIL_REGEX);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ namespace ICD.Common.Utils
|
||||
/// Returns true if the given type is an enum.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static bool IsEnumType(Type type)
|
||||
public static bool IsEnumType(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
@@ -148,7 +148,7 @@ namespace ICD.Common.Utils
|
||||
/// Gets the values from an enumeration without performing any caching. This is slow because of reflection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<int> GetValues(Type type)
|
||||
private static IEnumerable<int> GetValues(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
@@ -6,7 +6,17 @@
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
public BoolEventArgs(bool data) : base(data)
|
||||
public BoolEventArgs(bool data)
|
||||
: base(data)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public BoolEventArgs(BoolEventArgs eventArgs)
|
||||
: this(eventArgs.Data)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,14 @@
|
||||
public StringEventArgs(string data) : base(data)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public StringEventArgs(StringEventArgs eventArgs)
|
||||
: base(eventArgs.Data)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
90
ICD.Common.Utils/Extensions/CultureInfoExtensions.cs
Normal file
90
ICD.Common.Utils/Extensions/CultureInfoExtensions.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace ICD.Common.Utils.Extensions
|
||||
{
|
||||
public static class CultureInfoExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns true if the given culture uses a 24 hour time format.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
public static bool Uses24HourFormat(this CultureInfo extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
return extends.DateTimeFormat.ShortTimePattern.Contains("H");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the time patterns for the given culture to use 12 hour time.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
public static void ConvertTo12HourCulture(this CultureInfo extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (extends.IsReadOnly)
|
||||
throw new InvalidOperationException("Culture is readonly");
|
||||
|
||||
DateTimeFormatInfo dateTimeFormat = extends.DateTimeFormat;
|
||||
|
||||
dateTimeFormat.FullDateTimePattern = To12HourPattern(dateTimeFormat.FullDateTimePattern);
|
||||
dateTimeFormat.LongTimePattern = To12HourPattern(dateTimeFormat.LongTimePattern);
|
||||
dateTimeFormat.ShortTimePattern = To12HourPattern(dateTimeFormat.ShortTimePattern);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the time patterns for the given culture to use 24 hour time.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
public static void ConvertTo24HourCulture(this CultureInfo extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (extends.IsReadOnly)
|
||||
throw new InvalidOperationException("Culture is readonly");
|
||||
|
||||
DateTimeFormatInfo dateTimeFormat = extends.DateTimeFormat;
|
||||
|
||||
dateTimeFormat.FullDateTimePattern = To24HourPattern(dateTimeFormat.FullDateTimePattern);
|
||||
dateTimeFormat.LongTimePattern = To24HourPattern(dateTimeFormat.LongTimePattern);
|
||||
dateTimeFormat.ShortTimePattern = To24HourPattern(dateTimeFormat.ShortTimePattern);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the given format pattern to use 24 hour time.
|
||||
/// </summary>
|
||||
/// <param name="pattern"></param>
|
||||
/// <returns></returns>
|
||||
private static string To24HourPattern(string pattern)
|
||||
{
|
||||
if (pattern == null)
|
||||
return null;
|
||||
|
||||
pattern = pattern.Replace(" tt", "");
|
||||
|
||||
return pattern.Replace("h", "H");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the given format pattern to use 12 hour time.
|
||||
/// </summary>
|
||||
/// <param name="pattern"></param>
|
||||
/// <returns></returns>
|
||||
private static string To12HourPattern(string pattern)
|
||||
{
|
||||
if (pattern == null)
|
||||
return null;
|
||||
|
||||
if (!pattern.Contains("t"))
|
||||
pattern = pattern + " tt";
|
||||
|
||||
return pattern.Replace("H", "h");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using ICD.Common.Properties;
|
||||
|
||||
namespace ICD.Common.Utils.Extensions
|
||||
{
|
||||
@@ -63,5 +64,33 @@ namespace ICD.Common.Utils.Extensions
|
||||
bool success = times.OrderByDescending(dt => dt).TryFirst(dt => inclusive ? target >= dt : target > dt, out latestTime);
|
||||
return success ? latestTime : (DateTime?) null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the DateTime representing the very start of the current day.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
public static DateTime StartOfDay(this DateTime extends)
|
||||
{
|
||||
return new DateTime(extends.Year, extends.Month, extends.Day, 0, 0, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the DateTime representing the very end of the current day.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
public static DateTime EndOfDay(this DateTime extends)
|
||||
{
|
||||
return extends.StartOfDay() + new TimeSpan(24, 0, 0);
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public static double ToUnixTimestamp(this DateTime extends)
|
||||
{
|
||||
DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
|
||||
TimeSpan diff = extends.ToUniversalTime() - origin;
|
||||
return Math.Floor(diff.TotalSeconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@ namespace ICD.Common.Utils.Extensions
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (keys == null)
|
||||
throw new ArgumentNullException("keys");
|
||||
|
||||
foreach (TKey key in keys)
|
||||
extends.Remove(key);
|
||||
}
|
||||
@@ -66,6 +69,7 @@ namespace ICD.Common.Utils.Extensions
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
[CanBeNull]
|
||||
[PublicAPI]
|
||||
public static TValue GetDefault<TKey, TValue>(this IDictionary<TKey, TValue> extends, TKey key)
|
||||
{
|
||||
@@ -122,8 +126,63 @@ namespace ICD.Common.Utils.Extensions
|
||||
if (key == null)
|
||||
throw new ArgumentNullException("key");
|
||||
|
||||
extends[key] = extends.GetDefault(key, defaultValue);
|
||||
return extends[key];
|
||||
TValue value = extends.GetDefault(key, defaultValue);
|
||||
extends[key] = value;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the key is present in the dictionary return the value, otherwise add a new value to the dictionary and return it.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static TValue GetOrAddNew<TKey, TValue>(this IDictionary<TKey, TValue> extends, TKey key)
|
||||
where TValue : new()
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||
if (key == null)
|
||||
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||
throw new ArgumentNullException("key");
|
||||
|
||||
return extends.GetOrAddNew(key, () => ReflectionUtils.CreateInstance<TValue>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the key is present in the dictionary return the value, otherwise add a new value to the dictionary and return it.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="valueFunc"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static TValue GetOrAddNew<TKey, TValue>(this IDictionary<TKey, TValue> extends, TKey key, Func<TValue> valueFunc)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||
if (key == null)
|
||||
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||
throw new ArgumentNullException("key");
|
||||
|
||||
TValue value;
|
||||
if (!extends.TryGetValue(key, out value))
|
||||
{
|
||||
value = valueFunc();
|
||||
extends.Add(key, value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -58,7 +58,18 @@ namespace ICD.Common.Utils.Extensions
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
return extends.TryFirst(i => true, out item);
|
||||
IList<T> list = extends as IList<T>;
|
||||
if (list == null)
|
||||
return extends.TryFirst(i => true, out item);
|
||||
|
||||
item = default(T);
|
||||
|
||||
if (list.Count <= 0)
|
||||
return false;
|
||||
|
||||
item = list[0];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -106,7 +117,18 @@ namespace ICD.Common.Utils.Extensions
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
return extends.TryLast(i => true, out item);
|
||||
IList<T> list = extends as IList<T>;
|
||||
if (list == null)
|
||||
return extends.TryLast(i => true, out item);
|
||||
|
||||
item = default(T);
|
||||
|
||||
if (list.Count <= 0)
|
||||
return false;
|
||||
|
||||
item = list[list.Count - 1];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -156,17 +178,32 @@ namespace ICD.Common.Utils.Extensions
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (index < 0)
|
||||
throw new ArgumentOutOfRangeException("index");
|
||||
|
||||
item = default(T);
|
||||
|
||||
try
|
||||
IList<T> list = extends as IList<T>;
|
||||
if (list != null)
|
||||
{
|
||||
item = extends.ElementAt(index);
|
||||
if (index >= list.Count)
|
||||
return false;
|
||||
item = list[index];
|
||||
return true;
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
|
||||
int current = 0;
|
||||
foreach (T value in extends)
|
||||
{
|
||||
return false;
|
||||
if (current == index)
|
||||
{
|
||||
item = value;
|
||||
return true;
|
||||
}
|
||||
current++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -227,6 +264,12 @@ namespace ICD.Common.Utils.Extensions
|
||||
if (comparer == null)
|
||||
throw new ArgumentNullException("comparer");
|
||||
|
||||
// Simple count check
|
||||
ICollection<T> a = extends as ICollection<T>;
|
||||
ICollection<T> b = other as ICollection<T>;
|
||||
if (a != null && b != null && a.Count != b.Count)
|
||||
return false;
|
||||
|
||||
using (IEnumerator<T> firstPos = extends.GetEnumerator())
|
||||
{
|
||||
using (IEnumerator<T> secondPos = other.GetEnumerator())
|
||||
@@ -285,6 +328,12 @@ namespace ICD.Common.Utils.Extensions
|
||||
if (comparer == null)
|
||||
throw new ArgumentNullException("comparer");
|
||||
|
||||
// Simple count check
|
||||
ICollection<T> a = extends as ICollection<T>;
|
||||
ICollection<T> b = other as ICollection<T>;
|
||||
if (a != null && b != null && a.Count != b.Count)
|
||||
return false;
|
||||
|
||||
Dictionary<T, int> count = new Dictionary<T, int>(comparer);
|
||||
|
||||
foreach (T item in extends)
|
||||
@@ -383,7 +432,11 @@ namespace ICD.Common.Utils.Extensions
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
extends.ForEach(item => { });
|
||||
// ReSharper disable UnusedVariable
|
||||
foreach (T item in extends)
|
||||
// ReSharper restore UnusedVariable
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -616,7 +669,7 @@ namespace ICD.Common.Utils.Extensions
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="comparer"></param>
|
||||
/// <returns></returns>
|
||||
public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> extends, IComparer<T> comparer)
|
||||
public static IOrderedEnumerable<T> Order<T>(this IEnumerable<T> extends, IComparer<T> comparer)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
@@ -634,7 +687,7 @@ namespace ICD.Common.Utils.Extensions
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="comparer"></param>
|
||||
/// <returns></returns>
|
||||
public static IOrderedEnumerable<T> OrderByDescending<T>(this IEnumerable<T> extends, IComparer<T> comparer)
|
||||
public static IOrderedEnumerable<T> OrderDescending<T>(this IEnumerable<T> extends, IComparer<T> comparer)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
@@ -692,8 +745,22 @@ namespace ICD.Common.Utils.Extensions
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
ICollection<T> collection = extends as ICollection<T> ?? extends.ToArray();
|
||||
collection.CopyTo(array, index);
|
||||
if (array == null)
|
||||
throw new ArgumentNullException("array");
|
||||
|
||||
ICollection<T> collection = extends as ICollection<T>;
|
||||
if (collection != null)
|
||||
{
|
||||
collection.CopyTo(array, index);
|
||||
return;
|
||||
}
|
||||
|
||||
int current = 0;
|
||||
foreach (T item in extends)
|
||||
{
|
||||
array[index + current] = item;
|
||||
current++;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -707,7 +774,7 @@ namespace ICD.Common.Utils.Extensions
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
return new IcdHashSet<T>(extends);
|
||||
return extends.ToIcdHashSet(EqualityComparer<T>.Default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -778,7 +845,7 @@ namespace ICD.Common.Utils.Extensions
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static Dictionary<int, T> ToDictionary<T>(this IEnumerable<T> extends)
|
||||
public static Dictionary<int, T> ToIndexedDictionary<T>(this IEnumerable<T> extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
@@ -795,7 +862,7 @@ namespace ICD.Common.Utils.Extensions
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static Dictionary<uint, T> ToDictionaryUInt<T>(this IEnumerable<T> extends)
|
||||
public static Dictionary<uint, T> ToIndexedDictionaryUInt<T>(this IEnumerable<T> extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
@@ -1,374 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ICD.Common.Properties;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace ICD.Common.Utils.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for working with JSON.
|
||||
/// </summary>
|
||||
public static class JsonExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes the object value.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="serializer"></param>
|
||||
/// <param name="converter"></param>
|
||||
[PublicAPI]
|
||||
public static void WriteObject(this JsonWriter extends, object value, JsonSerializer serializer,
|
||||
JsonConverter converter)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (serializer == null)
|
||||
throw new ArgumentNullException("serializer");
|
||||
|
||||
if (converter == null)
|
||||
throw new ArgumentNullException("converter");
|
||||
|
||||
JObject jObject = JObject.FromObject(value, serializer);
|
||||
jObject.WriteTo(extends, converter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the type value.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="type"></param>
|
||||
[PublicAPI]
|
||||
public static void WriteType(this JsonWriter extends, Type type)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (type == null)
|
||||
{
|
||||
extends.WriteNull();
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the smallest possible name representation for the type that will still resolve
|
||||
string name = Type.GetType(type.FullName) == null
|
||||
? type.AssemblyQualifiedName
|
||||
: type.FullName;
|
||||
|
||||
extends.WriteValue(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value as a Type.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static Type GetValueAsType(this JsonReader extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
string value = extends.GetValueAsString();
|
||||
return Type.GetType(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value as an unsigned integer.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static uint GetValueAsUInt(this JsonReader extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (extends.TokenType == JsonToken.Integer)
|
||||
return (uint)(long)extends.Value;
|
||||
|
||||
string message = string.Format("Token {0} {1} is not {2}", extends.TokenType, extends.Value, JsonToken.Integer);
|
||||
throw new InvalidCastException(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value as an integer.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static int GetValueAsInt(this JsonReader extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (extends.TokenType == JsonToken.Integer)
|
||||
return (int)(long)extends.Value;
|
||||
|
||||
string message = string.Format("Token {0} {1} is not {2}", extends.TokenType, extends.Value, JsonToken.Integer);
|
||||
throw new InvalidCastException(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value as a string.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static string GetValueAsString(this JsonReader extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (extends.TokenType == JsonToken.String || extends.TokenType == JsonToken.Null)
|
||||
return extends.Value as string;
|
||||
|
||||
string message = string.Format("Token {0} {1} is not {2}", extends.TokenType, extends.Value, JsonToken.String);
|
||||
throw new InvalidCastException(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value as a bool.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static bool GetValueAsBool(this JsonReader extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (extends.TokenType == JsonToken.Boolean)
|
||||
return (bool)extends.Value;
|
||||
|
||||
string message = string.Format("Token {0} {1} is not {2}", extends.TokenType, extends.Value, JsonToken.Boolean);
|
||||
throw new InvalidCastException(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value as an enum.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static T GetValueAsEnum<T>(this JsonReader extends)
|
||||
where T : struct, IConvertible
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (extends.TokenType == JsonToken.String)
|
||||
return EnumUtils.Parse<T>(extends.GetValueAsString(), true);
|
||||
|
||||
return (T)(object)extends.GetValueAsInt();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the given sequence of items to the writer.
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="items"></param>
|
||||
public static void SerializeArray<TItem>(this JsonSerializer extends, JsonWriter writer, IEnumerable<TItem> items)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (writer == null)
|
||||
throw new ArgumentNullException("writer");
|
||||
|
||||
if (items == null)
|
||||
throw new ArgumentNullException("items");
|
||||
|
||||
extends.SerializeArray(writer, items, (s, w, item) => s.Serialize(w, item));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the given sequence of items to the writer.
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="items"></param>
|
||||
/// <param name="write"></param>
|
||||
public static void SerializeArray<TItem>(this JsonSerializer extends, JsonWriter writer, IEnumerable<TItem> items,
|
||||
Action<JsonSerializer, JsonWriter, TItem> write)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (writer == null)
|
||||
throw new ArgumentNullException("writer");
|
||||
|
||||
if (items == null)
|
||||
throw new ArgumentNullException("items");
|
||||
|
||||
if (write == null)
|
||||
throw new ArgumentNullException("write");
|
||||
|
||||
writer.WriteStartArray();
|
||||
{
|
||||
foreach (TItem item in items)
|
||||
write(extends, writer, item);
|
||||
}
|
||||
writer.WriteEndArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes an array of items from the reader's current value.
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="reader"></param>
|
||||
public static IEnumerable<TItem> DeserializeArray<TItem>(this JsonSerializer extends, JsonReader reader)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (reader == null)
|
||||
throw new ArgumentNullException("reader");
|
||||
|
||||
return extends.DeserializeArray(reader, (s, r) => extends.Deserialize<TItem>(reader));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes an array of items from the reader's current value.
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="reader"></param>
|
||||
/// <param name="read"></param>
|
||||
public static IEnumerable<TItem> DeserializeArray<TItem>(this JsonSerializer extends, JsonReader reader,
|
||||
Func<JsonSerializer, JsonReader, TItem> read)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (reader == null)
|
||||
throw new ArgumentNullException("reader");
|
||||
|
||||
if (read == null)
|
||||
throw new ArgumentNullException("read");
|
||||
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
return Enumerable.Empty<TItem>();
|
||||
|
||||
if (reader.TokenType != JsonToken.StartArray)
|
||||
throw new FormatException(string.Format("Expected token {0} got {1}", JsonToken.StartArray, reader.TokenType));
|
||||
|
||||
return DeserializeArrayIterator(extends, reader, read);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes an array of items from the reader's current value.
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem"></typeparam>
|
||||
/// <param name="serializer"></param>
|
||||
/// <param name="reader"></param>
|
||||
/// <param name="read"></param>
|
||||
private static IEnumerable<TItem> DeserializeArrayIterator<TItem>(JsonSerializer serializer, JsonReader reader,
|
||||
Func<JsonSerializer, JsonReader, TItem> read)
|
||||
{
|
||||
// Step into the first value
|
||||
reader.Read();
|
||||
|
||||
while (reader.TokenType != JsonToken.EndArray)
|
||||
{
|
||||
TItem output = read(serializer, reader);
|
||||
yield return output;
|
||||
|
||||
// Read out of the last value
|
||||
reader.Read();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the given sequence of key-value-pairs to the writer.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="items"></param>
|
||||
public static void SerializeDictionary<TKey, TValue>(this JsonSerializer extends, JsonWriter writer,
|
||||
IEnumerable<KeyValuePair<TKey, TValue>> items)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (writer == null)
|
||||
throw new ArgumentNullException("writer");
|
||||
|
||||
if (items == null)
|
||||
throw new ArgumentNullException("items");
|
||||
|
||||
writer.WriteStartObject();
|
||||
{
|
||||
foreach (KeyValuePair<TKey, TValue> kvp in items)
|
||||
{
|
||||
writer.WritePropertyName(kvp.Key.ToString());
|
||||
extends.Serialize(writer, kvp.Value);
|
||||
}
|
||||
}
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes a dictionary of items from the reader's current value.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="reader"></param>
|
||||
public static IEnumerable<KeyValuePair<TKey, TValue>> DeserializeDictionary<TKey, TValue>(this JsonSerializer extends,
|
||||
JsonReader reader)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (reader == null)
|
||||
throw new ArgumentNullException("reader");
|
||||
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
return Enumerable.Empty<KeyValuePair<TKey, TValue>>();
|
||||
|
||||
if (reader.TokenType != JsonToken.StartObject)
|
||||
throw new FormatException(string.Format("Expected token {0} got {1}", JsonToken.StartObject, reader.TokenType));
|
||||
|
||||
return DeserializeDictionaryIterator<TKey, TValue>(extends, reader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes a dictionary of items from the reader's current value.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
/// <param name="serializer"></param>
|
||||
/// <param name="reader"></param>
|
||||
private static IEnumerable<KeyValuePair<TKey, TValue>> DeserializeDictionaryIterator<TKey, TValue>(
|
||||
JsonSerializer serializer, JsonReader reader)
|
||||
{
|
||||
// Step into the first key
|
||||
reader.Read();
|
||||
|
||||
while (reader.TokenType != JsonToken.EndObject)
|
||||
{
|
||||
TKey key = (TKey)Convert.ChangeType(reader.Value, typeof(TKey), null);
|
||||
|
||||
// Step into the value
|
||||
reader.Read();
|
||||
|
||||
TValue value = serializer.Deserialize<TValue>(reader);
|
||||
|
||||
yield return new KeyValuePair<TKey, TValue>(key, value);
|
||||
|
||||
// Read out of the last value
|
||||
reader.Read();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
258
ICD.Common.Utils/Extensions/JsonReaderExtensions.cs
Normal file
258
ICD.Common.Utils/Extensions/JsonReaderExtensions.cs
Normal file
@@ -0,0 +1,258 @@
|
||||
using System;
|
||||
using ICD.Common.Properties;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ICD.Common.Utils.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for working with JSON.
|
||||
/// </summary>
|
||||
public static class JsonReaderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads the current token in the reader and deserializes to the given type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
public static T ReadAsObject<T>(this JsonReader extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
JsonSerializer serializer =
|
||||
#if SIMPLSHARP
|
||||
new JsonSerializer();
|
||||
#else
|
||||
JsonSerializer.CreateDefault();
|
||||
#endif
|
||||
return extends.ReadAsObject<T>(serializer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the current token in the reader and deserializes to the given type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="serializer"></param>
|
||||
/// <returns></returns>
|
||||
public static T ReadAsObject<T>(this JsonReader extends, JsonSerializer serializer)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (serializer == null)
|
||||
throw new ArgumentNullException("serializer");
|
||||
|
||||
return serializer.Deserialize<T>(extends);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads through the current object token and calls the callback for each property value.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="serializer"></param>
|
||||
/// <param name="readPropertyValue"></param>
|
||||
public static void ReadObject(this JsonReader extends, JsonSerializer serializer,
|
||||
Action<string, JsonReader, JsonSerializer> readPropertyValue)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (serializer == null)
|
||||
throw new ArgumentNullException("serializer");
|
||||
|
||||
if (readPropertyValue == null)
|
||||
throw new ArgumentNullException("readPropertyValue");
|
||||
|
||||
if (extends.TokenType == JsonToken.Null)
|
||||
return;
|
||||
|
||||
if (extends.TokenType != JsonToken.StartObject)
|
||||
throw new FormatException(string.Format("Expected {0} got {1}", JsonToken.StartObject, extends.TokenType));
|
||||
|
||||
while (extends.Read())
|
||||
{
|
||||
if (extends.TokenType == JsonToken.EndObject)
|
||||
break;
|
||||
|
||||
// Get the property
|
||||
if (extends.TokenType != JsonToken.PropertyName)
|
||||
continue;
|
||||
string property = (string)extends.Value;
|
||||
|
||||
// Read into the value
|
||||
extends.Read();
|
||||
|
||||
readPropertyValue(property, extends, serializer);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value as a Type.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static Type GetValueAsType(this JsonReader extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
string value = extends.GetValueAsString();
|
||||
return Type.GetType(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value as an unsigned integer.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static uint GetValueAsUInt(this JsonReader extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (extends.TokenType == JsonToken.Integer)
|
||||
return (uint)(long)extends.Value;
|
||||
|
||||
string message = string.Format("Token {0} {1} is not {2}", extends.TokenType, extends.Value, JsonToken.Integer);
|
||||
throw new InvalidCastException(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value as an integer.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static int GetValueAsInt(this JsonReader extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (extends.TokenType == JsonToken.Integer)
|
||||
return (int)(long)extends.Value;
|
||||
|
||||
string message = string.Format("Token {0} {1} is not {2}", extends.TokenType, extends.Value, JsonToken.Integer);
|
||||
throw new InvalidCastException(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value as a string.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static string GetValueAsString(this JsonReader extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
#if !SIMPLSHARP
|
||||
// Newer versions of NewtonSoft try to be helpful and interpret strings as DateTimes without any consideration for different DateTime formats.
|
||||
if (extends.TokenType == JsonToken.Date && extends.DateParseHandling != DateParseHandling.None)
|
||||
throw new InvalidOperationException("DateParseHandling needs to be set to None");
|
||||
#endif
|
||||
|
||||
if (!extends.TokenType.IsPrimitive())
|
||||
throw new FormatException("Expected primitive token type but got " + extends.TokenType);
|
||||
|
||||
return extends.Value == null ? null : extends.Value.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value as a bool.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static bool GetValueAsBool(this JsonReader extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (extends.TokenType == JsonToken.Boolean)
|
||||
return (bool)extends.Value;
|
||||
|
||||
string message = string.Format("Token {0} {1} is not {2}", extends.TokenType, extends.Value, JsonToken.Boolean);
|
||||
throw new InvalidCastException(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value as an enum.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static T GetValueAsEnum<T>(this JsonReader extends)
|
||||
where T : struct, IConvertible
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (extends.TokenType == JsonToken.String)
|
||||
return EnumUtils.Parse<T>(extends.GetValueAsString(), true);
|
||||
|
||||
return (T)(object)extends.GetValueAsInt();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value as a guid.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static Guid GetValueAsGuid(this JsonReader extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
string stringValue = extends.GetValueAsString();
|
||||
return new Guid(stringValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value as a date.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
public static DateTime GetValueAsDateTime(this JsonReader extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
#if !SIMPLSHARP
|
||||
// Newer NewtonSoft tries to be helpful by assuming that anything that looks like a DateTime must be a date.
|
||||
if (extends.DateParseHandling != DateParseHandling.None)
|
||||
return (DateTime)extends.Value;
|
||||
#endif
|
||||
|
||||
string stringValue = extends.GetValueAsString();
|
||||
return DateTime.Parse(stringValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current value as a date.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="format"></param>
|
||||
/// <param name="provider"></param>
|
||||
/// <returns></returns>
|
||||
public static DateTime GetValueAsDateTimeExact(this JsonReader extends, string format, IFormatProvider provider)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
#if !SIMPLSHARP
|
||||
// Newer NewtonSoft tries to be helpful by assuming that anything that looks like a DateTime must be a date.
|
||||
if (extends.DateParseHandling != DateParseHandling.None)
|
||||
throw new InvalidOperationException("DateParseHandling needs to be set to None");
|
||||
#endif
|
||||
|
||||
string stringValue = extends.GetValueAsString();
|
||||
return DateTime.ParseExact(stringValue, format, provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
306
ICD.Common.Utils/Extensions/JsonSerializerExtensions.cs
Normal file
306
ICD.Common.Utils/Extensions/JsonSerializerExtensions.cs
Normal file
@@ -0,0 +1,306 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ICD.Common.Utils.Extensions
|
||||
{
|
||||
public static class JsonSerializerExtensions
|
||||
{
|
||||
private const string PROPERTY_KEY = "k";
|
||||
private const string PROPERTY_VALUE = "v";
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes an array of items from the reader's current value.
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="reader"></param>
|
||||
public static IEnumerable<TItem> DeserializeArray<TItem>(this JsonSerializer extends, JsonReader reader)
|
||||
{
|
||||
return extends.DeserializeArray(reader, (s, r) => extends.Deserialize<TItem>(reader));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes an array of items from the reader's current value.
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="reader"></param>
|
||||
/// <param name="read"></param>
|
||||
public static IEnumerable<TItem> DeserializeArray<TItem>(this JsonSerializer extends, JsonReader reader,
|
||||
Func<JsonSerializer, JsonReader, TItem> read)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (reader == null)
|
||||
throw new ArgumentNullException("reader");
|
||||
|
||||
if (read == null)
|
||||
throw new ArgumentNullException("read");
|
||||
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
return Enumerable.Empty<TItem>();
|
||||
|
||||
if (reader.TokenType != JsonToken.StartArray)
|
||||
throw new FormatException(string.Format("Expected token {0} got {1}", JsonToken.StartArray, reader.TokenType));
|
||||
|
||||
// ToArray to ensure everything gets read before moving onto the next token
|
||||
return DeserializeArrayIterator(extends, reader, read).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes an array of items from the reader's current value.
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem"></typeparam>
|
||||
/// <param name="serializer"></param>
|
||||
/// <param name="reader"></param>
|
||||
/// <param name="read"></param>
|
||||
private static IEnumerable<TItem> DeserializeArrayIterator<TItem>(JsonSerializer serializer, JsonReader reader,
|
||||
Func<JsonSerializer, JsonReader, TItem> read)
|
||||
{
|
||||
// Step into the first value
|
||||
reader.Read();
|
||||
|
||||
while (reader.TokenType != JsonToken.EndArray)
|
||||
{
|
||||
TItem output = read(serializer, reader);
|
||||
yield return output;
|
||||
|
||||
// Step out of the value
|
||||
reader.Read();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes a dictionary of items from the reader's current value.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="reader"></param>
|
||||
public static IEnumerable<KeyValuePair<TKey, TValue>> DeserializeDict<TKey, TValue>(this JsonSerializer extends,
|
||||
JsonReader reader)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (reader == null)
|
||||
throw new ArgumentNullException("reader");
|
||||
|
||||
return extends.DeserializeDict(reader,
|
||||
(s, r) => s.Deserialize<TKey>(r),
|
||||
(s, r) => s.Deserialize<TValue>(r));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes a dictionary of items from the reader's current value.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="reader"></param>
|
||||
/// <param name="readKey"></param>
|
||||
/// <param name="readValue"></param>
|
||||
public static IEnumerable<KeyValuePair<TKey, TValue>> DeserializeDict<TKey, TValue>(this JsonSerializer extends,
|
||||
JsonReader reader,
|
||||
Func<JsonSerializer, JsonReader,
|
||||
TKey> readKey,
|
||||
Func<JsonSerializer, JsonReader,
|
||||
TValue> readValue)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (reader == null)
|
||||
throw new ArgumentNullException("reader");
|
||||
|
||||
if (readKey == null)
|
||||
throw new ArgumentNullException("readKey");
|
||||
|
||||
if (readValue == null)
|
||||
throw new ArgumentNullException("readValue");
|
||||
|
||||
return extends.DeserializeArray(reader, (s, r) => s.DeserializeKeyValuePair(r, readKey, readValue));
|
||||
}
|
||||
|
||||
public static KeyValuePair<TKey, TValue> DeserializeKeyValuePair<TKey, TValue>(this JsonSerializer extends, JsonReader reader,
|
||||
Func<JsonSerializer, JsonReader,
|
||||
TKey> readKey,
|
||||
Func<JsonSerializer, JsonReader,
|
||||
TValue> readValue)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (reader == null)
|
||||
throw new ArgumentNullException("reader");
|
||||
|
||||
if (readKey == null)
|
||||
throw new ArgumentNullException("readKey");
|
||||
|
||||
if (readValue == null)
|
||||
throw new ArgumentNullException("readValue");
|
||||
|
||||
if (reader.TokenType != JsonToken.StartObject)
|
||||
throw new FormatException(string.Format("Expected token {0} got {1}", JsonToken.StartObject, reader.TokenType));
|
||||
|
||||
TKey key = default(TKey);
|
||||
TValue value = default(TValue);
|
||||
|
||||
// Step into the first property
|
||||
reader.Read();
|
||||
|
||||
while (reader.TokenType != JsonToken.EndObject)
|
||||
{
|
||||
if (reader.TokenType != JsonToken.PropertyName)
|
||||
throw new FormatException(string.Format("Expected token {0} got {1}", JsonToken.PropertyName, reader.TokenType));
|
||||
|
||||
string propertyName = (string)reader.Value;
|
||||
|
||||
// Step into the value
|
||||
reader.Read();
|
||||
|
||||
switch (propertyName)
|
||||
{
|
||||
case PROPERTY_KEY:
|
||||
key = readKey(extends, reader);
|
||||
break;
|
||||
|
||||
case PROPERTY_VALUE:
|
||||
value = readValue(extends, reader);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new FormatException(string.Format("Unexpected property {0}", reader.Value));
|
||||
}
|
||||
|
||||
// Step out of the value
|
||||
reader.Read();
|
||||
}
|
||||
|
||||
return new KeyValuePair<TKey, TValue>(key, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the given sequence of items to the writer.
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="items"></param>
|
||||
public static void SerializeArray<TItem>(this JsonSerializer extends, JsonWriter writer, IEnumerable<TItem> items)
|
||||
{
|
||||
extends.SerializeArray(writer, items, (s, w, item) => s.Serialize(w, item));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the given sequence of items to the writer.
|
||||
/// </summary>
|
||||
/// <typeparam name="TItem"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="items"></param>
|
||||
/// <param name="write"></param>
|
||||
public static void SerializeArray<TItem>(this JsonSerializer extends, JsonWriter writer, IEnumerable<TItem> items,
|
||||
Action<JsonSerializer, JsonWriter, TItem> write)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (writer == null)
|
||||
throw new ArgumentNullException("writer");
|
||||
|
||||
if (write == null)
|
||||
throw new ArgumentNullException("write");
|
||||
|
||||
if (items == null)
|
||||
{
|
||||
writer.WriteNull();
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteStartArray();
|
||||
{
|
||||
foreach (TItem item in items)
|
||||
write(extends, writer, item);
|
||||
}
|
||||
writer.WriteEndArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the given sequence of items to the writer.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="items"></param>
|
||||
public static void SerializeDict<TKey, TValue>(this JsonSerializer extends, JsonWriter writer,
|
||||
IEnumerable<KeyValuePair<TKey, TValue>> items)
|
||||
{
|
||||
extends.SerializeDict(writer, items,
|
||||
(s, w, k) => s.Serialize(w, k),
|
||||
(s, w, v) => s.Serialize(w, v));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the given sequence of items to the writer.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="items"></param>
|
||||
/// <param name="writeKey"></param>
|
||||
/// <param name="writeValue"></param>
|
||||
public static void SerializeDict<TKey, TValue>(this JsonSerializer extends, JsonWriter writer,
|
||||
IEnumerable<KeyValuePair<TKey, TValue>> items,
|
||||
Action<JsonSerializer, JsonWriter, TKey> writeKey,
|
||||
Action<JsonSerializer, JsonWriter, TValue> writeValue)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (writer == null)
|
||||
throw new ArgumentNullException("writer");
|
||||
|
||||
if (writeKey == null)
|
||||
throw new ArgumentNullException("writeKey");
|
||||
|
||||
if (writeValue == null)
|
||||
throw new ArgumentNullException("writeValue");
|
||||
|
||||
extends.SerializeArray(writer, items, (s, w, kvp) => s.SerializeKeyValuePair(w, kvp, writeKey, writeValue));
|
||||
}
|
||||
|
||||
public static void SerializeKeyValuePair<TKey, TValue>(this JsonSerializer extends, JsonWriter writer,
|
||||
KeyValuePair<TKey, TValue> kvp,
|
||||
Action<JsonSerializer, JsonWriter, TKey> writeKey,
|
||||
Action<JsonSerializer, JsonWriter, TValue> writeValue)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (writer == null)
|
||||
throw new ArgumentNullException("writer");
|
||||
|
||||
if (writeKey == null)
|
||||
throw new ArgumentNullException("writeKey");
|
||||
|
||||
if (writeValue == null)
|
||||
throw new ArgumentNullException("writeValue");
|
||||
|
||||
writer.WriteStartObject();
|
||||
{
|
||||
writer.WritePropertyName(PROPERTY_KEY);
|
||||
writeKey(extends, writer, kvp.Key);
|
||||
|
||||
writer.WritePropertyName(PROPERTY_VALUE);
|
||||
writeValue(extends, writer, kvp.Value);
|
||||
}
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
45
ICD.Common.Utils/Extensions/JsonTokenExtensions.cs
Normal file
45
ICD.Common.Utils/Extensions/JsonTokenExtensions.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ICD.Common.Utils.Extensions
|
||||
{
|
||||
public static class JsonTokenExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns true if the JsonToken respresents a single data value
|
||||
/// rather than a complex type such as an object or an array.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsPrimitive(this JsonToken extends)
|
||||
{
|
||||
switch (extends)
|
||||
{
|
||||
case JsonToken.None:
|
||||
case JsonToken.StartObject:
|
||||
case JsonToken.StartArray:
|
||||
case JsonToken.StartConstructor:
|
||||
case JsonToken.EndObject:
|
||||
case JsonToken.EndArray:
|
||||
case JsonToken.EndConstructor:
|
||||
case JsonToken.Undefined:
|
||||
return false;
|
||||
|
||||
case JsonToken.PropertyName:
|
||||
case JsonToken.Comment:
|
||||
case JsonToken.Raw:
|
||||
case JsonToken.Integer:
|
||||
case JsonToken.Float:
|
||||
case JsonToken.String:
|
||||
case JsonToken.Boolean:
|
||||
case JsonToken.Null:
|
||||
case JsonToken.Date:
|
||||
case JsonToken.Bytes:
|
||||
return true;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("extends");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
135
ICD.Common.Utils/Extensions/JsonWriterExtensions.cs
Normal file
135
ICD.Common.Utils/Extensions/JsonWriterExtensions.cs
Normal file
@@ -0,0 +1,135 @@
|
||||
using System;
|
||||
using ICD.Common.Properties;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ICD.Common.Utils.Extensions
|
||||
{
|
||||
public static class JsonWriterExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes the type value.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="type"></param>
|
||||
[PublicAPI]
|
||||
public static void WriteType(this JsonWriter extends, Type type)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (type == null)
|
||||
{
|
||||
extends.WriteNull();
|
||||
return;
|
||||
}
|
||||
|
||||
string name = type.GetMinimalName();
|
||||
extends.WriteValue(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the property name and value to the writer.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="propertyName"></param>
|
||||
/// <param name="value"></param>
|
||||
public static void WriteProperty(this JsonWriter extends, string propertyName, object value)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
extends.WritePropertyName(propertyName);
|
||||
extends.WriteValue(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the property name and value to the writer.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="propertyName"></param>
|
||||
/// <param name="value"></param>
|
||||
public static void WriteProperty(this JsonWriter extends, string propertyName, string value)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
extends.WritePropertyName(propertyName);
|
||||
extends.WriteValue(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the property name and value to the writer.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="propertyName"></param>
|
||||
/// <param name="value"></param>
|
||||
public static void WriteProperty(this JsonWriter extends, string propertyName, DateTime value)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
extends.WritePropertyName(propertyName);
|
||||
extends.WriteValue(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the property name and value to the writer.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="propertyName"></param>
|
||||
/// <param name="value"></param>
|
||||
public static void WriteProperty(this JsonWriter extends, string propertyName, bool value)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
extends.WritePropertyName(propertyName);
|
||||
extends.WriteValue(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the property name and value to the writer.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="propertyName"></param>
|
||||
/// <param name="value"></param>
|
||||
public static void WriteProperty(this JsonWriter extends, string propertyName, int value)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
extends.WritePropertyName(propertyName);
|
||||
extends.WriteValue(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the property name and value to the writer.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="propertyName"></param>
|
||||
/// <param name="value"></param>
|
||||
public static void WriteProperty(this JsonWriter extends, string propertyName, Guid value)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
extends.WritePropertyName(propertyName);
|
||||
extends.WriteValue(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the property name and value to the writer.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="propertyName"></param>
|
||||
/// <param name="value"></param>
|
||||
public static void WriteProperty(this JsonWriter extends, string propertyName, Type value)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
extends.WritePropertyName(propertyName);
|
||||
extends.WriteType(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.Comparers;
|
||||
|
||||
@@ -18,7 +17,7 @@ namespace ICD.Common.Utils.Extensions
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="items"></param>
|
||||
[PublicAPI]
|
||||
public static void AddSorted<T>(this List<T> extends, IEnumerable<T> items)
|
||||
public static void AddSorted<T>(this IList<T> extends, IEnumerable<T> items)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
@@ -37,7 +36,7 @@ namespace ICD.Common.Utils.Extensions
|
||||
/// <param name="items"></param>
|
||||
/// <param name="comparer"></param>
|
||||
[PublicAPI]
|
||||
public static void AddSorted<T>(this List<T> extends, IEnumerable<T> items, IComparer<T> comparer)
|
||||
public static void AddSorted<T>(this IList<T> extends, IEnumerable<T> items, IComparer<T> comparer)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
@@ -60,7 +59,7 @@ namespace ICD.Common.Utils.Extensions
|
||||
/// <param name="items"></param>
|
||||
/// <param name="predicate"></param>
|
||||
[PublicAPI]
|
||||
public static void AddSorted<T, TProp>(this List<T> extends, IEnumerable<T> items, Func<T, TProp> predicate)
|
||||
public static void AddSorted<T, TProp>(this IList<T> extends, IEnumerable<T> items, Func<T, TProp> predicate)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
@@ -82,7 +81,7 @@ namespace ICD.Common.Utils.Extensions
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="item"></param>
|
||||
[PublicAPI]
|
||||
public static int AddSorted<T>(this List<T> extends, T item)
|
||||
public static int AddSorted<T>(this IList<T> extends, T item)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
@@ -98,7 +97,7 @@ namespace ICD.Common.Utils.Extensions
|
||||
/// <param name="item"></param>
|
||||
/// <param name="comparer"></param>
|
||||
[PublicAPI]
|
||||
public static int AddSorted<T>(this List<T> extends, T item, IComparer<T> comparer)
|
||||
public static int AddSorted<T>(this IList<T> extends, T item, IComparer<T> comparer)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
@@ -124,7 +123,7 @@ namespace ICD.Common.Utils.Extensions
|
||||
/// <param name="item"></param>
|
||||
/// <param name="predicate"></param>
|
||||
[PublicAPI]
|
||||
public static int AddSorted<T, TProp>(this List<T> extends, T item, Func<T, TProp> predicate)
|
||||
public static int AddSorted<T, TProp>(this IList<T> extends, T item, Func<T, TProp> predicate)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
@@ -137,44 +136,40 @@ namespace ICD.Common.Utils.Extensions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pads the list to the given total length.
|
||||
/// Returns the index of the item in the list.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="totalLength"></param>
|
||||
[PublicAPI]
|
||||
public static void PadRight<T>(this List<T> extends, int totalLength)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (totalLength < 0)
|
||||
throw new ArgumentOutOfRangeException("totalLength", "totalLength must be greater or equal to 0");
|
||||
|
||||
extends.PadRight(totalLength, default(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pads the list to the given total length with the given item.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="totalLength"></param>
|
||||
/// <param name="item"></param>
|
||||
/// <param name="comparer"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static void PadRight<T>(this List<T> extends, int totalLength, T item)
|
||||
public static int BinarySearch<T>(this IList<T> extends, T item, IComparer<T> comparer)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (totalLength < 0)
|
||||
throw new ArgumentOutOfRangeException("totalLength", "totalLength must be greater or equal to 0");
|
||||
if (comparer == null)
|
||||
throw new ArgumentNullException("comparer");
|
||||
|
||||
int pad = totalLength - extends.Count;
|
||||
if (pad <= 0)
|
||||
return;
|
||||
int lo = 0;
|
||||
int hi = extends.Count - 1;
|
||||
|
||||
extends.AddRange(Enumerable.Repeat(item, pad));
|
||||
while (lo <= hi)
|
||||
{
|
||||
int i = lo + ((hi - lo) >> 1);
|
||||
int order = comparer.Compare(extends[i], item);
|
||||
|
||||
if (order == 0)
|
||||
return i;
|
||||
|
||||
if (order < 0)
|
||||
lo = i + 1;
|
||||
else
|
||||
hi = i - 1;
|
||||
}
|
||||
|
||||
return ~lo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,10 @@ namespace ICD.Common.Utils.Extensions
|
||||
sigBuilder.Append("(");
|
||||
|
||||
firstParam = true;
|
||||
|
||||
#if !SIMPLSHARP
|
||||
bool secondParam = false;
|
||||
#endif
|
||||
|
||||
foreach (ParameterInfo param in method.GetParameters())
|
||||
{
|
||||
|
||||
@@ -43,5 +43,26 @@ namespace ICD.Common.Utils.Extensions
|
||||
item = extends.Dequeue();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Peeks the next item in the queue. Returns false if the queue is empty.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
public static bool Peek<T>(this Queue<T> extends, out T item)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
item = default(T);
|
||||
|
||||
if (extends.Count == 0)
|
||||
return false;
|
||||
|
||||
item = extends.Peek();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ namespace ICD.Common.Utils.Extensions
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<T> GetCustomAttributes<T>(this ICustomAttributeProvider extends)
|
||||
where T : Attribute
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
@@ -37,7 +36,6 @@ namespace ICD.Common.Utils.Extensions
|
||||
/// <param name="inherits"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<T> GetCustomAttributes<T>(this ICustomAttributeProvider extends, bool inherits)
|
||||
where T : Attribute
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
@@ -60,7 +58,6 @@ namespace ICD.Common.Utils.Extensions
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
public static T GetCustomAttribute<T>(this ICustomAttributeProvider extends)
|
||||
where T : Attribute
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
@@ -76,7 +73,6 @@ namespace ICD.Common.Utils.Extensions
|
||||
/// <param name="inherits"></param>
|
||||
/// <returns></returns>
|
||||
public static T GetCustomAttribute<T>(this ICustomAttributeProvider extends, bool inherits)
|
||||
where T : Attribute
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
@@ -37,6 +37,9 @@ namespace ICD.Common.Utils.Extensions
|
||||
|
||||
index = thisIndex;
|
||||
first = item;
|
||||
|
||||
if (index == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return index;
|
||||
@@ -149,7 +152,31 @@ namespace ICD.Common.Utils.Extensions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the given characters from the string.
|
||||
/// Removes all occurances of the given string.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="other"></param>
|
||||
/// <returns></returns>
|
||||
public static string Remove(this string extends, string other)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
if (other == null)
|
||||
throw new ArgumentNullException("other");
|
||||
|
||||
if (string.IsNullOrEmpty(other))
|
||||
return extends;
|
||||
|
||||
int index;
|
||||
while ((index = extends.IndexOf(other, StringComparison.Ordinal)) >= 0)
|
||||
extends = extends.Remove(index, other.Length);
|
||||
|
||||
return extends;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all occurances the given characters from the string.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="characters"></param>
|
||||
@@ -162,8 +189,9 @@ namespace ICD.Common.Utils.Extensions
|
||||
|
||||
if (characters == null)
|
||||
throw new ArgumentNullException("characters");
|
||||
var cSet = characters.ToIcdHashSet();
|
||||
|
||||
return new string(extends.Except(characters).ToArray());
|
||||
return new string(extends.Where(c => !cSet.Contains(c)).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -193,5 +221,29 @@ namespace ICD.Common.Utils.Extensions
|
||||
|
||||
return extends.Contains(character.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a hashcode that is consistent between program executions.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
public static int GetStableHashCode(this string extends)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int hash1 = 5381;
|
||||
int hash2 = hash1;
|
||||
|
||||
for (int i = 0; i < extends.Length && extends[i] != '\0'; i += 2)
|
||||
{
|
||||
hash1 = ((hash1 << 5) + hash1) ^ extends[i];
|
||||
if (i == extends.Length - 1 || extends[i + 1] == '\0')
|
||||
break;
|
||||
hash2 = ((hash2 << 5) + hash2) ^ extends[i + 1];
|
||||
}
|
||||
|
||||
return hash1 + (hash2 * 1566083941);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,5 +25,48 @@ namespace ICD.Common.Utils.Extensions
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the given number of hours to the time, wrapping every 24 hours without modifying the day.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="hours"></param>
|
||||
/// <returns></returns>
|
||||
public static TimeSpan AddHoursAndWrap(this TimeSpan extends, int hours)
|
||||
{
|
||||
hours = MathUtils.Modulus(hours + extends.Hours, 24);
|
||||
return new TimeSpan(extends.Days, hours, extends.Minutes, extends.Seconds, extends.Milliseconds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the given number of hours to the time, wrapping within the current 12 hour span, without modifying the day.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="hours"></param>
|
||||
/// <returns></returns>
|
||||
public static TimeSpan AddHoursAndWrap12Hour(this TimeSpan extends, int hours)
|
||||
{
|
||||
int currentHour = extends.Hours;
|
||||
bool am = extends.Hours < 12;
|
||||
|
||||
int current12Hour = MathUtils.Modulus(currentHour, 12);
|
||||
int new12Hour = MathUtils.Modulus(current12Hour + hours, 12);
|
||||
|
||||
return am
|
||||
? new TimeSpan(extends.Days, new12Hour, extends.Minutes, extends.Seconds, extends.Milliseconds)
|
||||
: new TimeSpan(extends.Days, new12Hour + 12, extends.Minutes, extends.Seconds, extends.Milliseconds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the given number of minutes to the time, wrapping every 60 minutes without modifying the hour.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <param name="minutes"></param>
|
||||
/// <returns></returns>
|
||||
public static TimeSpan AddMinutesAndWrap(this TimeSpan extends, int minutes)
|
||||
{
|
||||
minutes = MathUtils.Modulus(minutes + extends.Minutes, 60);
|
||||
return new TimeSpan(extends.Days, extends.Hours, minutes, extends.Seconds, extends.Milliseconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,8 @@ namespace ICD.Common.Utils.Extensions
|
||||
private static readonly Dictionary<Type, Type[]> s_TypeBaseTypes;
|
||||
private static readonly Dictionary<Type, Type[]> s_TypeImmediateInterfaces;
|
||||
private static readonly Dictionary<Type, Type[]> s_TypeMinimalInterfaces;
|
||||
private static readonly Dictionary<Type, string> s_TypeToMinimalName;
|
||||
private static readonly Dictionary<Type, string> s_TypeToNameWithoutAssemblyDetails;
|
||||
|
||||
/// <summary>
|
||||
/// Static constructor.
|
||||
@@ -72,6 +74,8 @@ namespace ICD.Common.Utils.Extensions
|
||||
s_TypeBaseTypes = new Dictionary<Type, Type[]>();
|
||||
s_TypeImmediateInterfaces = new Dictionary<Type, Type[]>();
|
||||
s_TypeMinimalInterfaces = new Dictionary<Type, Type[]>();
|
||||
s_TypeToMinimalName = new Dictionary<Type, string>();
|
||||
s_TypeToNameWithoutAssemblyDetails = new Dictionary<Type, string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -158,6 +162,19 @@ namespace ICD.Common.Utils.Extensions
|
||||
.Assembly;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the type is assignable to the given type.
|
||||
/// </summary>
|
||||
/// <param name="from"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsAssignableTo<T>(this Type from)
|
||||
{
|
||||
if (from == null)
|
||||
throw new ArgumentNullException("from");
|
||||
|
||||
return from.IsAssignableTo(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the type is assignable to the given type.
|
||||
/// </summary>
|
||||
@@ -307,6 +324,127 @@ namespace ICD.Common.Utils.Extensions
|
||||
return index == -1 ? name : name.Substring(0, index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the smallest possible string representation for the given type that
|
||||
/// can be converted back to a Type via Type.GetType(string).
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetMinimalName(this Type extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
string name;
|
||||
if (!s_TypeToMinimalName.TryGetValue(extends, out name))
|
||||
{
|
||||
// Generics are a pain
|
||||
if (extends.IsGenericType)
|
||||
{
|
||||
string nameWithoutAssemblyDetails = Type.GetType(extends.FullName) == null
|
||||
? extends.GetNameWithoutAssemblyDetails()
|
||||
: extends.FullName;
|
||||
int genericStart = nameWithoutAssemblyDetails.IndexOf('[');
|
||||
if (genericStart < 0)
|
||||
{
|
||||
name = nameWithoutAssemblyDetails;
|
||||
}
|
||||
else
|
||||
{
|
||||
string genericParameterNames =
|
||||
string.Join("],[", extends.GetGenericArguments().Select(t => t.GetMinimalName()).ToArray());
|
||||
int genericEnd = nameWithoutAssemblyDetails.LastIndexOf(']');
|
||||
|
||||
name = new StringBuilder().Append(nameWithoutAssemblyDetails, 0, genericStart + 2)
|
||||
.Append(genericParameterNames)
|
||||
.Append(nameWithoutAssemblyDetails, genericEnd - 1,
|
||||
nameWithoutAssemblyDetails.Length - genericEnd + 1)
|
||||
.ToString();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
name = Type.GetType(extends.FullName) == null
|
||||
? extends.GetNameWithoutAssemblyDetails()
|
||||
: extends.FullName;
|
||||
}
|
||||
|
||||
s_TypeToMinimalName[extends] = name;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the string representation for the type.
|
||||
/// </summary>
|
||||
/// <param name="extends"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetNameWithoutAssemblyDetails(this Type extends)
|
||||
{
|
||||
if (extends == null)
|
||||
throw new ArgumentNullException("extends");
|
||||
|
||||
string name;
|
||||
if (!s_TypeToNameWithoutAssemblyDetails.TryGetValue(extends, out name))
|
||||
{
|
||||
name = RemoveAssemblyDetails(extends.AssemblyQualifiedName);
|
||||
s_TypeToNameWithoutAssemblyDetails[extends] = name;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Taken from Newtonsoft.Json.Utilities.ReflectionUtils
|
||||
/// Removes the assembly details from a type assembly qualified name.
|
||||
/// </summary>
|
||||
/// <param name="fullyQualifiedTypeName"></param>
|
||||
/// <returns></returns>
|
||||
private static string RemoveAssemblyDetails(string fullyQualifiedTypeName)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
// loop through the type name and filter out qualified assembly details from nested type names
|
||||
bool writingAssemblyName = false;
|
||||
bool skippingAssemblyDetails = false;
|
||||
foreach (char current in fullyQualifiedTypeName)
|
||||
{
|
||||
switch (current)
|
||||
{
|
||||
case '[':
|
||||
writingAssemblyName = false;
|
||||
skippingAssemblyDetails = false;
|
||||
builder.Append(current);
|
||||
break;
|
||||
case ']':
|
||||
writingAssemblyName = false;
|
||||
skippingAssemblyDetails = false;
|
||||
builder.Append(current);
|
||||
break;
|
||||
case ',':
|
||||
if (!writingAssemblyName)
|
||||
{
|
||||
writingAssemblyName = true;
|
||||
builder.Append(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
skippingAssemblyDetails = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (!skippingAssemblyDetails)
|
||||
{
|
||||
builder.Append(current);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type name as it would appear in code.
|
||||
/// </summary>
|
||||
|
||||
1047
ICD.Common.Utils/Globalization/IcdCultureInfo.cs
Normal file
1047
ICD.Common.Utils/Globalization/IcdCultureInfo.cs
Normal file
File diff suppressed because it is too large
Load Diff
17
ICD.Common.Utils/GuidUtils.cs
Normal file
17
ICD.Common.Utils/GuidUtils.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
|
||||
namespace ICD.Common.Utils
|
||||
{
|
||||
public static class GuidUtils
|
||||
{
|
||||
public static Guid GenerateSeeded(int seed)
|
||||
{
|
||||
Random seeded = new Random(seed);
|
||||
byte[] bytes = new byte[16];
|
||||
|
||||
seeded.NextBytes(bytes);
|
||||
|
||||
return new Guid(bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,11 +39,16 @@
|
||||
<None Remove="Properties\ControlSystem.cfg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Data.SQLite" Version="2.1.0" />
|
||||
<PackageReference Include="Microsoft.Data.SQLite" Version="2.2.6" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="2.1.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||
<PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" />
|
||||
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="CultureInfo.sqlite">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -75,8 +75,9 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Attributes\AbstractIcdAttribute.cs" />
|
||||
<Compile Include="Attributes\IIcdAttribute.cs" />
|
||||
<Compile Include="Attributes\RangeAttribute.cs" />
|
||||
<Compile Include="Collections\BiDictionary.cs" />
|
||||
<Compile Include="Collections\AsyncEventQueue.cs" />
|
||||
<Compile Include="Collections\IcdOrderedDictionary.cs" />
|
||||
<Compile Include="Collections\PriorityQueue.cs" />
|
||||
<Compile Include="Collections\RateLimitedEventQueue.cs" />
|
||||
@@ -85,9 +86,11 @@
|
||||
<Compile Include="Comparers\PredicateComparer.cs" />
|
||||
<Compile Include="Comparers\SequenceComparer.cs" />
|
||||
<Compile Include="ConsoleColor.cs" />
|
||||
<Compile Include="DateTimeUtils.cs" />
|
||||
<Compile Include="Email\EmailClient.cs" />
|
||||
<Compile Include="Email\eMailErrorCode.cs" />
|
||||
<Compile Include="Email\EmailStringCollection.cs" />
|
||||
<Compile Include="Email\EmailValidation.cs" />
|
||||
<Compile Include="EncodingUtils.cs" />
|
||||
<Compile Include="Csv\CsvWriter.cs" />
|
||||
<Compile Include="Csv\CsvWriterSettings.cs" />
|
||||
@@ -101,21 +104,31 @@
|
||||
<Compile Include="EventArguments\StringEventArgs.cs" />
|
||||
<Compile Include="EventArguments\UShortEventArgs.cs" />
|
||||
<Compile Include="EventArguments\XmlRecursionEventArgs.cs" />
|
||||
<None Include="CultureInfo.sqlite">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="ObfuscationSettings.cs" />
|
||||
<Compile Include="Extensions\BoolExtensions.cs" />
|
||||
<Compile Include="Extensions\ByteExtensions.cs" />
|
||||
<Compile Include="Extensions\CultureInfoExtensions.cs" />
|
||||
<Compile Include="Extensions\DayOfWeekExtensions.cs" />
|
||||
<Compile Include="Extensions\JsonSerializerExtensions.cs" />
|
||||
<Compile Include="Extensions\JsonTokenExtensions.cs" />
|
||||
<Compile Include="Extensions\JsonWriterExtensions.cs" />
|
||||
<Compile Include="Extensions\ListExtensions.cs" />
|
||||
<Compile Include="Comparers\PredicateEqualityComparer.cs" />
|
||||
<Compile Include="Extensions\MethodInfoExtensions.cs" />
|
||||
<Compile Include="Extensions\ParameterInfoExtensions.cs" />
|
||||
<Compile Include="Extensions\UriExtensions.cs" />
|
||||
<Compile Include="Extensions\UshortExtensions.cs" />
|
||||
<Compile Include="Extensions\UShortExtensions.cs" />
|
||||
<Compile Include="Globalization\IcdCultureInfo.cs" />
|
||||
<Compile Include="GuidUtils.cs" />
|
||||
<Compile Include="IcdUriBuilder.cs" />
|
||||
<Compile Include="IO\Compression\IcdZipEntry.cs" />
|
||||
<Compile Include="IO\IcdBinaryReader.cs" />
|
||||
<Compile Include="IO\eSeekOrigin.cs" />
|
||||
<Compile Include="IO\IcdStreamWriter.cs" />
|
||||
<Compile Include="Json\ToStringJsonConverter.cs" />
|
||||
<Compile Include="ProcessorUtils.SimplSharp.cs" />
|
||||
<Compile Include="ProcessorUtils.Standard.cs" />
|
||||
<Compile Include="ProgramUtils.SimplSharp.cs" />
|
||||
@@ -153,7 +166,7 @@
|
||||
<Compile Include="Extensions\EnumerableExtensions.cs" />
|
||||
<Compile Include="Extensions\EnumExtensions.cs" />
|
||||
<Compile Include="Extensions\EventHandlerExtensions.cs" />
|
||||
<Compile Include="Extensions\JsonExtensions.cs" />
|
||||
<Compile Include="Extensions\JsonReaderExtensions.cs" />
|
||||
<Compile Include="Extensions\QueueExtensions.cs" />
|
||||
<Compile Include="Extensions\ReflectionExtensions.cs" />
|
||||
<Compile Include="Extensions\StringBuilderExtensions.cs" />
|
||||
@@ -184,6 +197,7 @@
|
||||
<Compile Include="SafeCriticalSection.SimplSharp.cs" />
|
||||
<Compile Include="SafeCriticalSection.Standard.cs" />
|
||||
<Compile Include="SafeMutex.cs" />
|
||||
<Compile Include="SPlusUtils.cs" />
|
||||
<Compile Include="Sqlite\eDbType.cs" />
|
||||
<Compile Include="Sqlite\IcdDbDataReader.cs" />
|
||||
<Compile Include="Sqlite\IcdSqliteCommand.cs" />
|
||||
@@ -201,6 +215,7 @@
|
||||
<Compile Include="Timers\Repeater.cs" />
|
||||
<Compile Include="Timers\SafeTimer.cs" />
|
||||
<Compile Include="TryUtils.cs" />
|
||||
<Compile Include="UriQueryBuilder.cs" />
|
||||
<Compile Include="UriUtils.cs" />
|
||||
<Compile Include="Xml\AbstractGenericXmlConverter.cs" />
|
||||
<Compile Include="Xml\AbstractXmlConverter.cs" />
|
||||
@@ -210,7 +225,6 @@
|
||||
<Compile Include="Xml\IcdXmlException.cs" />
|
||||
<Compile Include="Xml\IcdXmlReader.cs" />
|
||||
<Compile Include="Xml\IcdXmlTextWriter.cs" />
|
||||
<Compile Include="Xml\IcdXmlAttribute.cs" />
|
||||
<Compile Include="Xml\IXmlConverter.cs" />
|
||||
<Compile Include="Xml\XmlConverterAttribute.cs" />
|
||||
<Compile Include="Xml\XmlReaderExtensions.cs" />
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#if SIMPLSHARP
|
||||
using Crestron.SimplSharp.CrestronIO;
|
||||
#else
|
||||
using ICD.Common.Utils.Extensions;
|
||||
using System.IO;
|
||||
using Microsoft.DotNet.PlatformAbstractions;
|
||||
#endif
|
||||
@@ -19,6 +20,19 @@ namespace ICD.Common.Utils.IO
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This gets the application root directory for Crestron systems
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GetApplicationRootDirectory()
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
return Directory.GetApplicationRootDirectory();
|
||||
#else
|
||||
return Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetPath());
|
||||
#endif
|
||||
}
|
||||
|
||||
public static bool Exists(string path)
|
||||
{
|
||||
if (path == null)
|
||||
|
||||
@@ -17,5 +17,10 @@ namespace ICD.Common.Utils.IO
|
||||
public IcdStreamWriter(StreamWriter baseStreamWriter) : base(baseStreamWriter)
|
||||
{
|
||||
}
|
||||
|
||||
public void WriteLine(string value)
|
||||
{
|
||||
WrappedStreamWriter.WriteLine(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.EventArguments;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
#if SIMPLSHARP
|
||||
using Crestron.SimplSharp;
|
||||
#else
|
||||
@@ -18,6 +20,8 @@ namespace ICD.Common.Utils
|
||||
Administrator = 2
|
||||
}
|
||||
|
||||
public static event EventHandler<StringEventArgs> OnConsolePrint;
|
||||
|
||||
/// <summary>
|
||||
/// Wraps CrestronConsole.ConsoleCommandResponse for S+ compatibility.
|
||||
/// </summary>
|
||||
@@ -41,26 +45,34 @@ namespace ICD.Common.Utils
|
||||
message = string.Format(message, args);
|
||||
|
||||
#if SIMPLSHARP
|
||||
try
|
||||
if (IcdEnvironment.RuntimeEnvironment == IcdEnvironment.eRuntimeEnvironment.SimplSharpPro)
|
||||
{
|
||||
CrestronConsole.ConsoleCommandResponse(message);
|
||||
try
|
||||
{
|
||||
|
||||
CrestronConsole.ConsoleCommandResponse(message);
|
||||
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
PrintLine(message);
|
||||
}
|
||||
return;
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
Print(message);
|
||||
}
|
||||
#else
|
||||
Print(message, args);
|
||||
#endif
|
||||
|
||||
PrintLine(message);
|
||||
}
|
||||
|
||||
public static void PrintLine(string message)
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
CrestronConsole.PrintLine(message);
|
||||
if (IcdEnvironment.RuntimeEnvironment != IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono)
|
||||
CrestronConsole.PrintLine(message);
|
||||
#else
|
||||
Console.WriteLine(message);
|
||||
#endif
|
||||
OnConsolePrint.Raise(null, new StringEventArgs(message + IcdEnvironment.NewLine));
|
||||
}
|
||||
|
||||
public static void PrintLine(string message, params object[] args)
|
||||
@@ -90,10 +102,12 @@ namespace ICD.Common.Utils
|
||||
public static void Print(string message)
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
CrestronConsole.Print(message);
|
||||
if (IcdEnvironment.RuntimeEnvironment != IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono)
|
||||
CrestronConsole.Print(message);
|
||||
#else
|
||||
Console.Write(message);
|
||||
#endif
|
||||
OnConsolePrint.Raise(null, new StringEventArgs(message));
|
||||
}
|
||||
|
||||
public static void Print(string message, params object[] args)
|
||||
@@ -123,6 +137,10 @@ namespace ICD.Common.Utils
|
||||
public static bool SendControlSystemCommand(string command, ref string result)
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
// No console on VC4
|
||||
if (IcdEnvironment.RuntimeEnvironment == IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono)
|
||||
return false;
|
||||
|
||||
return CrestronConsole.SendControlSystemCommand(command, ref result);
|
||||
#else
|
||||
return false;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#if SIMPLSHARP
|
||||
using ICD.Common.Utils.Extensions;
|
||||
#if SIMPLSHARP
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Crestron.SimplSharp;
|
||||
@@ -12,7 +13,12 @@ namespace ICD.Common.Utils
|
||||
|
||||
public static eRuntimeEnvironment RuntimeEnvironment
|
||||
{
|
||||
get { return GetRuntimeEnvironment(CrestronEnvironment.RuntimeEnvironment); }
|
||||
get
|
||||
{
|
||||
return CrestronEnvironment.DevicePlatform == eDevicePlatform.Server
|
||||
? eRuntimeEnvironment.SimplSharpProMono
|
||||
: GetRuntimeEnvironment(CrestronEnvironment.RuntimeEnvironment);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -25,9 +31,36 @@ namespace ICD.Common.Utils
|
||||
{
|
||||
const CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET param =
|
||||
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS;
|
||||
const EthernetAdapterType type = EthernetAdapterType.EthernetLANAdapter;
|
||||
short id = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(type);
|
||||
yield return CrestronEthernetHelper.GetEthernetParameter(param, id);
|
||||
const EthernetAdapterType primaryType = EthernetAdapterType.EthernetLANAdapter;
|
||||
const EthernetAdapterType secondaryType = EthernetAdapterType.EthernetLAN2Adapter;
|
||||
|
||||
string address1 = null;
|
||||
|
||||
try
|
||||
{
|
||||
short id = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(primaryType);
|
||||
address1 = CrestronEthernetHelper.GetEthernetParameter(param, id);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(address1))
|
||||
yield return address1;
|
||||
|
||||
string address2 = null;
|
||||
|
||||
try
|
||||
{
|
||||
short adapter2Type = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(secondaryType);
|
||||
address2 = CrestronEthernetHelper.GetEthernetParameter(param, adapter2Type);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(address2))
|
||||
yield return address2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,9 +74,104 @@ namespace ICD.Common.Utils
|
||||
{
|
||||
const CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET param =
|
||||
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS;
|
||||
const EthernetAdapterType primaryType = EthernetAdapterType.EthernetLANAdapter;
|
||||
const EthernetAdapterType secondaryType = EthernetAdapterType.EthernetLAN2Adapter;
|
||||
|
||||
string macAddress1 = null;
|
||||
|
||||
try
|
||||
{
|
||||
short id = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(primaryType);
|
||||
macAddress1 = CrestronEthernetHelper.GetEthernetParameter(param, id);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(macAddress1))
|
||||
yield return macAddress1;
|
||||
|
||||
string macAddress2 = null;
|
||||
|
||||
try
|
||||
{
|
||||
short id = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(secondaryType);
|
||||
macAddress2 = CrestronEthernetHelper.GetEthernetParameter(param, id);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(macAddress2))
|
||||
yield return macAddress2;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dhcp status of the processor.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public static string DhcpStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
const CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET param =
|
||||
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_DHCP_STATE;
|
||||
const EthernetAdapterType type = EthernetAdapterType.EthernetLANAdapter;
|
||||
short id = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(type);
|
||||
yield return CrestronEthernetHelper.GetEthernetParameter(param, id);
|
||||
|
||||
try
|
||||
{
|
||||
short id = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(type);
|
||||
return CrestronEthernetHelper.GetEthernetParameter(param, id);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hostname of the processor.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public static IEnumerable<string> Hostname
|
||||
{
|
||||
get
|
||||
{
|
||||
const CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET param =
|
||||
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME;
|
||||
const EthernetAdapterType primaryType = EthernetAdapterType.EthernetLANAdapter;
|
||||
const EthernetAdapterType secondaryType = EthernetAdapterType.EthernetLAN2Adapter;
|
||||
|
||||
string address1 = null;
|
||||
|
||||
try
|
||||
{
|
||||
short id = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(primaryType);
|
||||
address1 = CrestronEthernetHelper.GetEthernetParameter(param, id);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(address1))
|
||||
yield return address1;
|
||||
|
||||
string address2 = null;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
short adapter2Type = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(secondaryType);
|
||||
address2 = CrestronEthernetHelper.GetEthernetParameter(param, adapter2Type);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(address2))
|
||||
yield return address2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +191,18 @@ namespace ICD.Common.Utils
|
||||
return CrestronEnvironment.GetLocalTime();
|
||||
}
|
||||
|
||||
public static void SetLocalTime(DateTime localTime)
|
||||
{
|
||||
CrestronEnvironment.SetTimeAndDate((ushort)localTime.Hour,
|
||||
(ushort)localTime.Minute,
|
||||
(ushort)localTime.Second,
|
||||
(ushort)localTime.Month,
|
||||
(ushort)localTime.Day,
|
||||
(ushort)localTime.Year);
|
||||
|
||||
OnSystemDateTimeChanged.Raise(null);
|
||||
}
|
||||
|
||||
public static eEthernetEventType GetEthernetEventType(Crestron.SimplSharp.eEthernetEventType type)
|
||||
{
|
||||
switch (type)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -13,11 +14,6 @@ namespace ICD.Common.Utils
|
||||
{
|
||||
public static string NewLine { get { return Environment.NewLine; } }
|
||||
|
||||
public static DateTime GetLocalTime()
|
||||
{
|
||||
return DateTime.Now;
|
||||
}
|
||||
|
||||
public static eRuntimeEnvironment RuntimeEnvironment { get { return eRuntimeEnvironment.Standard; } }
|
||||
|
||||
/// <summary>
|
||||
@@ -53,6 +49,48 @@ namespace ICD.Common.Utils
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dhcp status of the processor.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public static string DhcpStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
bool enabled =
|
||||
NetworkInterface.GetAllNetworkInterfaces()
|
||||
.Where(ni => ni.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 ||
|
||||
ni.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
|
||||
.Select(ni => ni.GetIPProperties().GetIPv4Properties().IsDhcpEnabled)
|
||||
.FirstOrDefault();
|
||||
|
||||
return enabled.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hostname of the processor.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public static IEnumerable<string> Hostname { get { yield return Dns.GetHostName(); } }
|
||||
|
||||
public static DateTime GetLocalTime()
|
||||
{
|
||||
return DateTime.Now;
|
||||
}
|
||||
|
||||
public static void SetLocalTime(DateTime localTime)
|
||||
{
|
||||
#if DEBUG
|
||||
IcdConsole.PrintLine(eConsoleColor.Magenta, "Debug Build - Skipped setting local time to {0}",
|
||||
localTime.ToString("s"));
|
||||
#else
|
||||
throw new NotSupportedException();
|
||||
|
||||
OnSystemDateTimeChanged.Raise(null);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts 12 digit address to XX:XX:XX... format
|
||||
/// </summary>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
|
||||
namespace ICD.Common.Utils
|
||||
{
|
||||
@@ -11,6 +13,7 @@ namespace ICD.Common.Utils
|
||||
{
|
||||
SimplSharp,
|
||||
SimplSharpPro,
|
||||
SimplSharpProMono,
|
||||
Standard
|
||||
}
|
||||
|
||||
@@ -53,5 +56,46 @@ namespace ICD.Common.Utils
|
||||
public static event ProgramStatusCallback OnProgramStatusEvent;
|
||||
|
||||
public static event EthernetEventCallback OnEthernetEvent;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when the program has completed initialization.
|
||||
/// </summary>
|
||||
public static event EventHandler OnProgramInitializationComplete;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when the system date/time has been set.
|
||||
/// </summary>
|
||||
public static event EventHandler OnSystemDateTimeChanged;
|
||||
|
||||
private static readonly SafeCriticalSection s_ProgramInitializationSection = new SafeCriticalSection();
|
||||
private static bool s_ProgramInitializationComplete;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the program has been flagged as completely initialized.
|
||||
/// </summary>
|
||||
public static bool ProgramIsInitialized { get { return s_ProgramInitializationSection.Execute(() => s_ProgramInitializationComplete); } }
|
||||
|
||||
/// <summary>
|
||||
/// Called by the program entry point to signify that the program initialization is complete.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public static void SetProgramInitializationComplete()
|
||||
{
|
||||
s_ProgramInitializationSection.Enter();
|
||||
|
||||
try
|
||||
{
|
||||
if (s_ProgramInitializationComplete)
|
||||
return;
|
||||
|
||||
s_ProgramInitializationComplete = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
s_ProgramInitializationSection.Leave();
|
||||
}
|
||||
|
||||
OnProgramInitializationComplete.Raise(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,12 +26,13 @@ namespace ICD.Common.Utils
|
||||
try
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
message = FormatConsoleColor(message, ConsoleColorExtensions.CONSOLE_RED);
|
||||
message = eConsoleColor.Red.FormatAnsi(message);
|
||||
ErrorLog.Error(message);
|
||||
#else
|
||||
System.Console.ForegroundColor = ConsoleColor.Red;
|
||||
System.Console.Error.WriteLine(message);
|
||||
System.Console.ResetColor();
|
||||
Console.Write("Error - {0} - ", IcdEnvironment.GetLocalTime());
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.Error.WriteLine(message);
|
||||
Console.ResetColor();
|
||||
#endif
|
||||
}
|
||||
finally
|
||||
@@ -54,12 +55,13 @@ namespace ICD.Common.Utils
|
||||
try
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
message = FormatConsoleColor(message, ConsoleColorExtensions.CONSOLE_YELLOW);
|
||||
message = eConsoleColor.Yellow.FormatAnsi(message);
|
||||
ErrorLog.Warn(message);
|
||||
#else
|
||||
System.Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
System.Console.Error.WriteLine(message);
|
||||
System.Console.ResetColor();
|
||||
Console.Write("Warn - {0} - ", IcdEnvironment.GetLocalTime());
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
Console.Error.WriteLine(message);
|
||||
Console.ResetColor();
|
||||
#endif
|
||||
}
|
||||
finally
|
||||
@@ -82,12 +84,13 @@ namespace ICD.Common.Utils
|
||||
try
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
message = FormatConsoleColor(message, ConsoleColorExtensions.CONSOLE_BLUE);
|
||||
message = eConsoleColor.Blue.FormatAnsi(message);
|
||||
ErrorLog.Notice(message);
|
||||
#else
|
||||
System.Console.ForegroundColor = ConsoleColor.Blue;
|
||||
System.Console.Error.WriteLine(message);
|
||||
System.Console.ResetColor();
|
||||
Console.Write("Notice - {0} - ", IcdEnvironment.GetLocalTime());
|
||||
Console.ForegroundColor = ConsoleColor.Blue;
|
||||
Console.Error.WriteLine(message);
|
||||
Console.ResetColor();
|
||||
#endif
|
||||
}
|
||||
finally
|
||||
@@ -110,12 +113,13 @@ namespace ICD.Common.Utils
|
||||
try
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
message = FormatConsoleColor(message, ConsoleColorExtensions.CONSOLE_GREEN);
|
||||
message = eConsoleColor.Green.FormatAnsi(message);
|
||||
ErrorLog.Ok(message);
|
||||
#else
|
||||
System.Console.ForegroundColor = ConsoleColor.Green;
|
||||
System.Console.Error.WriteLine(message);
|
||||
System.Console.ResetColor();
|
||||
Console.Write("OK - {0} - ", IcdEnvironment.GetLocalTime());
|
||||
Console.ForegroundColor = ConsoleColor.Green;
|
||||
Console.Error.WriteLine(message);
|
||||
Console.ResetColor();
|
||||
#endif
|
||||
}
|
||||
finally
|
||||
@@ -138,14 +142,15 @@ namespace ICD.Common.Utils
|
||||
try
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
message = FormatConsoleColor(message, ConsoleColorExtensions.CONSOLE_YELLOW_ON_RED_BACKGROUND);
|
||||
message = eConsoleColor.YellowOnRed.FormatAnsi(message);
|
||||
ErrorLog.Exception(message, ex);
|
||||
#else
|
||||
System.Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
System.Console.BackgroundColor = ConsoleColor.Red;
|
||||
System.Console.Error.WriteLine("{0}: {1}", ex.GetType().Name, message);
|
||||
System.Console.ResetColor();
|
||||
System.Console.Error.WriteLine(ex.StackTrace);
|
||||
Console.Write("Except - {0} - ", IcdEnvironment.GetLocalTime());
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
Console.BackgroundColor = ConsoleColor.Red;
|
||||
Console.Error.WriteLine("{0}: {1}", ex.GetType().Name, message);
|
||||
Console.ResetColor();
|
||||
Console.Error.WriteLine(ex.StackTrace);
|
||||
#endif
|
||||
}
|
||||
finally
|
||||
@@ -169,12 +174,13 @@ namespace ICD.Common.Utils
|
||||
try
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
message = FormatConsoleColor(message, ConsoleColorExtensions.CONSOLE_CYAN);
|
||||
message = eConsoleColor.Cyan.FormatAnsi(message);
|
||||
ErrorLog.Info(message);
|
||||
#else
|
||||
System.Console.ForegroundColor = ConsoleColor.Cyan;
|
||||
System.Console.Error.WriteLine(message);
|
||||
System.Console.ResetColor();
|
||||
Console.Write("Info - {0} - ", IcdEnvironment.GetLocalTime());
|
||||
Console.ForegroundColor = ConsoleColor.Cyan;
|
||||
Console.Error.WriteLine(message);
|
||||
Console.ResetColor();
|
||||
#endif
|
||||
}
|
||||
finally
|
||||
@@ -188,16 +194,5 @@ namespace ICD.Common.Utils
|
||||
{
|
||||
Info(string.Format(message, args));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats the text with the given console color.
|
||||
/// </summary>
|
||||
/// <param name="text"></param>
|
||||
/// <param name="color"></param>
|
||||
/// <returns></returns>
|
||||
private static string FormatConsoleColor(string text, string color)
|
||||
{
|
||||
return string.Format("{0}{1}{2}", color, text, ConsoleColorExtensions.CONSOLE_RESET);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
using System;
|
||||
#if !SIMPLSHARP
|
||||
using System.Linq;
|
||||
#endif
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
|
||||
namespace ICD.Common.Utils
|
||||
@@ -9,6 +13,8 @@ namespace ICD.Common.Utils
|
||||
/// </summary>
|
||||
public sealed class IcdUriBuilder
|
||||
{
|
||||
private string m_Query;
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
@@ -39,7 +45,7 @@ namespace ICD.Common.Utils
|
||||
/// <summary>
|
||||
/// Gets or sets any query information included in the URI.
|
||||
/// </summary>
|
||||
public string Query { get; set; }
|
||||
public string Query { get { return string.IsNullOrEmpty(m_Query) ? string.Empty : "?" + m_Query; } set { m_Query = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the scheme name of the URI.
|
||||
@@ -62,6 +68,7 @@ namespace ICD.Common.Utils
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
public IcdUriBuilder()
|
||||
: this(new Uri("http://localhost/"))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -80,6 +87,9 @@ namespace ICD.Common.Utils
|
||||
/// <param name="uri"></param>
|
||||
public IcdUriBuilder(Uri uri)
|
||||
{
|
||||
if (uri == null)
|
||||
throw new ArgumentNullException("uri");
|
||||
|
||||
if (!uri.IsAbsoluteUri)
|
||||
uri = new Uri(Uri.UriSchemeHttp + Uri.SchemeDelimiter + uri);
|
||||
|
||||
@@ -88,7 +98,7 @@ namespace ICD.Common.Utils
|
||||
Password = uri.GetPassword();
|
||||
Path = uri.AbsolutePath;
|
||||
Port = (ushort)uri.Port;
|
||||
Query = uri.Query;
|
||||
Query = uri.Query.TrimStart('?');
|
||||
Scheme = uri.Scheme;
|
||||
UserName = uri.GetUserName();
|
||||
}
|
||||
@@ -99,20 +109,20 @@ namespace ICD.Common.Utils
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
{
|
||||
// URI = scheme:[//authority]path[?query][#fragment]
|
||||
// URI = [scheme://][authority]path[?query][#fragment]
|
||||
// authority = [userinfo@]host[:port]
|
||||
// userinfo = username[:password]
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
// Scheme
|
||||
string scheme = string.IsNullOrEmpty(Scheme) ? Uri.UriSchemeHttp : Scheme;
|
||||
builder.Append(scheme);
|
||||
builder.Append(':');
|
||||
if (!string.IsNullOrEmpty(Scheme))
|
||||
{
|
||||
builder.Append(Scheme);
|
||||
builder.Append("://");
|
||||
}
|
||||
|
||||
// Authority
|
||||
builder.Append("//");
|
||||
|
||||
if (!string.IsNullOrEmpty(UserName))
|
||||
{
|
||||
builder.Append(UserName);
|
||||
@@ -126,8 +136,7 @@ namespace ICD.Common.Utils
|
||||
builder.Append('@');
|
||||
}
|
||||
|
||||
string host = string.IsNullOrEmpty(Host) ? "localhost" : Host;
|
||||
builder.Append(host);
|
||||
builder.Append(Host);
|
||||
|
||||
if (Port != 0)
|
||||
{
|
||||
@@ -142,10 +151,7 @@ namespace ICD.Common.Utils
|
||||
|
||||
// Query
|
||||
if (!string.IsNullOrEmpty(Query))
|
||||
{
|
||||
builder.Append('?');
|
||||
builder.Append(Query);
|
||||
}
|
||||
|
||||
// Fragment
|
||||
if (!string.IsNullOrEmpty(Fragment))
|
||||
@@ -155,6 +161,125 @@ namespace ICD.Common.Utils
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Appends the given path to the current path, ensuring only one separator between parts.
|
||||
/// </summary>
|
||||
/// <param name="parts"></param>
|
||||
/// <returns></returns>
|
||||
public void AppendPath(params string[] parts)
|
||||
{
|
||||
parts = parts.Prepend(Path).ToArray(parts.Length + 1);
|
||||
Path = Combine(parts);
|
||||
}
|
||||
|
||||
#region Flurl
|
||||
|
||||
// The following region is taken from Flurl https://github.com/tmenier/Flurl
|
||||
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Todd Menier
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Basically a Path.Combine for URLs. Ensures exactly one '/' seperates each segment,
|
||||
/// and exactly on '&' seperates each query parameter.
|
||||
/// URL-encodes illegal characters but not reserved characters.
|
||||
/// </summary>
|
||||
/// <param name="parts">URL parts to combine.</param>
|
||||
public static string Combine(params string[] parts)
|
||||
{
|
||||
if (parts == null)
|
||||
throw new ArgumentNullException("parts");
|
||||
|
||||
string result = "";
|
||||
bool inQuery = false, inFragment = false;
|
||||
|
||||
foreach (var part in parts)
|
||||
{
|
||||
if (string.IsNullOrEmpty(part))
|
||||
continue;
|
||||
|
||||
if (result.EndsWith("?") || part.StartsWith("?"))
|
||||
result = CombineEnsureSingleSeperator(result, part, '?');
|
||||
else if (result.EndsWith("#") || part.StartsWith("#"))
|
||||
result = CombineEnsureSingleSeperator(result, part, '#');
|
||||
else if (inFragment)
|
||||
result += part;
|
||||
else if (inQuery)
|
||||
result = CombineEnsureSingleSeperator(result, part, '&');
|
||||
else
|
||||
result = CombineEnsureSingleSeperator(result, part, '/');
|
||||
|
||||
if (part.Contains("#"))
|
||||
{
|
||||
inQuery = false;
|
||||
inFragment = true;
|
||||
}
|
||||
else if (!inFragment && part.Contains("?"))
|
||||
{
|
||||
inQuery = true;
|
||||
}
|
||||
}
|
||||
return EncodeIllegalCharacters(result, false);
|
||||
}
|
||||
|
||||
private static string CombineEnsureSingleSeperator(string a, string b, char seperator)
|
||||
{
|
||||
if (string.IsNullOrEmpty(a)) return b;
|
||||
if (string.IsNullOrEmpty(b)) return a;
|
||||
return a.TrimEnd(seperator) + seperator + b.TrimStart(seperator);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// URL-encodes characters in a string that are neither reserved nor unreserved. Avoids encoding reserved characters such as '/' and '?'. Avoids encoding '%' if it begins a %-hex-hex sequence (i.e. avoids double-encoding).
|
||||
/// </summary>
|
||||
/// <param name="s">The string to encode.</param>
|
||||
/// <param name="encodeSpaceAsPlus">If true, spaces will be encoded as + signs. Otherwise, they'll be encoded as %20.</param>
|
||||
/// <returns>The encoded URL.</returns>
|
||||
private static string EncodeIllegalCharacters(string s, bool encodeSpaceAsPlus) {
|
||||
if (string.IsNullOrEmpty(s))
|
||||
return s;
|
||||
|
||||
if (encodeSpaceAsPlus)
|
||||
s = s.Replace(" ", "+");
|
||||
|
||||
// Uri.EscapeUriString mostly does what we want - encodes illegal characters only - but it has a quirk
|
||||
// in that % isn't illegal if it's the start of a %-encoded sequence https://stackoverflow.com/a/47636037/62600
|
||||
|
||||
// no % characters, so avoid the regex overhead
|
||||
if (!s.Contains("%"))
|
||||
return Uri.EscapeUriString(s);
|
||||
|
||||
// pick out all %-hex-hex matches and avoid double-encoding
|
||||
return Regex.Replace(s, "(.*?)((%[0-9A-Fa-f]{2})|$)", c => {
|
||||
var a = c.Groups[1].Value; // group 1 is a sequence with no %-encoding - encode illegal characters
|
||||
var b = c.Groups[2].Value; // group 2 is a valid 3-character %-encoded sequence - leave it alone!
|
||||
return Uri.EscapeUriString(a) + b;
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ICD.Common.Utils.Json
|
||||
@@ -10,7 +11,10 @@ namespace ICD.Common.Utils.Json
|
||||
/// Creates a new instance of T.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected abstract T Instantiate();
|
||||
protected virtual T Instantiate()
|
||||
{
|
||||
return ReflectionUtils.CreateInstance<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the JSON representation of the object.
|
||||
@@ -26,12 +30,6 @@ namespace ICD.Common.Utils.Json
|
||||
if (serializer == null)
|
||||
throw new ArgumentNullException("serializer");
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNull();
|
||||
return;
|
||||
}
|
||||
|
||||
WriteJson(writer, (T)value, serializer);
|
||||
}
|
||||
|
||||
@@ -50,12 +48,25 @@ namespace ICD.Common.Utils.Json
|
||||
if (serializer == null)
|
||||
throw new ArgumentNullException("serializer");
|
||||
|
||||
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||
if (value == null)
|
||||
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||
{
|
||||
writer.WriteNull();
|
||||
return;
|
||||
}
|
||||
|
||||
WriteObject(writer, value, serializer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override to write the object value to the writer.
|
||||
/// </summary>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="serializer"></param>
|
||||
protected virtual void WriteObject(JsonWriter writer, T value, JsonSerializer serializer)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
{
|
||||
WriteProperties(writer, value, serializer);
|
||||
@@ -92,7 +103,10 @@ namespace ICD.Common.Utils.Json
|
||||
if (serializer == null)
|
||||
throw new ArgumentNullException("serializer");
|
||||
|
||||
return ReadJson(reader, (T)existingValue, serializer);
|
||||
// Casting null blows up struct casts
|
||||
T cast = (T)(existingValue ?? default(T));
|
||||
|
||||
return ReadJson(reader, cast, serializer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -113,30 +127,26 @@ namespace ICD.Common.Utils.Json
|
||||
if (serializer == null)
|
||||
throw new ArgumentNullException("serializer");
|
||||
|
||||
T output = default(T);
|
||||
bool instantiated = false;
|
||||
if (reader.TokenType == JsonToken.Null)
|
||||
return default(T);
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader.TokenType == JsonToken.Null || reader.TokenType == JsonToken.EndObject)
|
||||
break;
|
||||
if (reader.TokenType != JsonToken.StartObject)
|
||||
throw new FormatException(string.Format("Expected {0} got {1}", JsonToken.StartObject, reader.TokenType));
|
||||
|
||||
if (!instantiated)
|
||||
{
|
||||
instantiated = true;
|
||||
output = Instantiate();
|
||||
}
|
||||
return ReadObject(reader, serializer);
|
||||
}
|
||||
|
||||
// Get the property
|
||||
if (reader.TokenType != JsonToken.PropertyName)
|
||||
continue;
|
||||
string property = (string)reader.Value;
|
||||
/// <summary>
|
||||
/// Override to handle deserialization of the current StartObject token.
|
||||
/// </summary>
|
||||
/// <param name="reader"></param>
|
||||
/// <param name="serializer"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual T ReadObject(JsonReader reader, JsonSerializer serializer)
|
||||
{
|
||||
T output = Instantiate();
|
||||
|
||||
// Read into the value
|
||||
reader.Read();
|
||||
|
||||
ReadProperty(property, reader, output, serializer);
|
||||
}
|
||||
reader.ReadObject(serializer, (p, r, s) => ReadProperty(p, r, output, s));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
using ICD.Common.Utils.IO;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace ICD.Common.Utils.Json
|
||||
{
|
||||
@@ -16,102 +14,9 @@ namespace ICD.Common.Utils.Json
|
||||
[PublicAPI]
|
||||
public static class JsonUtils
|
||||
{
|
||||
// 2016-02-26T19:24:59
|
||||
private const string DATE_FORMAT = @"yyyy-MM-dd\THH:mm:ss";
|
||||
|
||||
private const string MESSAGE_NAME_PROPERTY = "m";
|
||||
private const string MESSAGE_DATA_PROPERTY = "d";
|
||||
|
||||
/// <summary>
|
||||
/// Forces Newtonsoft to cache the given type for faster subsequent usage.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public static void CacheType<T>()
|
||||
where T : new()
|
||||
{
|
||||
CacheType(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forces Newtonsoft to cache the given type for faster subsequent usage.
|
||||
/// </summary>
|
||||
public static void CacheType(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
string serialized = JsonConvert.SerializeObject(ReflectionUtils.CreateInstance(type));
|
||||
JsonConvert.DeserializeObject(serialized, type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the token as a DateTime value.
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static DateTime ParseDateTime(JToken token)
|
||||
{
|
||||
if (token == null)
|
||||
throw new ArgumentNullException("token");
|
||||
|
||||
#if SIMPLSHARP
|
||||
return DateTime.ParseExact((string)token, DATE_FORMAT, CultureInfo.CurrentCulture);
|
||||
#else
|
||||
return (DateTime)token;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the token as a DateTime value.
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="output"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static bool TryParseDateTime(JToken token, out DateTime output)
|
||||
{
|
||||
if (token == null)
|
||||
throw new ArgumentNullException("token");
|
||||
|
||||
output = default(DateTime);
|
||||
|
||||
try
|
||||
{
|
||||
output = ParseDateTime(token);
|
||||
return true;
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pretty-prints the JSON document.
|
||||
/// </summary>
|
||||
/// <param name="json"></param>
|
||||
[PublicAPI]
|
||||
public static void Print(string json)
|
||||
{
|
||||
if (json == null)
|
||||
throw new ArgumentNullException("json");
|
||||
|
||||
string formatted = Format(json);
|
||||
IcdConsole.PrintLine(formatted);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the given item and pretty-prints to JSON.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
[PublicAPI]
|
||||
public static void Print(object value)
|
||||
{
|
||||
string formatted = Format(value);
|
||||
IcdConsole.PrintLine(formatted);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the given item and formats the JSON into a human-readable form.
|
||||
/// </summary>
|
||||
@@ -234,6 +139,22 @@ namespace ICD.Common.Utils.Json
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes to json, wrapping the object with a message property to differentiate between messages.
|
||||
/// E.g.
|
||||
/// { a = 1 }
|
||||
/// Becomes
|
||||
/// { m = "Test", d = { a = 1 } }
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="messageName"></param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static string SerializeMessage(object value, string messageName)
|
||||
{
|
||||
return SerializeMessage(w => new JsonSerializer().Serialize(w, value), messageName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes to json, wrapping the object with a message property to differentiate between messages.
|
||||
/// E.g.
|
||||
@@ -317,44 +238,5 @@ namespace ICD.Common.Utils.Json
|
||||
},
|
||||
json);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the given token based on the known type.
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public static object Deserialize(Type type, JToken token)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
if (token == null)
|
||||
throw new ArgumentNullException("token");
|
||||
|
||||
return Deserialize(type, token, new JsonSerializer());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the given token based on the known type.
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <param name="serializer"></param>
|
||||
/// <returns></returns>
|
||||
public static object Deserialize(Type type, JToken token, JsonSerializer serializer)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
if (token == null)
|
||||
throw new ArgumentNullException("token");
|
||||
|
||||
if (serializer == null)
|
||||
throw new ArgumentNullException("serializer");
|
||||
|
||||
using (JTokenReader jsonReader = new JTokenReader(token))
|
||||
return serializer.Deserialize(jsonReader, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
96
ICD.Common.Utils/Json/ToStringJsonConverter.cs
Normal file
96
ICD.Common.Utils/Json/ToStringJsonConverter.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
#if SIMPLSHARP
|
||||
using Crestron.SimplSharp.Reflection;
|
||||
#else
|
||||
using System.Reflection;
|
||||
#endif
|
||||
using ICD.Common.Properties;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ICD.Common.Utils.Json
|
||||
{
|
||||
/// <summary>
|
||||
/// Simply reads/writes values from/to JSON as their string representation.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public sealed class ToStringJsonConverter : JsonConverter
|
||||
{
|
||||
private static readonly Dictionary<Type, MethodInfo> s_ParseMethods;
|
||||
|
||||
public override bool CanRead { get { return true; } }
|
||||
|
||||
/// <summary>
|
||||
/// Static constructor.
|
||||
/// </summary>
|
||||
static ToStringJsonConverter()
|
||||
{
|
||||
s_ParseMethods = new Dictionary<Type, MethodInfo>();
|
||||
}
|
||||
|
||||
#region Methods
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
writer.WriteValue(value.ToString());
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
MethodInfo parse = GetParseMethod(objectType);
|
||||
if (parse == null)
|
||||
throw new ArgumentException(
|
||||
string.Format("{0} does not have a 'static {0} Parse(string)' method.", objectType.Name),
|
||||
"objectType");
|
||||
|
||||
try
|
||||
{
|
||||
return parse.Invoke(null, new[] { reader.Value });
|
||||
}
|
||||
catch (TargetInvocationException e)
|
||||
{
|
||||
throw e.InnerException;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[CanBeNull]
|
||||
private static MethodInfo GetParseMethod(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
MethodInfo output;
|
||||
if (!s_ParseMethods.TryGetValue(type, out output))
|
||||
{
|
||||
|
||||
output = type
|
||||
#if SIMPLSHARP
|
||||
.GetCType()
|
||||
.GetMethod("Parse",
|
||||
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic,
|
||||
CType.DefaultBinder,
|
||||
new CType[] {typeof(string)},
|
||||
new ParameterModifier[] {});
|
||||
#else
|
||||
.GetTypeInfo()
|
||||
.GetMethod("Parse",
|
||||
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic,
|
||||
Type.DefaultBinder,
|
||||
new[] {typeof(string)},
|
||||
new ParameterModifier[] {});
|
||||
#endif
|
||||
|
||||
s_ParseMethods.Add(type, output);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,6 +78,24 @@ namespace ICD.Common.Utils
|
||||
return outputStart + slope * (value - inputStart);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value after the input range has been mapped to a new range
|
||||
/// </summary>
|
||||
/// <param name="inputStart">Input start.</param>
|
||||
/// <param name="inputEnd">Input end.</param>
|
||||
/// <param name="outputStart">Output start.</param>
|
||||
/// <param name="outputEnd">Output end.</param>
|
||||
/// <param name="value">Value.</param>
|
||||
/// <returns>The newly mapped value</returns>
|
||||
public static decimal MapRange(decimal inputStart, decimal inputEnd, decimal outputStart, decimal outputEnd, decimal value)
|
||||
{
|
||||
if (inputStart.Equals(inputEnd))
|
||||
throw new DivideByZeroException();
|
||||
|
||||
decimal slope = (outputEnd - outputStart) / (inputEnd - inputStart);
|
||||
return outputStart + slope * (value - inputStart);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value after the input range has been mapped to a new range
|
||||
/// </summary>
|
||||
@@ -191,5 +209,18 @@ namespace ICD.Common.Utils
|
||||
|
||||
return nearest.Aggregate((x, y) => Math.Abs(x - number) < Math.Abs(y - number) ? x : y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the modulus of the given number.
|
||||
/// </summary>
|
||||
/// <param name="number"></param>
|
||||
/// <param name="mod"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>method name can't be "Mod", due to S+ compatability issues</remarks>
|
||||
public static int Modulus(int number, int mod)
|
||||
{
|
||||
int remainder = number % mod;
|
||||
return remainder < 0 ? remainder + mod : remainder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
@@ -17,7 +19,15 @@ namespace ICD.Common.Utils
|
||||
/// Gets the path to the root directory of the processor.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public static string RootPath { get { return IcdDirectory.GetDirectoryRoot("\\"); } }
|
||||
public static string RootPath {
|
||||
get
|
||||
{
|
||||
if (IcdEnvironment.RuntimeEnvironment == IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono)
|
||||
return IcdDirectory.GetApplicationRootDirectory();
|
||||
|
||||
return IcdDirectory.GetDirectoryRoot(IcdPath.DirectorySeparatorChar.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the program directory
|
||||
@@ -35,11 +45,11 @@ namespace ICD.Common.Utils
|
||||
get
|
||||
{
|
||||
#if SIMPLSHARP
|
||||
return Join(RootPath, "USER");
|
||||
return Join(RootPath, "User");
|
||||
#elif LINUX
|
||||
return Join(RootPath, "opt", "ICD.Connect");
|
||||
#else
|
||||
return Join(RootPath, "ProgramData", "ICD.Connect");
|
||||
return Join(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "ICD.Connect");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -49,12 +59,60 @@ namespace ICD.Common.Utils
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
[PublicAPI]
|
||||
public static string ProgramConfigPath
|
||||
public static string ProgramConfigPath { get { return Join(RootConfigPath, ProgramConfigDirectory); } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the name of the program config directory.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public static string ProgramConfigDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
string directoryName = string.Format("Program{0:D2}Config", ProgramUtils.ProgramNumber);
|
||||
return Join(RootConfigPath, directoryName);
|
||||
switch (IcdEnvironment.RuntimeEnvironment)
|
||||
{
|
||||
case IcdEnvironment.eRuntimeEnvironment.SimplSharp:
|
||||
case IcdEnvironment.eRuntimeEnvironment.SimplSharpPro:
|
||||
case IcdEnvironment.eRuntimeEnvironment.Standard:
|
||||
return string.Format("Program{0:D2}Config", ProgramUtils.ProgramNumber);
|
||||
|
||||
case IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono:
|
||||
return "ProgramConfig";
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the absolute path to the program data directory.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
[PublicAPI]
|
||||
public static string ProgramDataPath { get { return Join(RootConfigPath, ProgramDataDirectory); } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the name of the program data directory.
|
||||
/// This directory contains runtime program data that should be retained through deployments.
|
||||
/// </summary>
|
||||
public static string ProgramDataDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (IcdEnvironment.RuntimeEnvironment)
|
||||
{
|
||||
case IcdEnvironment.eRuntimeEnvironment.SimplSharp:
|
||||
case IcdEnvironment.eRuntimeEnvironment.SimplSharpPro:
|
||||
case IcdEnvironment.eRuntimeEnvironment.Standard:
|
||||
return string.Format("Program{0:D2}Data", ProgramUtils.ProgramNumber);
|
||||
|
||||
case IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono:
|
||||
return "ProgramData";
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +120,10 @@ namespace ICD.Common.Utils
|
||||
/// Returns the absolute path to the common configuration directory.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public static string CommonConfigPath { get { return Join(RootConfigPath, "CommonConfig"); } }
|
||||
public static string CommonConfigPath { get { return Join(RootConfigPath, CommonConfigDirectory); } }
|
||||
|
||||
[PublicAPI]
|
||||
public static string CommonConfigDirectory { get { return "CommonConfig"; }}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the absolute path to the common config library directory.
|
||||
@@ -76,6 +137,37 @@ namespace ICD.Common.Utils
|
||||
[PublicAPI]
|
||||
public static string ProgramLibPath { get { return Join(ProgramConfigPath, "Lib"); } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the absolute path to the logs directory.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
[PublicAPI]
|
||||
public static string ProgramLogsPath
|
||||
{
|
||||
get
|
||||
{
|
||||
string directoryName;
|
||||
|
||||
switch (IcdEnvironment.RuntimeEnvironment)
|
||||
{
|
||||
case IcdEnvironment.eRuntimeEnvironment.SimplSharp:
|
||||
case IcdEnvironment.eRuntimeEnvironment.SimplSharpPro:
|
||||
case IcdEnvironment.eRuntimeEnvironment.Standard:
|
||||
directoryName = string.Format("Program{0:D2}Logs", ProgramUtils.ProgramNumber);
|
||||
break;
|
||||
|
||||
case IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono:
|
||||
directoryName = "ProgramLogs";
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
return Join(RootConfigPath, directoryName);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
@@ -9,14 +9,21 @@ namespace ICD.Common.Utils
|
||||
{
|
||||
public static partial class ProcessorUtils
|
||||
{
|
||||
private const string MODEL_NAME_REGEX = @"^(\S*)";
|
||||
private const string MODEL_VERSION_REGEX = @" [[]v(\S*)";
|
||||
private const string VER_REGEX =
|
||||
@"(?'model'\S+) (?'type'\S+) (?'lang'\S+) \[v(?'version'\d+.\d+.\d+.\d+) \((?'date'\S+ \d+ \d+)\), #(?'serial'[A-F0-9]+)\] @E-(?'mac'[a-z0-9]+)";
|
||||
|
||||
private const string UPTIME_COMMAND = "uptime";
|
||||
private const string PROGUPTIME_COMMAND_ROOT = "proguptime:{0}";
|
||||
private const string UPTIME_REGEX = @".*(?'uptime'(?'days'\d+) days (?'hours'\d{2}):(?'minutes'\d{2}):(?'seconds'\d{2})\.(?'milliseconds'\d+))";
|
||||
|
||||
private const string RAMFREE_COMMAND = "ramfree";
|
||||
private const string RAMFREE_DIGITS_REGEX = @"^(\d*)";
|
||||
|
||||
private static string s_VersionResult;
|
||||
|
||||
private static DateTime? s_SystemUptimeStartTime;
|
||||
private static DateTime? s_ProgramUptimeStartTime;
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
@@ -48,11 +55,15 @@ namespace ICD.Common.Utils
|
||||
{
|
||||
get
|
||||
{
|
||||
Regex regex = new Regex(MODEL_NAME_REGEX);
|
||||
Match match = regex.Match(VersionResult);
|
||||
string versionResult = VersionResult;
|
||||
if (!String.IsNullOrEmpty(versionResult))
|
||||
{
|
||||
Regex regex = new Regex(VER_REGEX);
|
||||
Match match = regex.Match(versionResult);
|
||||
|
||||
if (match.Success)
|
||||
return match.Groups[1].Value;
|
||||
if (match.Success)
|
||||
return match.Groups["model"].Value;
|
||||
}
|
||||
|
||||
ServiceProvider.TryGetService<ILoggerService>()
|
||||
.AddEntry(eSeverity.Warning, "Unable to get model name from \"{0}\"", VersionResult);
|
||||
@@ -68,11 +79,15 @@ namespace ICD.Common.Utils
|
||||
{
|
||||
get
|
||||
{
|
||||
Regex regex = new Regex(MODEL_VERSION_REGEX);
|
||||
Match match = regex.Match(VersionResult);
|
||||
string versionResult = VersionResult;
|
||||
if (!String.IsNullOrEmpty(versionResult))
|
||||
{
|
||||
Regex regex = new Regex(VER_REGEX);
|
||||
Match match = regex.Match(VersionResult);
|
||||
|
||||
if (match.Success)
|
||||
return new Version(match.Groups[1].Value);
|
||||
if (match.Success)
|
||||
return new Version(match.Groups["version"].Value);
|
||||
}
|
||||
|
||||
ServiceProvider.TryGetService<ILoggerService>()
|
||||
.AddEntry(eSeverity.Warning, "Unable to get model version from \"{0}\"", VersionResult);
|
||||
@@ -80,6 +95,51 @@ namespace ICD.Common.Utils
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the date that the firmware was updated.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public static string ModelVersionDate
|
||||
{
|
||||
get
|
||||
{
|
||||
Regex regex = new Regex(VER_REGEX);
|
||||
Match match = regex.Match(VersionResult);
|
||||
|
||||
if (match.Success)
|
||||
return match.Groups["date"].Value;
|
||||
|
||||
ServiceProvider.TryGetService<ILoggerService>()
|
||||
.AddEntry(eSeverity.Warning, "Unable to get model version date from \"{0}\"", VersionResult);
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the serial number of the processor
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public static string ProcessorSerialNumber
|
||||
{
|
||||
get
|
||||
{
|
||||
Regex regex = new Regex(VER_REGEX);
|
||||
Match match = regex.Match(VersionResult);
|
||||
|
||||
if (!match.Success)
|
||||
{
|
||||
ServiceProvider.TryGetService<ILoggerService>()
|
||||
.AddEntry(eSeverity.Warning, "Unable to get serial number from \"{0}\"", VersionResult);
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
int decValue = int.Parse(match.Groups["serial"].Value, System.Globalization.NumberStyles.HexNumber);
|
||||
return decValue.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ram usage in the range 0 - 1.
|
||||
/// </summary>
|
||||
@@ -170,6 +230,60 @@ namespace ICD.Common.Utils
|
||||
IcdConsole.SendControlSystemCommand("reboot", ref consoleResult);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the uptime for the system
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static TimeSpan GetSystemUptime()
|
||||
{
|
||||
if (s_SystemUptimeStartTime == null)
|
||||
{
|
||||
string uptime = GetSystemUptimeFeedback();
|
||||
Match match = Regex.Match(uptime, UPTIME_REGEX);
|
||||
if (!match.Success)
|
||||
return default(TimeSpan);
|
||||
|
||||
int days = int.Parse(match.Groups["days"].Value);
|
||||
int hours = int.Parse(match.Groups["hours"].Value);
|
||||
int minutes = int.Parse(match.Groups["minutes"].Value);
|
||||
int seconds = int.Parse(match.Groups["seconds"].Value);
|
||||
int milliseconds = int.Parse(match.Groups["milliseconds"].Value);
|
||||
|
||||
TimeSpan span = new TimeSpan(days, hours, minutes, seconds, milliseconds);
|
||||
s_SystemUptimeStartTime = IcdEnvironment.GetLocalTime() - span;
|
||||
}
|
||||
|
||||
return IcdEnvironment.GetLocalTime() - s_SystemUptimeStartTime.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the uptime of the current program.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static TimeSpan GetProgramUptime()
|
||||
{
|
||||
if (s_ProgramUptimeStartTime == null)
|
||||
{
|
||||
string uptime = GetProgramUptimeFeedback((int)ProgramUtils.ProgramNumber);
|
||||
Match match = Regex.Match(uptime, UPTIME_REGEX);
|
||||
if (!match.Success)
|
||||
return default(TimeSpan);
|
||||
|
||||
int days = int.Parse(match.Groups["days"].Value);
|
||||
int hours = int.Parse(match.Groups["hours"].Value);
|
||||
int minutes = int.Parse(match.Groups["minutes"].Value);
|
||||
int seconds = int.Parse(match.Groups["seconds"].Value);
|
||||
int milliseconds = int.Parse(match.Groups["milliseconds"].Value);
|
||||
|
||||
TimeSpan span = new TimeSpan(days, hours, minutes, seconds, milliseconds);
|
||||
s_ProgramUptimeStartTime = IcdEnvironment.GetLocalTime() - span;
|
||||
}
|
||||
|
||||
return IcdEnvironment.GetLocalTime() - s_ProgramUptimeStartTime.Value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
@@ -187,6 +301,30 @@ namespace ICD.Common.Utils
|
||||
}
|
||||
return ramfree;
|
||||
}
|
||||
|
||||
private static string GetSystemUptimeFeedback()
|
||||
{
|
||||
string uptime = null;
|
||||
if (!IcdConsole.SendControlSystemCommand(UPTIME_COMMAND, ref uptime))
|
||||
{
|
||||
ServiceProvider.TryGetService<ILoggerService>()
|
||||
.AddEntry(eSeverity.Warning, "{0} - Failed to send console command \"{1}\"",
|
||||
typeof(ProcessorUtils).Name, UPTIME_COMMAND);
|
||||
}
|
||||
return uptime;
|
||||
}
|
||||
|
||||
private static string GetProgramUptimeFeedback(int programSlot)
|
||||
{
|
||||
string uptime = null;
|
||||
if (!IcdConsole.SendControlSystemCommand(string.Format(PROGUPTIME_COMMAND_ROOT, programSlot), ref uptime))
|
||||
{
|
||||
ServiceProvider.TryGetService<ILoggerService>()
|
||||
.AddEntry(eSeverity.Warning, "{0} - Failed to send console command \"{1}\"",
|
||||
typeof(ProcessorUtils).Name, UPTIME_COMMAND);
|
||||
}
|
||||
return uptime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,32 @@ namespace ICD.Common.Utils
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the date that the firmware was updated.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public static string ModelVersionDate
|
||||
{
|
||||
get
|
||||
{
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the serial number of the processor
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public static string ProcessorSerialNumber
|
||||
{
|
||||
get
|
||||
{
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ram usage in the range 0 - 1.
|
||||
/// </summary>
|
||||
@@ -109,6 +135,27 @@ namespace ICD.Common.Utils
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the uptime for the system
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static TimeSpan GetSystemUptime()
|
||||
{
|
||||
return TimeSpan.FromMilliseconds(Environment.TickCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the uptime
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static TimeSpan GetProgramUptime()
|
||||
{
|
||||
var current = System.Diagnostics.Process.GetCurrentProcess();
|
||||
return IcdEnvironment.GetLocalTime() - current.StartTime;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using ICD.Common.Utils.Services;
|
||||
using ICD.Common.Utils.IO;
|
||||
using ICD.Common.Utils.Services;
|
||||
using ICD.Common.Utils.Services.Logging;
|
||||
#if SIMPLSHARP
|
||||
using Crestron.SimplSharp;
|
||||
@@ -86,6 +87,16 @@ namespace ICD.Common.Utils
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the date and time the program was installed.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[PublicAPI]
|
||||
public static DateTime ProgramInstallDate
|
||||
{
|
||||
get { return IcdFile.GetCreationTime(PathUtils.Join(PathUtils.ProgramPath, ProgramFile)); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the prog comments and pulls program information.
|
||||
/// </summary>
|
||||
|
||||
@@ -55,6 +55,15 @@ namespace ICD.Common.Utils
|
||||
return Assembly.GetEntryAssembly().GetName().Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the date and time the program was installed.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public static DateTime ProgramInstallDate
|
||||
{
|
||||
get { return IcdFile.GetCreationTime(PathUtils.Join(PathUtils.ProgramPath, ProgramFile)); }
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -33,6 +33,10 @@ namespace ICD.Common.Utils
|
||||
name = name.Substring(0, proLength).PadRight(26);
|
||||
break;
|
||||
|
||||
case IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono:
|
||||
// No console
|
||||
return;
|
||||
|
||||
case IcdEnvironment.eRuntimeEnvironment.Standard:
|
||||
name += ' ';
|
||||
break;
|
||||
|
||||
@@ -3,5 +3,5 @@ using System.Reflection;
|
||||
[assembly: AssemblyTitle("ICD.Common.Utils")]
|
||||
[assembly: AssemblyCompany("ICD Systems")]
|
||||
[assembly: AssemblyProduct("ICD.Common.Utils")]
|
||||
[assembly: AssemblyCopyright("Copyright © ICD Systems 2018")]
|
||||
[assembly: AssemblyVersion("7.0.0.0")]
|
||||
[assembly: AssemblyCopyright("Copyright © ICD Systems 2019")]
|
||||
[assembly: AssemblyVersion("9.9.0.0")]
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.Collections;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
|
||||
namespace ICD.Common.Utils
|
||||
{
|
||||
@@ -31,6 +32,24 @@ namespace ICD.Common.Utils
|
||||
.Select(node => GetClique(map, visited, node));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the clique containing the given node.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="node"></param>
|
||||
/// <param name="getAdjacent"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<T> GetClique<T>(T node, Func<T, IEnumerable<T>> getAdjacent)
|
||||
{
|
||||
if (node == null)
|
||||
throw new ArgumentNullException("node");
|
||||
|
||||
if (getAdjacent == null)
|
||||
throw new ArgumentNullException("getAdjacent");
|
||||
|
||||
return BreadthFirstSearch(node, getAdjacent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the clique containing the given node.
|
||||
/// </summary>
|
||||
@@ -97,23 +116,23 @@ namespace ICD.Common.Utils
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if there is a path from the given root to the given child node.
|
||||
/// Returns true if there is a path from the given root to the given destination node.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="root"></param>
|
||||
/// <param name="child"></param>
|
||||
/// <param name="destination"></param>
|
||||
/// <param name="getChildren"></param>
|
||||
/// <returns></returns>
|
||||
public static bool BreadthFirstSearch<T>(T root, T child, Func<T, IEnumerable<T>> getChildren)
|
||||
public static bool BreadthFirstSearch<T>(T root, T destination, Func<T, IEnumerable<T>> getChildren)
|
||||
{
|
||||
if (getChildren == null)
|
||||
throw new ArgumentNullException("getChildren");
|
||||
|
||||
return BreadthFirstSearchPath(root, child, getChildren) != null;
|
||||
return BreadthFirstSearch(root, destination, getChildren, EqualityComparer<T>.Default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if there is a path from the given root to the given child node.
|
||||
/// Returns true if there is a path from the given root to the given destination node.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="root"></param>
|
||||
@@ -148,7 +167,7 @@ namespace ICD.Common.Utils
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all of the nodes in the tree via breadth-first search.
|
||||
/// Returns all of the nodes in the graph via breadth-first search.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="root"></param>
|
||||
@@ -156,16 +175,20 @@ namespace ICD.Common.Utils
|
||||
/// <returns></returns>
|
||||
private static IEnumerable<T> BreadthFirstSearchIterator<T>(T root, Func<T, IEnumerable<T>> getChildren)
|
||||
{
|
||||
IcdHashSet<T> visited = new IcdHashSet<T> {root};
|
||||
Queue<T> process = new Queue<T>();
|
||||
process.Enqueue(root);
|
||||
|
||||
while (process.Count > 0)
|
||||
T current;
|
||||
while (process.Dequeue(out current))
|
||||
{
|
||||
T current = process.Dequeue();
|
||||
yield return current;
|
||||
|
||||
foreach (T child in getChildren(current))
|
||||
foreach (T child in getChildren(current).Where(c => !visited.Contains(c)))
|
||||
{
|
||||
visited.Add(child);
|
||||
process.Enqueue(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,10 +237,9 @@ namespace ICD.Common.Utils
|
||||
|
||||
Dictionary<T, T> nodeParents = new Dictionary<T, T>(comparer);
|
||||
|
||||
while (queue.Count > 0)
|
||||
T current;
|
||||
while (queue.Dequeue(out current))
|
||||
{
|
||||
T current = queue.Dequeue();
|
||||
|
||||
foreach (T node in getChildren(current))
|
||||
{
|
||||
if (nodeParents.ContainsKey(node))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
using ICD.Common.Utils.IO;
|
||||
#if SIMPLSHARP
|
||||
@@ -146,6 +147,7 @@ namespace ICD.Common.Utils
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
[CanBeNull]
|
||||
public static object GetDefaultValue(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
@@ -167,6 +169,7 @@ namespace ICD.Common.Utils
|
||||
/// <param name="firstArgument"></param>
|
||||
/// <param name="method"></param>
|
||||
/// <returns></returns>
|
||||
[NotNull]
|
||||
public static Delegate CreateDelegate(Type type, object firstArgument, MethodInfo method)
|
||||
{
|
||||
return
|
||||
@@ -182,6 +185,7 @@ namespace ICD.Common.Utils
|
||||
/// Creates an instance of the given type, calling the default constructor.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[NotNull]
|
||||
public static T CreateInstance<T>(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
@@ -195,6 +199,7 @@ namespace ICD.Common.Utils
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
[NotNull]
|
||||
public static T CreateInstance<T>(params object[] parameters)
|
||||
{
|
||||
if (parameters == null)
|
||||
@@ -207,6 +212,7 @@ namespace ICD.Common.Utils
|
||||
/// Creates an instance of the given type, calling the default constructor.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[NotNull]
|
||||
public static object CreateInstance(Type type, params object[] parameters)
|
||||
{
|
||||
if (type == null)
|
||||
@@ -214,11 +220,15 @@ namespace ICD.Common.Utils
|
||||
|
||||
if (parameters == null)
|
||||
throw new ArgumentNullException("parameters");
|
||||
|
||||
ConstructorInfo constructor = GetConstructor(type, parameters);
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
if (parameters.Length == 0)
|
||||
return Activator.CreateInstance(type);
|
||||
|
||||
ConstructorInfo constructor = GetConstructor(type, parameters);
|
||||
|
||||
|
||||
return constructor.Invoke(parameters);
|
||||
}
|
||||
catch (TypeLoadException e)
|
||||
@@ -237,6 +247,7 @@ namespace ICD.Common.Utils
|
||||
/// <param name="type"></param>
|
||||
/// <param name="parameters"></param>
|
||||
/// <returns></returns>
|
||||
[NotNull]
|
||||
public static ConstructorInfo GetConstructor(Type type, params object[] parameters)
|
||||
{
|
||||
if (type == null)
|
||||
@@ -245,13 +256,18 @@ namespace ICD.Common.Utils
|
||||
if (parameters == null)
|
||||
throw new ArgumentNullException("parameters");
|
||||
|
||||
return
|
||||
type
|
||||
ConstructorInfo info;
|
||||
|
||||
if(!type
|
||||
#if SIMPLSHARP
|
||||
.GetCType()
|
||||
.GetCType()
|
||||
#endif
|
||||
.GetConstructors()
|
||||
.First(c => MatchesConstructorParameters(c, parameters));
|
||||
.GetConstructors()
|
||||
.Where(c => MatchesConstructorParameters(c, parameters))
|
||||
.TryFirst(out info))
|
||||
throw new ArgumentException("Couldn't find a constructor matching the given parameters.");
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -259,6 +275,7 @@ namespace ICD.Common.Utils
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
[NotNull]
|
||||
public static Assembly LoadAssemblyFromPath(string path)
|
||||
{
|
||||
if (path == null)
|
||||
@@ -299,6 +316,7 @@ namespace ICD.Common.Utils
|
||||
/// <param name="value"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
[CanBeNull]
|
||||
public static object ChangeType(object value, Type type)
|
||||
{
|
||||
if (type == null)
|
||||
@@ -325,8 +343,9 @@ namespace ICD.Common.Utils
|
||||
if (valueType.IsIntegerNumeric())
|
||||
return Enum.ToObject(type, value);
|
||||
|
||||
if (value is string)
|
||||
return Enum.Parse(type, value as string, false);
|
||||
string valueAsString = value as string;
|
||||
if (valueAsString != null)
|
||||
return Enum.Parse(type, valueAsString, false);
|
||||
}
|
||||
|
||||
return Convert.ChangeType(value, type, null);
|
||||
@@ -340,13 +359,62 @@ namespace ICD.Common.Utils
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subscribes to the event on the given instance using the handler and callback method.
|
||||
/// Subscribes to the event on the given instance using the event handler.
|
||||
/// </summary>
|
||||
/// <param name="instance">The instance with the event. Null for static types.</param>
|
||||
/// <param name="eventInfo">The EventInfo for the event.</param>
|
||||
/// <param name="handler">The instance with the callback MethodInfo. Null for static types.</param>
|
||||
/// <param name="callback">The MethodInfo for the callback method.</param>
|
||||
/// <param name="eventHandler">The EventHandler for the callback.</param>
|
||||
/// <returns></returns>
|
||||
[NotNull]
|
||||
public static Delegate SubscribeEvent(object instance, EventInfo eventInfo, Action<object> eventHandler)
|
||||
{
|
||||
if (eventInfo == null)
|
||||
throw new ArgumentNullException("eventInfo");
|
||||
|
||||
if (eventHandler == null)
|
||||
throw new ArgumentNullException("eventHandler");
|
||||
|
||||
object handler = eventHandler.Target;
|
||||
// ReSharper disable InvokeAsExtensionMethod
|
||||
MethodInfo callback = EventHandlerExtensions.GetMethodInfo(eventHandler);
|
||||
// ReSharper restore InvokeAsExtensionMethod
|
||||
|
||||
return SubscribeEvent(instance, eventInfo, handler, callback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subscribes to the event on the given instance using the event handler.
|
||||
/// </summary>
|
||||
/// <param name="instance">The instance with the event. Null for static types.</param>
|
||||
/// <param name="eventInfo">The EventInfo for the event.</param>
|
||||
/// <param name="eventHandler">The EventHandler for the callback.</param>
|
||||
/// <returns></returns>
|
||||
[NotNull]
|
||||
public static Delegate SubscribeEvent<T>(object instance, EventInfo eventInfo, Action<object, T> eventHandler)
|
||||
{
|
||||
if (eventInfo == null)
|
||||
throw new ArgumentNullException("eventInfo");
|
||||
|
||||
if (eventHandler == null)
|
||||
throw new ArgumentNullException("eventHandler");
|
||||
|
||||
object handler = eventHandler.Target;
|
||||
// ReSharper disable InvokeAsExtensionMethod
|
||||
MethodInfo callback = EventHandlerExtensions.GetMethodInfo(eventHandler);
|
||||
// ReSharper restore InvokeAsExtensionMethod
|
||||
|
||||
return SubscribeEvent(instance, eventInfo, handler, callback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subscribes to the event on the given instance using the handler and eventHandler method.
|
||||
/// </summary>
|
||||
/// <param name="instance">The instance with the event. Null for static types.</param>
|
||||
/// <param name="eventInfo">The EventInfo for the event.</param>
|
||||
/// <param name="handler">The instance with the eventHandler MethodInfo. Null for static types.</param>
|
||||
/// <param name="callback">The MethodInfo for the eventHandler method.</param>
|
||||
/// <returns></returns>
|
||||
[NotNull]
|
||||
public static Delegate SubscribeEvent(object instance, EventInfo eventInfo, object handler, MethodInfo callback)
|
||||
{
|
||||
if (eventInfo == null)
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace ICD.Common.Utils
|
||||
{
|
||||
@@ -30,5 +33,83 @@ namespace ICD.Common.Utils
|
||||
match = Regex.Match(input, pattern, options);
|
||||
return match.Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses the pattern to replace the specified group with the provided replacement string.
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="pattern"></param>
|
||||
/// <param name="groupName"></param>
|
||||
/// <param name="replacement"></param>
|
||||
/// <returns></returns>
|
||||
public static string ReplaceGroup(string input, string pattern, string groupName, string replacement)
|
||||
{
|
||||
return ReplaceGroup(input, pattern, groupName, replacement, RegexOptions.None);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses the pattern to replace the specified group with the provided replacement string.
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="pattern"></param>
|
||||
/// <param name="groupName"></param>
|
||||
/// <param name="replacement"></param>
|
||||
/// <returns></returns>
|
||||
public static string ReplaceGroup(string input, string pattern, string groupName, Func<Match, string> replacement)
|
||||
{
|
||||
return ReplaceGroup(input, pattern, groupName, replacement, RegexOptions.None);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses the pattern to replace the specified group with the provided replacement string.
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="pattern"></param>
|
||||
/// <param name="groupName"></param>
|
||||
/// <param name="replacement"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
public static string ReplaceGroup(string input, string pattern, string groupName, string replacement, RegexOptions options)
|
||||
{
|
||||
return ReplaceGroup(input, pattern, groupName, match => replacement, options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses the pattern to replace the specified group with the provided replacement string.
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="pattern"></param>
|
||||
/// <param name="groupName"></param>
|
||||
/// <param name="replacement"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
public static string ReplaceGroup(string input, string pattern, string groupName, Func<Match, string> replacement, RegexOptions options)
|
||||
{
|
||||
MatchEvaluator evaluator =
|
||||
m =>
|
||||
{
|
||||
string replacementString = replacement(m);
|
||||
|
||||
Group group = m.Groups[groupName];
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int previousCaptureEnd = 0;
|
||||
foreach (Capture capture in group.Captures.Cast<Capture>())
|
||||
{
|
||||
int currentCaptureEnd = capture.Index + capture.Length - m.Index;
|
||||
int currentCaptureLength = capture.Index - m.Index - previousCaptureEnd;
|
||||
|
||||
sb.Append(m.Value.Substring(previousCaptureEnd, currentCaptureLength));
|
||||
sb.Append(replacementString);
|
||||
|
||||
previousCaptureEnd = currentCaptureEnd;
|
||||
}
|
||||
sb.Append(m.Value.Substring(previousCaptureEnd));
|
||||
|
||||
return sb.ToString();
|
||||
};
|
||||
|
||||
return Regex.Replace(input, pattern, evaluator, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,7 @@ namespace ICD.Common.Utils
|
||||
{
|
||||
private readonly object m_Instance;
|
||||
|
||||
private readonly List<string> m_PropertyOrder;
|
||||
private readonly Dictionary<string, string> m_PropertyValues;
|
||||
private readonly List<KeyValuePair<string, string>> m_PropertyOrder;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
@@ -23,8 +22,7 @@ namespace ICD.Common.Utils
|
||||
{
|
||||
m_Instance = instance;
|
||||
|
||||
m_PropertyOrder = new List<string>();
|
||||
m_PropertyValues = new Dictionary<string, string>();
|
||||
m_PropertyOrder = new List<KeyValuePair<string, string>>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -32,14 +30,10 @@ namespace ICD.Common.Utils
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="value"></param>
|
||||
public void AppendProperty(string name, object value)
|
||||
public ReprBuilder AppendProperty(string name, object value)
|
||||
{
|
||||
m_PropertyOrder.Remove(name);
|
||||
m_PropertyOrder.Add(name);
|
||||
|
||||
string valueString = GetValueStringRepresentation(value);
|
||||
|
||||
m_PropertyValues[name] = valueString;
|
||||
return AppendPropertyRaw(name, valueString);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -47,12 +41,10 @@ namespace ICD.Common.Utils
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="value"></param>
|
||||
public void AppendPropertyRaw(string name, string value)
|
||||
public ReprBuilder AppendPropertyRaw(string name, string value)
|
||||
{
|
||||
m_PropertyOrder.Remove(name);
|
||||
m_PropertyOrder.Add(name);
|
||||
|
||||
m_PropertyValues[name] = value;
|
||||
m_PropertyOrder.Add(new KeyValuePair<string, string>(name, value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -62,7 +54,7 @@ namespace ICD.Common.Utils
|
||||
public override string ToString()
|
||||
{
|
||||
if (m_Instance == null)
|
||||
return GetValueStringRepresentation(m_Instance);
|
||||
return GetValueStringRepresentation(null);
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
@@ -71,12 +63,11 @@ namespace ICD.Common.Utils
|
||||
|
||||
for (int index = 0; index < m_PropertyOrder.Count; index++)
|
||||
{
|
||||
string property = m_PropertyOrder[index];
|
||||
builder.Append(property);
|
||||
builder.Append('=');
|
||||
KeyValuePair<string, string> pair = m_PropertyOrder[index];
|
||||
|
||||
string valueString = m_PropertyValues[property];
|
||||
builder.Append(valueString);
|
||||
builder.Append(pair.Key);
|
||||
builder.Append('=');
|
||||
builder.Append(pair.Value);
|
||||
|
||||
if (index < m_PropertyOrder.Count - 1)
|
||||
builder.Append(", ");
|
||||
|
||||
23
ICD.Common.Utils/SPlusUtils.cs
Normal file
23
ICD.Common.Utils/SPlusUtils.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using ICD.Common.Properties;
|
||||
|
||||
namespace ICD.Common.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class containing useful utilities for use in S+ programs
|
||||
/// </summary>
|
||||
[PublicAPI("S+")]
|
||||
public static class SPlusUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Convert two ushort's to an int
|
||||
/// </summary>
|
||||
/// <param name="lowWord">ushort for the least significant 16 bits</param>
|
||||
/// <param name="highWord">ushort for the most significant 1 bits</param>
|
||||
/// <returns></returns>
|
||||
[PublicAPI("S+")]
|
||||
public static int ConvertToInt(ushort lowWord, ushort highWord)
|
||||
{
|
||||
return (highWord << 16) + lowWord;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using ICD.Common.Properties;
|
||||
|
||||
namespace ICD.Common.Utils.Services.Logging
|
||||
@@ -21,11 +20,6 @@ namespace ICD.Common.Utils.Services.Logging
|
||||
[PublicAPI]
|
||||
public DateTime Timestamp { get { return m_Timestamp; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the log time in local time.
|
||||
/// </summary>
|
||||
public DateTime LocalTimestamp { get { return Timestamp.ToLocalTime(); } }
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set for severity level.
|
||||
/// </summary>
|
||||
@@ -56,24 +50,6 @@ namespace ICD.Common.Utils.Services.Logging
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Return the text format to send to Fusion
|
||||
/// </summary>
|
||||
/// <returns>text format for fusion, including timestamp, severity, and message</returns>
|
||||
[PublicAPI]
|
||||
public string GetFusionLogText()
|
||||
{
|
||||
StringBuilder s = new StringBuilder();
|
||||
|
||||
s.Append(Timestamp.ToString("yyyyMMddHHmmss"));
|
||||
s.Append("||");
|
||||
s.Append((int)Severity);
|
||||
s.Append("||");
|
||||
s.Append(Message);
|
||||
|
||||
return s.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementing default equality.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ICD.Common.Properties;
|
||||
using ICD.Common.Utils.Extensions;
|
||||
|
||||
@@ -228,18 +227,7 @@ namespace ICD.Common.Utils.Services
|
||||
if (tService == null)
|
||||
throw new ArgumentNullException("tService");
|
||||
|
||||
try
|
||||
{
|
||||
m_ServicesSection.Enter();
|
||||
|
||||
object service;
|
||||
m_Services.TryGetValue(tService, out service);
|
||||
return service;
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_ServicesSection.Leave();
|
||||
}
|
||||
return m_ServicesSection.Execute(() => m_Services.GetDefault(tService));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -265,7 +253,7 @@ namespace ICD.Common.Utils.Services
|
||||
/// <returns></returns>
|
||||
private IEnumerable<object> GetServicesInstance()
|
||||
{
|
||||
return m_ServicesSection.Execute(() => m_Services.Values.ToList());
|
||||
return m_ServicesSection.Execute(() => m_Services.Values.ToArray(m_Services.Count));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -32,8 +32,8 @@ namespace ICD.Common.Utils.Sqlite
|
||||
/// <param name="path"></param>
|
||||
public static void CreateFile(string path)
|
||||
{
|
||||
IcdFileStream fs = IcdFile.Create(path);
|
||||
fs.Close();
|
||||
using (IcdFileStream fs = IcdFile.Create(path))
|
||||
fs.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -34,5 +34,30 @@ namespace ICD.Common.Utils.Sqlite
|
||||
{
|
||||
return m_Reader.Read();
|
||||
}
|
||||
|
||||
public int GetInt32(int ordinal)
|
||||
{
|
||||
return m_Reader.GetInt32(ordinal);
|
||||
}
|
||||
|
||||
public bool GetBoolean(int ordinal)
|
||||
{
|
||||
return m_Reader.GetBoolean(ordinal);
|
||||
}
|
||||
|
||||
public string GetString(int ordinal)
|
||||
{
|
||||
return m_Reader.GetString(ordinal);
|
||||
}
|
||||
|
||||
public int GetOrdinal(string name)
|
||||
{
|
||||
return m_Reader.GetOrdinal(name);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
m_Reader.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,22 +6,27 @@ using Microsoft.Data.Sqlite;
|
||||
|
||||
namespace ICD.Common.Utils.Sqlite
|
||||
{
|
||||
public sealed class IcdSqliteParameterCollection
|
||||
{
|
||||
private readonly SqliteParameterCollection m_Parameters;
|
||||
public sealed class IcdSqliteParameterCollection
|
||||
{
|
||||
private readonly SqliteParameterCollection m_Parameters;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="commandParameters"></param>
|
||||
public IcdSqliteParameterCollection(SqliteParameterCollection commandParameters)
|
||||
public IcdSqliteParameterCollection(SqliteParameterCollection commandParameters)
|
||||
{
|
||||
m_Parameters = commandParameters;
|
||||
}
|
||||
|
||||
public IcdSqliteParameter Add(string name, eDbType type)
|
||||
{
|
||||
{
|
||||
return new IcdSqliteParameter(m_Parameters.Add(name, type.ToParamType()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddWithValue(string parameterName, object value)
|
||||
{
|
||||
m_Parameters.AddWithValue(parameterName, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ namespace ICD.Common.Utils
|
||||
private const char INTERSECT = '+';
|
||||
|
||||
private readonly List<string[]> m_Rows;
|
||||
private readonly SafeCriticalSection m_RowsSection;
|
||||
private readonly string[] m_Columns;
|
||||
|
||||
/// <summary>
|
||||
@@ -39,7 +38,6 @@ namespace ICD.Common.Utils
|
||||
public TableBuilder(params string[] columns)
|
||||
{
|
||||
m_Rows = new List<string[]>();
|
||||
m_RowsSection = new SafeCriticalSection();
|
||||
m_Columns = columns;
|
||||
}
|
||||
|
||||
@@ -49,9 +47,10 @@ namespace ICD.Common.Utils
|
||||
/// Clears all of the rows.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public void ClearRows()
|
||||
public TableBuilder ClearRows()
|
||||
{
|
||||
m_RowsSection.Execute(() => m_Rows.Clear());
|
||||
m_Rows.Clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -59,11 +58,11 @@ namespace ICD.Common.Utils
|
||||
/// </summary>
|
||||
/// <param name="row"></param>
|
||||
[PublicAPI]
|
||||
public void AddRow(params object[] row)
|
||||
public TableBuilder AddRow(params object[] row)
|
||||
{
|
||||
string[] stringRow = row.Select(o => string.Format("{0}", o))
|
||||
.ToArray();
|
||||
AddRow(stringRow);
|
||||
return AddRow(stringRow);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -71,31 +70,33 @@ namespace ICD.Common.Utils
|
||||
/// </summary>
|
||||
/// <param name="row"></param>
|
||||
[PublicAPI]
|
||||
public void AddRow(params string[] row)
|
||||
public TableBuilder AddRow(params string[] row)
|
||||
{
|
||||
if (row != null && row.Length != m_Columns.Length)
|
||||
throw new ArgumentException("Row must match columns length.");
|
||||
|
||||
m_RowsSection.Execute(() => m_Rows.Add(row));
|
||||
m_Rows.Add(row);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an empty row to the builder.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public void AddEmptyRow()
|
||||
public TableBuilder AddEmptyRow()
|
||||
{
|
||||
AddRow(new string[m_Columns.Length]);
|
||||
return AddRow(new string[m_Columns.Length]);
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public void AddSeparator()
|
||||
public TableBuilder AddSeparator()
|
||||
{
|
||||
AddRow(null);
|
||||
return AddRow(null);
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public void AddHeader(params string[] row)
|
||||
public TableBuilder AddHeader(params string[] row)
|
||||
{
|
||||
if (row.Length != m_Columns.Length)
|
||||
throw new ArgumentException("Row must match columns length.");
|
||||
@@ -103,6 +104,8 @@ namespace ICD.Common.Utils
|
||||
AddSeparator();
|
||||
AddRow(row);
|
||||
AddSeparator();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -112,30 +115,21 @@ namespace ICD.Common.Utils
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
m_RowsSection.Enter();
|
||||
int[] columnWidths = GetColumnWidths();
|
||||
|
||||
try
|
||||
AppendRow(sb, m_Columns, columnWidths);
|
||||
AppendSeparator(sb, columnWidths);
|
||||
|
||||
foreach (string[] row in m_Rows)
|
||||
{
|
||||
int[] columnWidths = GetColumnWidths();
|
||||
|
||||
AppendRow(sb, m_Columns, columnWidths);
|
||||
AppendSeparator(sb, columnWidths);
|
||||
|
||||
foreach (string[] row in m_Rows)
|
||||
{
|
||||
if (row == null)
|
||||
AppendSeparator(sb, columnWidths);
|
||||
else
|
||||
AppendRow(sb, row, columnWidths);
|
||||
}
|
||||
|
||||
AppendSeparator(sb, columnWidths);
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_RowsSection.Leave();
|
||||
if (row == null)
|
||||
AppendSeparator(sb, columnWidths);
|
||||
else
|
||||
AppendRow(sb, row, columnWidths);
|
||||
}
|
||||
|
||||
AppendSeparator(sb, columnWidths);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace ICD.Common.Utils.Timers
|
||||
private readonly Timer m_Timer;
|
||||
private int m_RepeatPeriod;
|
||||
#endif
|
||||
private readonly Action m_Callback;
|
||||
private Action m_Callback;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this instance has been disposed.
|
||||
@@ -67,8 +67,8 @@ namespace ICD.Common.Utils.Timers
|
||||
/// <returns></returns>
|
||||
public static SafeTimer Stopped(Action callback)
|
||||
{
|
||||
// Some arbitrarily large number that shouldn't timeout before we call stop.
|
||||
SafeTimer output = new SafeTimer(callback, 100 * 1000, 100 * 1000);
|
||||
//No due time or repeat period on a stopped timer
|
||||
SafeTimer output = new SafeTimer(callback, -1, -1);
|
||||
output.Stop();
|
||||
return output;
|
||||
}
|
||||
@@ -85,10 +85,12 @@ namespace ICD.Common.Utils.Timers
|
||||
if (IsDisposed)
|
||||
return;
|
||||
|
||||
IsDisposed = true;
|
||||
|
||||
Stop();
|
||||
m_Timer.Dispose();
|
||||
|
||||
IsDisposed = true;
|
||||
m_Callback = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -158,7 +160,8 @@ namespace ICD.Common.Utils.Timers
|
||||
// Essentially the meat of this class. There's some weirdness with the garbage collector where
|
||||
// the reference to the timer will be cleared, and eventually the CTimer will call the callback
|
||||
// despite being stopped/disposed.
|
||||
if (m_Timer == null
|
||||
if (IsDisposed ||
|
||||
m_Timer == null
|
||||
#if SIMPLSHARP
|
||||
|| m_Timer.Disposed
|
||||
#endif
|
||||
|
||||
41
ICD.Common.Utils/UriQueryBuilder.cs
Normal file
41
ICD.Common.Utils/UriQueryBuilder.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace ICD.Common.Utils
|
||||
{
|
||||
public sealed class UriQueryBuilder
|
||||
{
|
||||
private readonly Dictionary<string, string> m_Parameters;
|
||||
|
||||
public UriQueryBuilder()
|
||||
{
|
||||
m_Parameters = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
public UriQueryBuilder Append(string key, string value)
|
||||
{
|
||||
m_Parameters.Add(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder("?");
|
||||
|
||||
bool first = true;
|
||||
|
||||
foreach (KeyValuePair<string, string> kvp in m_Parameters)
|
||||
{
|
||||
if (!first)
|
||||
builder.Append('&');
|
||||
first = false;
|
||||
|
||||
builder.Append(kvp.Key);
|
||||
builder.Append('=');
|
||||
builder.Append(kvp.Value);
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ICD.Common.Utils
|
||||
{
|
||||
public static class UriUtils
|
||||
{
|
||||
private static readonly Dictionary<string, ushort> s_SchemeToPort =
|
||||
new Dictionary<string, ushort>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{Uri.UriSchemeHttp, 80},
|
||||
{Uri.UriSchemeHttps, 443}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to parse the given URI string into a System.Uri instance.
|
||||
/// </summary>
|
||||
@@ -27,5 +35,16 @@ namespace ICD.Common.Utils
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the port number for the given URI scheme.
|
||||
/// </summary>
|
||||
/// <param name="scheme"></param>
|
||||
/// <param name="port"></param>
|
||||
/// <returns></returns>
|
||||
public static bool TryGetPortForScheme(string scheme, out ushort port)
|
||||
{
|
||||
return s_SchemeToPort.TryGetValue(scheme, out port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,9 @@ namespace ICD.Common.Utils.Xml
|
||||
if (writer == null)
|
||||
throw new ArgumentNullException("writer");
|
||||
|
||||
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||
if (value == null)
|
||||
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||
{
|
||||
writer.WriteElementString(elementName, null);
|
||||
return;
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace ICD.Common.Utils.Xml
|
||||
{
|
||||
/// <summary>
|
||||
/// IcdXmlAttribute represents an attribute="value" pair from xml.
|
||||
/// </summary>
|
||||
public struct IcdXmlAttribute : IEquatable<IcdXmlAttribute>
|
||||
{
|
||||
private readonly string m_Name;
|
||||
private readonly string m_Value;
|
||||
|
||||
public string Name { get { return m_Name; } }
|
||||
public string Value { get { return m_Value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="value"></param>
|
||||
public IcdXmlAttribute(string name, string value)
|
||||
{
|
||||
m_Name = name;
|
||||
m_Value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementing default equality.
|
||||
/// </summary>
|
||||
/// <param name="a1"></param>
|
||||
/// <param name="a2"></param>
|
||||
/// <returns></returns>
|
||||
public static bool operator ==(IcdXmlAttribute a1, IcdXmlAttribute a2)
|
||||
{
|
||||
return a1.Equals(a2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementing default inequality.
|
||||
/// </summary>
|
||||
/// <param name="a1"></param>
|
||||
/// <param name="a2"></param>
|
||||
/// <returns></returns>
|
||||
public static bool operator !=(IcdXmlAttribute a1, IcdXmlAttribute a2)
|
||||
{
|
||||
return !a1.Equals(a2);
|
||||
}
|
||||
|
||||
public bool Equals(IcdXmlAttribute other)
|
||||
{
|
||||
return m_Name == other.m_Name &&
|
||||
m_Value == other.m_Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this instance is equal to the given object.
|
||||
/// </summary>
|
||||
/// <param name="other"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Equals(object other)
|
||||
{
|
||||
return other is IcdXmlAttribute && Equals((IcdXmlAttribute)other);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hashcode for this instance.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int hash = 17;
|
||||
hash = hash * 23 + (m_Name == null ? 0 : m_Name.GetHashCode());
|
||||
hash = hash * 23 + (m_Value == null ? 0 : m_Value.GetHashCode());
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -72,7 +73,12 @@ namespace ICD.Common.Utils.Xml
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
using (IcdXmlReader reader = new IcdXmlReader(xml))
|
||||
return DeserializeObject(type, reader);
|
||||
{
|
||||
if (reader.ReadToNextElement())
|
||||
return DeserializeObject(type, reader);
|
||||
|
||||
throw new FormatException("Expected element in XML");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -108,6 +114,64 @@ namespace ICD.Common.Utils.Xml
|
||||
return converter.ReadXml(reader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the child elements as items in an array.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="reader"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<T> DeserializeArray<T>(IcdXmlReader reader)
|
||||
{
|
||||
if (reader == null)
|
||||
throw new ArgumentNullException("reader");
|
||||
|
||||
return DeserializeArray(typeof(T), reader).Cast<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the child elements as items in an array.
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="reader"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<object> DeserializeArray(Type type, IcdXmlReader reader)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
if (reader == null)
|
||||
throw new ArgumentNullException("reader");
|
||||
|
||||
if (reader.NodeType != XmlNodeType.Element)
|
||||
throw new FormatException("Expected start element for array");
|
||||
|
||||
string arrayName = reader.Name;
|
||||
|
||||
// Read into the first element
|
||||
do
|
||||
{
|
||||
reader.Read();
|
||||
} while (reader.NodeType != XmlNodeType.Element && reader.NodeType != XmlNodeType.EndElement);
|
||||
|
||||
// Empty array
|
||||
if (reader.NodeType == XmlNodeType.EndElement)
|
||||
yield break;
|
||||
|
||||
// Read the items
|
||||
IXmlConverter converter = XmlConverterAttribute.GetConverterForType(type);
|
||||
while (reader.NodeType != XmlNodeType.EndElement)
|
||||
{
|
||||
yield return converter.ReadXml(reader);
|
||||
reader.SkipInsignificantWhitespace();
|
||||
}
|
||||
|
||||
if (reader.NodeType != XmlNodeType.EndElement || reader.Name != arrayName)
|
||||
throw new FormatException("Expected end element for array");
|
||||
|
||||
// Read out of the array end element
|
||||
reader.Read();
|
||||
}
|
||||
|
||||
public static string ToString(int value)
|
||||
{
|
||||
return XmlConvert.ToString(value);
|
||||
@@ -208,37 +272,127 @@ namespace ICD.Common.Utils.Xml
|
||||
throw new ArgumentNullException("type");
|
||||
|
||||
if (type == typeof(bool))
|
||||
return bool.Parse(value);
|
||||
return ToBool(value);
|
||||
if (type == typeof(byte))
|
||||
return byte.Parse(value);
|
||||
return ToByte(value);
|
||||
if (type == typeof(decimal))
|
||||
return decimal.Parse(value);
|
||||
return ToDecimal(value);
|
||||
if (type == typeof(char))
|
||||
return value.Single();
|
||||
return ToChar(value);
|
||||
if (type == typeof(double))
|
||||
return double.Parse(value);
|
||||
return ToDouble(value);
|
||||
if (type == typeof(Guid))
|
||||
return new Guid(value);
|
||||
return ToGuid(value);
|
||||
if (type == typeof(float))
|
||||
return float.Parse(value);
|
||||
return ToSingle(value);
|
||||
if (type == typeof(int))
|
||||
return int.Parse((value));
|
||||
return ToInt32(value);
|
||||
if (type == typeof(long))
|
||||
return long.Parse(value);
|
||||
return ToInt64(value);
|
||||
if (type == typeof(sbyte))
|
||||
return sbyte.Parse(value);
|
||||
return ToSByte(value);
|
||||
if (type == typeof(short))
|
||||
return short.Parse(value);
|
||||
return ToInt16(value);
|
||||
if (type == typeof(TimeSpan))
|
||||
return TimeSpan.Parse(value);
|
||||
return ToTimeSpan(value);
|
||||
if (type == typeof(uint))
|
||||
return uint.Parse(value);
|
||||
return ToUInt32(value);
|
||||
if (type == typeof(ulong))
|
||||
return ulong.Parse(value);
|
||||
return ToUInt64(value);
|
||||
if (type == typeof(ushort))
|
||||
return ushort.Parse(value);
|
||||
return ToUInt16(value);
|
||||
|
||||
return Convert.ChangeType(value, type, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
public static bool ToBool(string data)
|
||||
{
|
||||
return XmlConvert.ToBoolean(data);
|
||||
}
|
||||
|
||||
public static byte ToByte(string data)
|
||||
{
|
||||
return XmlConvert.ToByte(data);
|
||||
}
|
||||
|
||||
public static char ToChar(string data)
|
||||
{
|
||||
return XmlConvert.ToChar(data);
|
||||
}
|
||||
|
||||
public static DateTime ToDateTime(string data, string format)
|
||||
{
|
||||
return XmlConvert.ToDateTime(data, format);
|
||||
}
|
||||
|
||||
public static DateTime ToDateTime(string data, string[] formats)
|
||||
{
|
||||
return XmlConvert.ToDateTime(data, formats);
|
||||
}
|
||||
|
||||
public static DateTime ToDateTime(string data, XmlDateTimeSerializationMode dateTimeOption)
|
||||
{
|
||||
return XmlConvert.ToDateTime(data, dateTimeOption);
|
||||
}
|
||||
|
||||
public static decimal ToDecimal(string data)
|
||||
{
|
||||
return XmlConvert.ToDecimal(data);
|
||||
}
|
||||
|
||||
public static double ToDouble(string data)
|
||||
{
|
||||
return XmlConvert.ToDouble(data);
|
||||
}
|
||||
|
||||
public static Guid ToGuid(string data)
|
||||
{
|
||||
return XmlConvert.ToGuid(data);
|
||||
}
|
||||
|
||||
public static short ToInt16(string data)
|
||||
{
|
||||
return XmlConvert.ToInt16(data);
|
||||
}
|
||||
|
||||
public static int ToInt32(string data)
|
||||
{
|
||||
return XmlConvert.ToInt32(data);
|
||||
}
|
||||
|
||||
public static long ToInt64(string data)
|
||||
{
|
||||
return XmlConvert.ToInt64(data);
|
||||
}
|
||||
|
||||
public static sbyte ToSByte(string data)
|
||||
{
|
||||
return XmlConvert.ToSByte(data);
|
||||
}
|
||||
|
||||
public static float ToSingle(string data)
|
||||
{
|
||||
return XmlConvert.ToSingle(data);
|
||||
}
|
||||
|
||||
public static TimeSpan ToTimeSpan(string data)
|
||||
{
|
||||
return XmlConvert.ToTimeSpan(data);
|
||||
}
|
||||
|
||||
public static ushort ToUInt16(string data)
|
||||
{
|
||||
return XmlConvert.ToUInt16(data);
|
||||
}
|
||||
|
||||
public static uint ToUInt32(string data)
|
||||
{
|
||||
return XmlConvert.ToUInt32(data);
|
||||
}
|
||||
|
||||
public static ulong ToUInt64(string data)
|
||||
{
|
||||
return XmlConvert.ToUInt64(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user