Compare commits

...

330 Commits

Author SHA1 Message Date
Chris Cameron
d07373b69e chore: Updating changelog, incrementing major version 2020-03-20 13:04:11 -04:00
Laura Gomez
3ebfa76970 feat : Added ToPrivateString Method to convert password into special characters for privacy. 2020-03-17 18:47:46 -04:00
Chris Cameron
ac5da50e98 feat: Added IsDistinct extension method 2020-03-16 10:07:15 -04:00
Chris Cameron
6c6d272511 feat: Added MinOrDefault extension method 2020-03-16 10:04:23 -04:00
Chris Cameron
022e625143 fix: Fixed a bug where table width calculations were not considering unprintable characters 2020-03-15 15:51:05 -04:00
Chris Cameron
b496594cd6 test: Using UTC in unit tests 2020-03-11 15:36:21 -04:00
Chris Cameron
e99a7f313f fix: Using UTC for tracking durations 2020-03-11 13:02:34 -04:00
Chris Cameron
ed2cf84a7e fix: Using UTC for tracking scheduled events 2020-03-10 13:39:38 -04:00
Chris Cameron
91684f25f2 refactor: Tidying 2020-03-04 14:50:38 -05:00
Chris Cameron
be5024271f chore: Fixing comments 2020-03-03 17:41:02 -05:00
Chris Cameron
dd90227ca1 fix: Resolving warning 2020-03-03 17:31:56 -05:00
Chris Cameron
2fa6ff3de6 fix: Fixing TableBuilder spacing for Net Standard 2020-03-03 15:57:57 -05:00
Chris Cameron
311d63204f refactor: Tidying 2020-02-28 12:24:04 -05:00
Chris Cameron
82d0598352 feat: AnsiUtils exposes ANSI codes 2020-02-28 11:27:39 -05:00
Chris Cameron
4229a6a73f chore: Exluding build directory from test project 2020-02-28 11:27:09 -05:00
Chris Cameron
f5c6b64ab7 fix: Fixing bugs in AnsiUtils color conversion 2020-02-26 12:25:25 -05:00
Chris Cameron
3f62e7e929 refactor: Splitting ANSI into codes and texts, instead of converting straight to HTML 2020-02-25 19:06:34 -05:00
Chris Cameron
a82645e902 feat: Console uses unicode for table drawing on Net Standard 2020-02-24 17:57:43 -05:00
Chris Cameron
985578985a feat: Simplifying ANSI color methods, better cross-platform color support 2020-02-21 21:53:27 -05:00
Chris Cameron
c453717998 feat: First attempt at an ANSI to HTML converter 2020-02-19 16:52:21 -05:00
Chris Cameron
fde3106389 refactor: Tidying 2020-02-19 13:48:04 -05:00
Chris Cameron
94265b1915 Merge branch 'ConnectPro_v1.5' into ConnectPro_v1.6 2020-02-18 13:01:11 -05:00
Chris Cameron
9b3294382f Merge branch 'ConnectPro_v1.4' into ConnectPro_v1.5
# Conflicts:
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2020-02-18 13:00:59 -05:00
Chris Cameron
d59eb00d6b Merge branch 'ConnectPro_v1.3' into ConnectPro_v1.4
# Conflicts:
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2020-02-18 13:00:27 -05:00
Chris Cameron
d051ddb098 Merge branch 'ConnectPro_v1.2' into ConnectPro_v1.3
# Conflicts:
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2020-02-18 12:59:56 -05:00
Chris Cameron
a53ad74811 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2020-02-18 12:59:18 -05:00
Chris Cameron
69eb4b3d34 chore: Updating changelog, incrementing patch version 2020-02-18 12:13:00 -05:00
Drew Tingen
8e5486e1ef chore: Changelog 2020-02-14 23:56:56 -05:00
Drew Tingen
ecf7e626f3 fix: IcdTimer fix issue that prevents OnElapsed callback from firing when Length is less than (or close to) Heartbeat Interval 2020-02-14 23:55:32 -05:00
Chris Cameron
3b5c9ed51b fix: Fixed a bug where color formatted console output on Net Standard was not raising the OnConsolePrint event 2020-02-12 16:59:40 -05:00
Jeffery Thompson
e2646194b8 chore: changelog 2020-02-11 11:33:12 -05:00
Jeffery Thompson
0adad154c6 feat: add extensions for getting JsonReader value as long or ulong 2020-02-11 11:32:03 -05:00
Jeffery Thompson
0b8eb82e3b feat: add methods for creating a DateTime from epoch seconds or millis 2020-02-11 11:31:42 -05:00
Chris Cameron
13d1072d10 feat: Adding shims for converting DateTimes to/from XML 2020-02-03 16:32:04 -05:00
Chris Cameron
8d2321c350 refactor: Removing redundant code 2020-02-03 16:32:02 -05:00
Chris Cameron
55f494e2f5 Merge remote-tracking branch 'origin/ConnectPro_v1.5' into ConnectPro_v1.6 2020-02-03 16:31:43 -05:00
Chris Cameron
859a2b0830 Merge remote-tracking branch 'origin/ConnectPro_v1.4' into ConnectPro_v1.5 2020-02-03 16:31:03 -05:00
Chris Cameron
9d5dfb3b64 Merge branch 'ConnectPro_v1.3' into ConnectPro_v1.4
# Conflicts:
#	ICD.Common.Utils/Extensions/DictionaryExtensions.cs
2020-02-03 16:30:18 -05:00
Chris Cameron
c60acf52ba Merge remote-tracking branch 'origin/ConnectPro_v1.2' into ConnectPro_v1.3 2020-02-03 16:27:54 -05:00
Chris Cameron
311bf683e0 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Extensions/DictionaryExtensions.cs
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2020-02-03 16:12:26 -05:00
Chris Cameron
d025946948 chore: Updating changelog, incrementing minor version 2020-01-23 12:46:06 -05:00
Chris Cameron
b74d2c9d60 fix: Adding PriorityQueue EnqueueRemove overload for backwards compat 2020-01-23 12:44:08 -05:00
Jack Kanarish
ac4c0eccc9 feat: add ability to select when de-duplication should queue at the end of the queue, or at the first occurance
# Conflicts:
#	ICD.Common.Utils/Collections/PriorityQueue.cs
2020-01-23 11:44:31 -05:00
Jeffery Thompson
0cae292899 chore: changelog 2020-01-22 14:45:13 -05:00
Jeffery Thompson
9cdc8b26a2 fix: catch PlatformNotSupportedException for linux systems 2020-01-22 14:43:27 -05:00
Chris Cameron
80786dd84c Merge remote-tracking branch 'origin/ConnectPro_v1.5' into ConnectPro_v1.6
# Conflicts:
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2020-01-21 11:15:18 -05:00
Chris Cameron
bf8061046b chore: Updating changelog, incrementing minor version 2020-01-20 11:30:45 -05:00
Chris Cameron
201639b30b fix: Skip over invalid adapter ids when getting network information 2020-01-17 11:11:32 -05:00
Chris Cameron
89f0214cce fix: Ignoring Crestron ethernet parameters that say "Invalid Value" 2020-01-16 15:51:05 -05:00
Chris Cameron
49f8f116fd feat: Simplifying network interfaces, enumerating all adapter types
# Conflicts:
#	CHANGELOG.md
2020-01-16 15:49:40 -05:00
Laura Gomez
7598a451cc chore: XmlConverterAttribute is decorated as implicit 2020-01-14 14:08:32 -05:00
Laura Gomez
f03f49b376 fix: IcdXmlConvert supports serializing arrays of different items 2020-01-14 14:08:06 -05:00
Jack Kanarish
da4415a11c chore: changelog 2020-01-09 14:00:19 -05:00
Jack Kanarish
67c07b8833 feat: make get values public 2020-01-09 14:00:18 -05:00
Austin Noska
11c4d10a51 feat: added not null tag to ICDUriBuilder constructor that takes a Uri as an argument. 2020-01-06 12:54:02 -05:00
Chris Cameron
d1ec8a45d1 Merge branch 'ConnectPro_v1.5' into ConnectPro_v1.6 2020-01-06 10:30:00 -05:00
Chris Cameron
352121e25c Merge branch 'ConnectPro_v1.4' into ConnectPro_v1.5 2020-01-06 10:29:45 -05:00
Chris Cameron
0d5ee31d61 Merge branch 'ConnectPro_v1.3' into ConnectPro_v1.4 2020-01-06 10:28:48 -05:00
Chris Cameron
ec7004e053 Merge branch 'ConnectPro_v1.2' into ConnectPro_v1.3 2020-01-06 10:28:39 -05:00
Chris Cameron
ea0bcec2c3 Merge branch 'ConnectPro_v1.1' into ConnectPro_v1.2 2020-01-06 10:28:31 -05:00
Chris Cameron
55bf458a2b test: Fixing PriorityQueue unit tests 2020-01-06 10:28:03 -05:00
Chris Cameron
7562dddeff chore: Updating changelog 2020-01-06 09:50:08 -05:00
Laura Gomez
f66ddc7e03 refactor: cleaned up code. 2020-01-03 15:28:16 -05:00
Laura Gomez
b5fc25de7c feat: Added WriteAllByte method to IcdFile class. 2020-01-03 15:27:48 -05:00
Chris Cameron
d4ef4c3e1a feat: Added utils for building paths in the HTML directory 2020-01-03 14:17:13 -05:00
Chris Cameron
2a8a936b6f chore: Updating AssemblyInfo 2020-01-03 10:28:27 -05:00
Chris Cameron
bbe596c116 feat: Added methods for serializing an XML array 2019-12-13 12:21:41 -05:00
Laura Gomez
7689ffc3c8 feat: creating deserializItem method. Making xml changes. 2019-12-12 15:39:27 -05:00
Jeffery Thompson
1ab247f204 chore: changelog 2019-12-12 15:27:05 -05:00
Jeffery Thompson
5b5ee258ca chore: comments 2019-12-12 15:23:44 -05:00
Jeffery Thompson
4695a80575 feat: add DateTime extensions for add and wrap, like TimeSpan 2019-12-12 14:58:00 -05:00
Chris Cameron
79a98d8c10 feat: Added enum extensions for finding the inclusion and exclusion of enum flags 2019-12-05 15:31:20 -05:00
Chris Cameron
b68c5f1c97 feat: Added MathUtils methods for converting to and from percentages 2019-12-04 11:53:44 -05:00
Chris Cameron
3deec98f44 chore: Updating changelog, incrementing minor version 2019-12-04 11:51:18 -05:00
Chris Cameron
eb52b164bf feat: Added shim methods for finding closest DateTimes from a sequence 2019-11-19 17:08:21 -05:00
Chris Cameron
fb8abe2aa4 chore: Updating changelog, incrementing minor version 2019-11-18 14:17:31 -05:00
Chris Cameron
f61305856f refactor: Simplifying reflection code, potential micro-optimization 2019-11-14 11:24:10 -05:00
Chris Cameron
de00acbf79 feat: Adding extension method for getting max value from a sequence, otherwise a default value 2019-11-12 17:12:20 -05:00
Chris Cameron
5ffca5e7a3 feat: Adding overload for determining if a sorted list contains an item by a given predicate 2019-11-08 14:57:27 -05:00
Chris Cameron
2037c990b2 feat: Method for determining if a URI is default 2019-11-07 19:22:52 -05:00
Chris Cameron
13a2493f4c feat: Adding methods to get the data directory for a given room 2019-11-06 14:34:47 -05:00
Chris Cameron
09e0a20443 fix: IcdSqliteConnection CreateFile method will make directories recursively 2019-11-05 16:19:32 -05:00
Chris Cameron
7870d2c375 feat: Added method for getting a path in the ProgramData directory 2019-11-05 16:18:24 -05:00
Laura Gomez
7cf3d18127 feat: Adding CompareTo method wich helped with validation cheking on DeploymentTool. 2019-10-30 10:13:15 -04:00
Chris Cameron
f39b3897fc Merge branch 'ConnectPro_v1.3' into ConnectPro_v1.4 2019-10-29 14:58:27 -04:00
Chris Cameron
ab2fab0b3a Merge remote-tracking branch 'origin/ConnectPro_v1.2' into ConnectPro_v1.3 2019-10-29 14:58:19 -04:00
Chris Cameron
9b69b2a712 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-10-29 14:57:38 -04:00
Chris Cameron
0a1f637b45 chore: Updating changelog, incrementing patch version 2019-10-29 14:52:36 -04:00
Chris Cameron
e0ace12ef9 Merge pull request #43 from Utils fix/SerialQueueFix
Fix/SerialQueueFix
2019-10-29 14:33:28 -04:00
Jack Kanarish
9f1541f843 chore: update changelog 2019-10-29 14:19:58 -04:00
Jack Kanarish
b9f5349055 fix: fix an issue where commands would collapse to the point of the last deleted command instead of the position in queue where the new command was going 2019-10-29 14:18:45 -04:00
Chris Cameron
0c7f82835c fix: Fixing Net Standard build 2019-10-15 14:06:37 -04:00
Chris Cameron
41755cb472 refactor: Adding NotNull attributes to collections 2019-10-09 10:47:29 -04:00
Chris Cameron
238d6518ab refactor: Adding NotNull attributes to RangeAttribute 2019-10-09 10:15:47 -04:00
Chris Cameron
89cde5c9a0 chore: Decorating extension methods with NotNull and CanBeNull attributes 2019-10-07 21:59:21 -04:00
Chris Cameron
38204314e7 chore: Updating changelog, incrementing major version 2019-10-07 11:56:23 -04:00
Chris Cameron
9e8cedfbfa feat: Overload for Modulus taking long params 2019-09-30 11:52:02 -04:00
Chris Cameron
52229c1472 feat: Adding AreOrdered enumerable extension methods 2019-09-30 11:51:20 -04:00
Drew Tingen
38c24d42a7 feat: GetUtcTime() 2019-09-30 11:50:42 -04:00
Chris Cameron
cff1ec8d7e feat: Initial commit of NullObject 2019-09-25 13:52:20 -04:00
Chris Cameron
5a64a6c269 refactor: Tidying 2019-09-25 13:52:02 -04:00
Chris Cameron
68d98021a5 perf: Micro-optimization for copying arrays 2019-09-23 11:43:54 -04:00
Chris Cameron
0e16606d75 feat: Additional binary search extensions, AddSorted methods renamed to InsertSorted 2019-09-23 11:43:43 -04:00
Chris Cameron
602f170091 fix: Moving SafeCriticalSection Enters outside of tryf block, don't want to Leave if the Enter fails 2019-09-20 10:01:07 -04:00
Laura Gomez
aae8bc5323 feat: Adding default implementation for AbstractGenericXmlConverter Instantiate method 2019-09-16 15:15:35 -04:00
Chris Cameron
11004085c5 chore: Updating changelog, incrementing minor version 2019-09-16 14:44:07 -04:00
Chris Cameron
6ca015a561 Merge branch 'feat/ProgramDataPath' of Common/Utils into dev 2019-09-16 18:19:58 +00:00
Drew Tingen
73b1c4819c chore: Update changelog 2019-09-16 14:10:45 -04:00
Drew Tingen
f913af6efe Merge remote-tracking branch 'origin/dev' into feat/ProgramDataPath 2019-09-16 14:05:48 -04:00
Drew Tingen
099517df7d feat: Adding program data path to PathUtils 2019-09-16 14:00:47 -04:00
Chris Cameron
6a7b58f50f docs: Updating changelog 2019-09-14 11:23:19 -04:00
Chris Cameron
2273d5b3a1 refactor: Removing unused code 2019-09-14 11:23:09 -04:00
Chris Cameron
aa17f29305 feat: Adding BinarySearch extension method for ILists 2019-09-13 16:35:38 -04:00
Chris Cameron
e65578584a docs: Updating changelog 2019-09-10 17:19:28 -04:00
Chris Cameron
96d2df8871 feat: Added CultureInfo extensions for converting between 12 hour and 24 hour time formatting 2019-09-10 17:19:00 -04:00
Chris Cameron
b4d82a855e feat: Added a dictionary extension method for getting or adding a new value via func 2019-09-10 17:18:12 -04:00
Chris Cameron
83bc344ab3 feat: Added an event that is raised when the system time is set 2019-09-10 17:17:09 -04:00
Chris Cameron
0821dcb3ca fix: Fixed a bug where CultureInfo was not being cloned correctly 2019-09-10 17:16:31 -04:00
Chris Cameron
b6f64bb9b2 Merge branch 'fix/ModulusRename' of Common/Utils into dev 2019-09-09 19:54:24 +00:00
Drew Tingen
6ae110a997 Merge remote-tracking branch 'origin/dev' into fix/ModulusRename 2019-09-09 15:38:56 -04:00
Chris Cameron
efdb48f2c3 Merge branch 'fix/programdata-path' of Common/Utils into ConnectPro_v1.4 2019-09-09 19:33:32 +00:00
Drew Tingen
9d02ee0022 fix: Fixing MathUtilsTest after rename 2019-09-09 15:33:31 -04:00
Austin Noska
8c0416f70e docs: updating changelog 2019-09-09 15:28:03 -04:00
Austin Noska
0f27d68edf fix: Net Standard: the Root Config Path is now ICD.Connect in the current environments ProgramData directory 2019-09-09 15:25:35 -04:00
Drew Tingen
f8fc68e08f chore: remarks explaining method name limitations 2019-09-09 15:17:32 -04:00
Drew Tingen
fc4ae67e40 chore: changelog slightly more specific 2019-09-09 15:16:23 -04:00
Drew Tingen
0f618198b5 fix: Rename "Mod" to "Modulus" to keep S+ from throwing a fit 2019-09-09 15:06:39 -04:00
Chris Cameron
9a6f197aa0 feat: Added TimeSpan extension methods for cycling hours and minutes without modifying the day 2019-09-09 10:07:08 -04:00
Chris Cameron
45ee3e70b0 feat: Added mod method to MathUtils 2019-09-09 10:06:08 -04:00
Chris Cameron
b09f614ef5 feat: Added a method for determining if a culture uses 24 hour format 2019-09-04 14:31:16 -04:00
Chris Cameron
027c9ffe82 refactor: Changed DateTime extension method to a simple util method 2019-09-04 14:30:45 -04:00
Chris Cameron
dc1b60e629 feat: Added an extension method for getting the hour in 12 hour format 2019-09-04 12:36:54 -04:00
Chris Cameron
091ad10068 test: Updating test framework version 2019-09-03 16:09:03 -04:00
Chris Cameron
71bb320057 chore: Updating changelog, incrementing minor version 2019-09-03 10:52:19 -04:00
Chris Cameron
e6b0fd5f7b Merge remote-tracking branch 'origin/feat/xml-array' into ConnectPro_v1.4 2019-09-03 10:27:42 -04:00
Chris Cameron
2a2bff2e92 Merge branch 'feat/uptime-utils' of Common/Utils into ConnectPro_v1.4 2019-09-03 14:02:26 +00:00
Austin Noska
9c07b3da04 docs: updating changelog 2019-08-30 17:21:17 -04:00
Austin Noska
438b3d48e4 feat: Implemented Processor Utils for Net Standard to get the system uptime and the program uptime. 2019-08-30 17:19:17 -04:00
Austin Noska
629ceec84e feat: Added Public API Property to get the program install date based on the creation date of core dll file for Net Standard and SimplSharp 2019-08-30 17:18:18 -04:00
Chris Cameron
bb41d59a4b feat: Adding methods for deserializing an XML array of items 2019-08-29 17:21:57 -04:00
Chris Cameron
c23d81e023 chore: Updating nuget packages 2019-08-29 14:13:55 -04:00
Chris Cameron
18abe78550 feat: Better handling of JSON DateTimes in Net Standard 2019-08-27 15:01:09 -04:00
Chris Cameron
f33218f7a6 chore: Updating nuget packages 2019-08-22 17:17:35 -04:00
Chris Cameron
4938dad882 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.4
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-08-22 10:42:57 -04:00
Chris Cameron
5900f5974b chore: Updating changelog, incrementing patch version 2019-08-22 10:41:00 -04:00
Drew Tingen
81f7eb9c66 Merge branch 'fix/ordered-dict' of Common/Utils into MetLife_v5.4.3 2019-08-22 14:30:40 +00:00
Chris Cameron
440c1c62f1 fix: Fixed a bug with the IcdOrderedDict index setter that was creating additional values 2019-08-22 10:17:32 -04:00
Chris Cameron
63b590a9ea feat: ToStringJsonConverter rethrows the inner exception for TargetInvocationExceptions 2019-08-20 15:40:01 -04:00
Chris Cameron
f8c88630fc fix: Fixed a bug where ANSI color encoded strings with percentages were being scrambled 2019-08-20 15:34:40 -04:00
Chris Cameron
3f1f9611ec chore: Updating changelog, incrementing minor version 2019-08-15 11:02:18 -04:00
Chris Cameron
47c611a0b4 Merge remote-tracking branch 'origin/MetLife_v5.4.3' into dev 2019-08-15 10:57:50 -04:00
Chris Cameron
e388f35efb Revert "fix: fix for logging deadlock, use mutexes, add logging for last message sent."
This reverts commit 7c238b9fef.
2019-08-15 10:56:34 -04:00
Jack Kanarish
89061b5cbf feat: add unit test for timer 2019-08-07 20:47:54 -04:00
Chris Cameron
ff6f15d3ef fix: Potential JSON under-read fix 2019-08-07 17:34:07 -04:00
Drew Tingen
02e6fe9f8c chore: formatting 2019-08-07 13:30:55 -04:00
Drew Tingen
edb5534b9d Merge remote-tracking branch 'origin/fix/json-dict' into KrangAtHome 2019-08-07 13:28:26 -04:00
Drew Tingen
6af3e5b2ff fix: Reflection - throw inner exception for parameterless constructors that throw exceptions 2019-08-07 13:28:11 -04:00
Chris Cameron
65f76402cc feat: Serializing both keys and values to JSON when serializing dicts 2019-08-07 13:02:18 -04:00
Chris Cameron
5700cf4ce2 feat: Re-adding missing util method for getting class attributes 2019-08-01 09:24:17 -04:00
Jack Kanarish
7c238b9fef fix: fix for logging deadlock, use mutexes, add logging for last message sent. 2019-07-31 16:22:05 -04:00
Laura Gomez
6eda848410 feat: Initial commit of EmailValidation class 2019-07-31 11:47:52 -04:00
Laura Gomez
7b44867f34 docs: updating changelog 2019-07-30 13:38:37 -04:00
Laura Gomez
149f480add fix: Fixing JSON datetime parsing in 2017 2019-07-30 12:16:29 -04:00
Austin Noska
0f5632ced8 refactor: changed public method to private as it is only being used from within EnumUtils 2019-07-18 11:37:33 -04:00
Chris Cameron
9df5f7ae37 feat: Clarifying method usage 2019-07-12 17:17:05 -04:00
Laura Gomez
6e056c9dcc feat: Added util extension method for converting a DateTime to a Unix timestamp 2019-07-12 13:57:52 -04:00
Chris Cameron
7add461a1a Merge branch 'feat/log-timestamps' of Common/Utils into ConnectPro_v1.3 2019-07-11 14:44:37 +00:00
Austin Noska
cb3677bd72 docs: updating changelog 2019-07-11 10:39:26 -04:00
Austin Noska
69ad4bb240 feat: Added timestamps to logs for non Simplsharp programs 2019-07-11 10:23:17 -04:00
Chris Cameron
1a868d5a7d chore: Updating changelog, incrementing minor version 2019-07-03 10:22:01 -04:00
Laura Gomez
bb6110931a feat : added a StartofDay and EndofDay DateTime methods. 2019-07-02 16:28:29 -04:00
Chris Cameron
909ebfbc97 fix: Throwing an exception when trying to read non-primitive JSON tokens as string 2019-07-01 17:07:50 -04:00
Chris Cameron
3d068aeb68 fix: Potential fix for errant '?' characters in URIs 2019-06-28 11:22:23 -04:00
Chris Cameron
1f6915a825 Merge branch 'feat/GetCliqueOptimization' of Common/Utils into ConnectPro_v1.3 2019-06-27 15:02:00 +00:00
Austin Noska
00e7fd6a6b docs: updating changelog 2019-06-27 11:00:03 -04:00
Austin Noska
e3f356a5db test: updating get cliques unit tests 2019-06-27 10:58:22 -04:00
Austin Noska
2d401959b6 feat: optimized get clique by using a bredth-first-search so it would not have to search the whole graph 2019-06-27 10:57:55 -04:00
Austin Noska
7cc5a47d6a feat: Added a hashset of visited nodes so bfs can be used on graphs 2019-06-27 10:57:00 -04:00
Chris Cameron
8c160c77c4 docs: Updating changelog 2019-06-26 13:33:37 -04:00
Austin Noska
65c50e8e90 feat: Added method to get a single clique given a starting node 2019-06-26 11:39:50 -04:00
Chris Cameron
3a2fc0eef7 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.3
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-06-24 12:52:24 -04:00
Chris Cameron
1be852685d chore: Updating changelog, incrementing minor version 2019-06-24 12:49:39 -04:00
Chris Cameron
6201184fab feat: IcdXmlException exposes LineNumber and LinePosition 2019-06-24 12:42:29 -04:00
Chris Cameron
e8acb42bb9 fix: Fixed bug in IcdUriBuilder where Query property behaved differently to UriBuilder 2019-06-21 21:32:46 -04:00
Chris Cameron
d3d812265e Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.3
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-06-14 16:54:12 -04:00
Chris Cameron
b915401109 chore: Updating changelog, incrementing patch version 2019-06-14 16:52:56 -04:00
Austin Noska
3e3a4e33cb fix: SafeTimer Stopped now returns a SafeTimer with no due time and no repeat period 2019-06-14 16:51:36 -04:00
Chris Cameron
b680bab67a Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-06-14 10:28:13 -04:00
Chris Cameron
7666021925 chore: Updating changelog, incrementing minor version 2019-06-14 10:25:47 -04:00
Chris Cameron
7b6092c291 fix: Fixing issues with Remap methods, added unit tests 2019-06-13 17:35:03 -04:00
Chris Cameron
f7740aaea2 fix: Fixing overflow 2019-06-13 17:10:34 -04:00
Chris Cameron
c31b2b556b feat: Adding methods for remapping and clamping numeric values to ranges 2019-06-13 16:56:49 -04:00
Chris Cameron
8866a3e1e6 fix: Fixing tests, bad maths 2019-06-13 11:59:12 -04:00
Chris Cameron
e3273934a7 fix: Begin rewriting RangeAttribute 2019-06-12 23:42:59 -04:00
Chris Cameron
0152259a25 chore: Updating changelog, incrementing minor version 2019-06-10 13:50:37 -04:00
Chris Cameron
98c3f17602 docs: Updating changelog 2019-06-10 13:50:23 -04:00
Chris Cameron
bb3fba100d fix: Fixing NetStandard CultureInfo database connection string 2019-06-10 13:48:08 -04:00
Chris Cameron
9adad373f6 fix: Better determine builtin cultures on NetStandard 2019-06-10 13:47:45 -04:00
Chris Cameron
844f8b7b46 refactor: Tidying 2019-06-10 13:47:21 -04:00
Chris Cameron
43d7ea944e Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-06-06 15:54:04 -04:00
Chris Cameron
6526b2b811 chore: Updating changelog, incrementing minor version 2019-06-06 15:52:35 -04:00
Chris Cameron
ead365e251 chore: Fixing bad merge 2019-06-06 15:51:53 -04:00
Jack Kanarish
f24e6d2597 Merge branch 'feat/init-event' into MetLife_v5.4.2
# Conflicts:
#	CHANGELOG.md
2019-06-06 11:06:09 -04:00
Chris Cameron
311f2dfaf4 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-06-05 15:03:33 -04:00
Chris Cameron
1c38d9f04a fix: Fixing Net Standard build, changing method name 2019-06-05 15:01:07 -04:00
Chris Cameron
02c18d152f chore: Updating changelog, incrementing patch version 2019-06-05 14:34:59 -04:00
Chris Cameron
fc482ec685 Merge branch 'fix/processorUptimeCaching' of Common/Utils into MetLife_v5.4.2 2019-06-05 18:28:28 +00:00
Austin Noska
d649fb9dc4 docs: updating utils changelog 2019-06-05 14:18:53 -04:00
Austin Noska
4d76abe046 fix: cache the uptime values and calculate the uptime from those values instead of polling the crestron processor each time its needed 2019-06-05 14:15:53 -04:00
Chris Cameron
d6d3bfa9e0 Merge branch 'feat/XmlUtilsRoku' of Common/Utils into ConnectPro_v1.3 2019-06-04 17:17:33 +00:00
Austin Noska
536742a1c6 docs: updating changelog 2019-06-04 12:54:39 -04:00
Austin Noska
dc824b2034 feat: Added a URI query builder 2019-06-04 12:19:12 -04:00
Chris Cameron
0cc588ce15 Merge branch 'feat/XmlUtilsRoku' of Common/Utils into ConnectPro_v1.3 2019-05-31 20:16:55 +00:00
Austin Noska
b996a295f6 Merge remote-tracking branch 'origin/ConnectPro_v1.3' into feat/XmlUtilsRoku
# Conflicts:
#	CHANGELOG.md
2019-05-31 16:14:14 -04:00
Austin Noska
4312ad1a61 chore: updated changelog 2019-05-31 15:58:06 -04:00
Austin Noska
7792b01629 feat: Added Shim to read a list from xml with no root element 2019-05-31 15:52:47 -04:00
Chris Cameron
4953e40f9e docs: Updating changelog 2019-05-31 13:34:29 -04:00
Chris Cameron
69f872ced1 feat: Adding features to IcdEnvironment for tracking program initialization state 2019-05-31 13:33:21 -04:00
Chris Cameron
7e3aef4cb3 fix: Fixed threading exception in TypeExtensions 2019-05-28 09:52:06 -04:00
Chris Cameron
a6fbd5a6d2 chore: Updating changelog 2019-05-28 09:51:54 -04:00
Chris Cameron
6f67064d34 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2 2019-05-24 09:59:54 -04:00
Chris Cameron
723759f805 Merge remote-tracking branch 'origin/MetLife_v5.4' into MetLife_v5.4.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-05-24 09:59:07 -04:00
Chris Cameron
59f4411620 chore: Updating changelog, incrementing patch version 2019-05-24 09:55:48 -04:00
Chris Cameron
243e285948 feat: Added empty, placeholder interface for ICD Attributes 2019-05-24 09:55:33 -04:00
Chris Cameron
198bf8dac0 Merge branch 'fix/json-reader-extensions' of Common/Utils into ConnectPro_v1.3 2019-05-22 17:45:08 +00:00
Jeffery Thompson
78f5c4a7b6 fix: use ToString() instead of as string to support .NET Standard 2019-05-22 11:09:32 -04:00
Chris Cameron
c0ed7f9b26 feat: Clarifying neutral culture exception 2019-05-16 16:24:59 -04:00
Chris Cameron
6d08ee3bef Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj
#	ICD.Common.Utils/PathUtils.cs
#	ICD.Common.Utils/ProcessorUtils.SimplSharp.cs
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-05-16 09:56:43 -04:00
Chris Cameron
2b376bff47 chore: Updating changelog, incrementing minor version 2019-05-15 15:59:09 -04:00
Chris Cameron
9f0e66e4a1 fix: XmlReaderExtensions handling both TimeSpan formats 2019-05-14 16:16:22 -04:00
Chris Cameron
4c93515f83 refactor: Exposing missing XmlConvert methods 2019-05-14 16:15:48 -04:00
Chris Cameron
9ad49540d2 fix: Fixing JSON converter error when handling default existing value with struct types 2019-05-10 16:04:11 -04:00
Chris Cameron
cbf7a3d79c chore: Updating changelog, incrementing minor version 2019-05-10 14:53:27 -04:00
Jeffery Thompson
5a4d3cabac Merge branch 'feat/localization' of Common/Utils into ConnectPro_v1.3 2019-05-10 18:35:34 +00:00
Jack Kanarish
dc0e65125a Merge remote-tracking branch 'origin/MetLife_v5.4' into Telemetry
# Conflicts:
#	CHANGELOG.md
2019-05-10 12:06:13 -04:00
Chris Cameron
9d732ef4b2 feat: Adding RemoveRange method to IcdHashSet 2019-05-10 11:47:00 -04:00
Chris Cameron
ecdb4f4fb5 feat: AbstractGenericJsonConverter exposes virtual methods for overriding object serialization/deserialization 2019-05-09 15:18:21 -04:00
Chris Cameron
6f5188909b fix: Fixing dumb mistake with extension method resolution order 2019-05-09 12:51:55 -04:00
Chris Cameron
3fa089b85e feat: Added methods for serializing additional types, arrays and dictionaries to JSON 2019-05-09 11:58:55 -04:00
Chris Cameron
fef667191b chore: Moving CultureInfo.sqlite into project root so it gets included in clz 2019-05-08 10:21:52 -04:00
Chris Cameron
28abb69c85 feat: Initial commit of IcdCultureInfo and associated CultureInfo.sqlite database 2019-05-07 11:52:13 -04:00
Chris Cameron
0bf88240b2 feat: Adding missing methods to sqlite wrappers 2019-05-07 11:51:08 -04:00
Drew Tingen
294afd1834 chore: update changelog 2019-05-02 20:22:54 -04:00
Drew Tingen
475f381991 feat: Breaking out Program/Common config directories from the full paths 2019-05-02 20:22:32 -04:00
Chris Cameron
1460bf2924 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
2019-05-02 10:28:09 -04:00
Chris Cameron
33b1d29781 fix: IcdUriBuilder constructors behave closer to UriBuilder, Host defaults to "localhost" 2019-05-01 17:05:22 -04:00
Chris Cameron
78c20201ab fix: IcdUriBuilder constructors behave closer to UriBuilder, Host defaults to "localhost" 2019-05-01 16:33:09 -04:00
Chris Cameron
66f4e797ed feat: Adding extension method for getting or adding a new item to a dictionary 2019-04-26 12:17:09 -04:00
Chris Cameron
94ac37b32a refactor: Tidying 2019-04-23 12:01:53 -04:00
Chris Cameron
22978e90c4 feat: Added extension method for peeking queues 2019-04-23 09:57:28 -04:00
Chris Cameron
995a57f8e4 chore: Updating changelog, incrementing minor version 2019-04-16 14:07:52 -04:00
Chris Cameron
d6d767d8f9 Merge remote-tracking branch 'origin/feat/logs' into ConnectPro_v1.2 2019-04-16 14:01:11 -04:00
Jack Kanarish
0931d6f1ec feat: add helper method for un-mapping a range from ushorts 2019-04-10 17:17:30 -04:00
Jack Kanarish
24859aaa31 feat: add types to maprange 2019-04-10 17:16:26 -04:00
Chris Cameron
798e9cc0a7 Merge branch 'feat/SPlusUtils' of Common/Utils into dev 2019-04-09 19:58:33 +00:00
Drew Tingen
1dac1bfb67 chore: Changelog + Docs 2019-04-09 15:57:10 -04:00
Drew Tingen
829c24b667 feat: Adding SPlusUtils to convert ushort's to int 2019-04-09 15:46:10 -04:00
Chris Cameron
715c198763 feat: Keeping paths as they were until we can agree on an approach going forwards 2019-04-08 17:00:10 -04:00
Chris Cameron
d8741773c5 refactor: Removing unused code 2019-04-08 16:38:01 -04:00
Chris Cameron
26b924dd48 feat: IcdStreamWriter exposes WriteLine(string) 2019-04-08 16:31:53 -04:00
Chris Cameron
8892e6e223 feat: Adding ProgramLogsPath to PathUtils 2019-04-08 15:48:05 -04:00
Chris Cameron
23afa8e025 feat: Windows and VC4 use Config directory for configuration 2019-04-08 15:47:52 -04:00
Chris Cameron
7d1cc3139f chore: Updating nuget packages 2019-04-08 14:00:47 -04:00
Chris Cameron
30ea6ced9e fix: Fixing bad merge 2019-04-08 10:59:37 -04:00
Chris Cameron
3041d0f402 Merge remote-tracking branch 'origin/ConnectPro_v1.1' into ConnectPro_v1.2
# Conflicts:
#	CHANGELOG.md
#	ICD.Common.Utils/Properties/AssemblyInfo.cs
2019-04-08 10:55:52 -04:00
Chris Cameron
f4693df048 Merge remote-tracking branch 'origin/MetLife_v5.4' into Telemetry
# Conflicts:
#	CHANGELOG.md
2019-04-05 14:31:59 -04:00
Chris Cameron
40342e2d9e Merge remote-tracking branch 'origin/MetLife_v5.4' into Telemetry 2019-04-03 16:23:52 -04:00
Chris Cameron
b2ca43baf1 feat: Adding extension methods for writing properties to JSON 2019-04-02 16:37:18 -04:00
Chris Cameron
f36b9f7856 fix: Fixing format exception when parsing JSON DateTime with timezone info 2019-04-01 16:47:08 -04:00
Chris Cameron
bcf13ef972 perf: Optimizing object instantiation for default constructors 2019-04-01 14:16:56 -04:00
Chris Cameron
100b8e4753 fix: JsonReader GetValueAsString ignores token type 2019-04-01 12:27:06 -04:00
Chris Cameron
134ee85067 feat: Adding JsonReader extension to read current value as DateTime 2019-03-31 20:38:22 -04:00
Chris Cameron
c054a9d752 fix: Fixing argument exceptions when looking up LAN2 properties on a system without multiple network adapters 2019-03-28 10:36:04 -04:00
Chris Cameron
ef19e20d67 docs: Updating changelog 2019-03-27 11:24:35 -04:00
Chris Cameron
3fd344a308 fix: Adding missing methods to Net Standard 2019-03-27 10:49:29 -04:00
Chris Cameron
17e7f4d3c9 Merge remote-tracking branch 'origin/feat/seeded_guid' into Telemetry
# Conflicts:
#	ICD.Common.Utils/Attributes/RangeAttribute.cs
2019-03-26 11:58:07 -04:00
Chris Cameron
87d1f4da16 feat: Added util method for generating seeded guids 2019-03-26 11:28:59 -04:00
Chris Cameron
88a4801f8e feat: Added extension method for generating stable string hashcodes 2019-03-26 11:28:15 -04:00
Jack Kanarish
c55e35ac6e Saftey commit for CC 2019-03-25 13:51:29 -04:00
Chris Cameron
24601b0ef2 fix: Potential fix for sqlite database locked exception 2019-03-14 16:31:13 -04:00
Chris Cameron
4fa46ff5a0 Merge remote-tracking branch 'origin/fix/VC4_Fixes' into ConnectPro_v1.2 2019-03-13 16:28:18 -04:00
Chris Cameron
827ab2cd42 refactor: Removing unused code, loosening attribute type constraints 2019-03-13 16:26:53 -04:00
Drew Tingen
158c261d19 fix: VC4 Compat Fixes 2019-03-09 14:51:44 -05:00
Chris Cameron
c607d1254e chore: Updating changelog, incrementing minor version 2019-03-01 14:48:57 -05:00
Chris Cameron
e90914664f Merge remote-tracking branch 'origin/ConnectPro_v1.3' into ConnectPro_v1.2 2019-03-01 14:32:25 -05:00
Chris Cameron
fc855d407b Merge remote-tracking branch 'origin/fix/IcdConsole' into ConnectPro_v1.2 2019-03-01 14:32:13 -05:00
Chris Cameron
e3a4713b3b fix: Fixed bug preventing deserialization of XML lists 2019-03-01 14:29:46 -05:00
Drew Tingen
f85896e947 fix: PrintLine raises OnConoslePrint, Crestron Console Response uses PrintLine, Better environment checks 2019-02-24 16:19:03 -05:00
Chris Cameron
131e2f87f4 feat: Adding constructor to BiDictionary to build from an existing dict 2019-02-21 14:04:06 -05:00
Chris Cameron
4a330637a7 feat: Type IsAssignableTo extension shim 2019-02-19 14:32:32 -05:00
Chris Cameron
fa124a0afc refactor: Resolving warning 2019-02-11 12:13:56 -05:00
Chris Cameron
72fd823643 test: Fixing unit tests 2019-02-07 17:13:25 -05:00
Chris Cameron
644388edad chore: Updating changelog, incrementing minor version 2019-02-07 16:55:22 -05:00
Chris Cameron
cbb05c8b79 refactor: Removing unused code 2019-02-07 16:53:33 -05:00
Chris Cameron
066c9f93a7 chore: Updating AssemblyInfo 2019-02-07 15:32:49 -05:00
Chris Cameron
9aa7459b0f chore: Updating changelog 2019-02-07 14:42:22 -05:00
Jack Kanarish
7557e01c9f feat: add processor utilities and environment utilities for telemetry 2019-02-07 10:45:06 -05:00
Chris Cameron
f8a813c97b perf: Removing redundant code, logging micro-optimization 2019-02-07 10:37:35 -05:00
Chris Cameron
be6a6de65a perf: ReprBuilder micro-optimizations 2019-02-06 17:09:37 -05:00
Chris Cameron
ffe3e67241 perf: Better JSON serialization of nullable types 2019-02-06 13:10:52 -05:00
Chris Cameron
141d911eb0 perf: Reduced size of JSON serialized nullable types 2019-02-06 11:31:14 -05:00
Chris Cameron
d6abf3fdf6 perf: Don't serialize namespace for builtin types 2019-02-04 13:22:59 -05:00
Chris Cameron
46a1ea09b6 refactor: Moving JSON type name util into TypeExtensions 2019-02-04 12:03:15 -05:00
Chris Cameron
2dc705d335 perf: Significantly reducing the size of JSON serialized types 2019-02-04 11:38:39 -05:00
Chris Cameron
0700a357dd feat: Adding ToStringJsonConverter 2019-02-01 14:52:33 -05:00
Chris Cameron
5fb7636ed4 feat: Extension method for reading JSON token as a Guid 2019-01-30 10:52:44 -05:00
Chris Cameron
196c2a535a feat: Added shims for ReflectionUtils.SubscribeEvent for known callbacks 2019-01-29 21:59:10 -05:00
Chris Cameron
db50ada952 refactor: Tidying 2019-01-29 17:49:23 -05:00
Chris Cameron
087b04fd62 chore: Updating changelog, incrementing major version 2019-01-29 14:52:36 -05:00
Chris Cameron
ea73351d39 refactor: Removing redundant critical section, support for chaining TableBuilder methods 2019-01-28 16:58:21 -05:00
Chris Cameron
ca1fae29b0 chore: Updating nuget packages 2019-01-28 14:19:38 -05:00
Chris Cameron
1916c2b750 refactor: Reducing duplicate code 2019-01-28 14:02:16 -05:00
Chris Cameron
3af2544e70 feat: ReprBuilder better supports method chaining 2019-01-28 13:32:35 -05:00
Chris Cameron
20e8aa93f2 Merge branch 'feat/ConsoleOnPrint' of Common/Utils into dev 2019-01-28 13:04:40 +00:00
Drew Tingen
3937902f38 Merge remote-tracking branch 'origin/dev' into feat/ConsoleOnPrint
# Conflicts:
#	CHANGELOG.md
2019-01-27 22:59:25 -08:00
Drew Tingen
021d5781a3 Merge branch 'feat/json' of Common/Utils into dev 2019-01-28 06:56:15 +00:00
Drew Tingen
b429e4bc53 feat: OnConsolePrint event and better VC-4 console support 2019-01-27 22:55:24 -08:00
Chris Cameron
4a203e2449 refactor: Reducing duplicate code 2019-01-27 17:55:47 -05:00
Chris Cameron
d41203b856 docs: Updating changelog 2019-01-25 17:11:08 -05:00
Chris Cameron
2f21379e52 Merge remote-tracking branch 'origin/dev' into feat/json 2019-01-25 17:10:03 -05:00
Chris Cameron
bd2ea606ae docs: Updating changelog 2019-01-25 16:52:09 -05:00
Chris Cameron
1f20c07e94 refactor: Splitting JSON extensions into Reader and Writer extensions, removing unused code 2019-01-25 14:06:51 -05:00
Chris Cameron
1be588b86a refactor: Simplifying JSON converters 2019-01-25 13:57:41 -05:00
Chris Cameron
488df297fc refactor: Removing unused code 2019-01-25 13:57:19 -05:00
Chris Cameron
80a4d94358 refactor: Removing unused code 2019-01-24 17:28:59 -05:00
Chris Cameron
6a40f3ce18 refactor: Tidying 2019-01-24 16:46:07 -05:00
Chris Cameron
d564a0a423 feat: Adding shorthand method for serializing an object into a JSON message 2019-01-24 16:21:29 -05:00
Chris Cameron
a9a544c433 feat: Simplifying generic JSON converters 2019-01-24 15:58:46 -05:00
Chris Cameron
2e0837f5c8 feat: Extension methods for reading current JSON token to the given type 2019-01-24 15:58:21 -05:00
Chris Cameron
77be0ec477 refactor: Removing unused code 2019-01-24 15:57:53 -05:00
112 changed files with 6892 additions and 2307 deletions

View File

@@ -6,6 +6,223 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## [Unreleased]
## [11.0.0] - 2020-03-20
### Added
- Added Not null tag for ICDUriBuilder Constructor that takes a URI as an argument.
- Added MathUtils methods for converting to and from percentages
- Added enum extensions for finding the inclusion and exclusion of enum flags
- Added DateTime extensions for adding years, months, days, hours, minutes and wrapping without modifying other values
- Added shims for deserializing an XML array using a callback for each item
- Added methods for serializing an XML array
- Added WriteAllByte method on IcdFile.
- Added PathUtils for building paths in the HTML directory
- Added public access to GetValues enumeration extension
- Added extensions for getting JsonReader values as long or ulong
- Added DateTimeUtils methods for creating DateTimes from epoch seconds or milliseconds
- Added utils for splitting ANSI into spans for conversion to XAML, HTML, etc
### Changed
- Fixed exception trying to get DHCP status of network interfaces on Linux
- Fixed a bug where color formatted console output on Net Standard was not raising the OnConsolePrint event
- Simplifying ANSI color methods, better cross-platform color support
- Console uses unicode for table drawing on Net Standard
- Using UTC for tracking scheduled events, fixes issues with DST
- Using UTC for tracking durations
- Fixed a bug where table width calculations were not considering unprintable characters
## [10.3.0] - 2020-01-20
### Changed
- Network/MAC/DNS address utils are now enumerating all adapter types
- Ignoring Crestron ethernet parameters that say "Invalid Value"
- Skipping network interfaces with an invalid adapter id
## [10.2.0] - 2019-12-04
### Added
- Added shim methods for finding closest DateTimes from a sequence
## [10.1.0] - 2019-11-18
### Added
- Added PathUtils methods for getting ProgramData paths
- Added a method for determining if a URI is defaults
- Added MaxOrDefault extension method for enumerables
- Added a method for finding an item in a sorted list by a given predicate
### Changed
- NullObject implements IComparable, fixes issues with null keys in ordered dictionaries
- IcdSqliteConnection CreateFile method will create directories recursively
## [10.0.0] - 2019-10-07
### Added
- IcdEnvironment.GetUtcTime() to get UTC representaiton of current time.
- Extension methods for determining if a sequence is in order
- Overload for calculating the modulus of longs
- Default implementation for AbstractGenericXmlConverter Instantiate method
- Additional binary search extensions, now working for all ILists
- Added NullObject as a means of having null keys in hash tables
### Changed
- Potential fix for unhelpful exception messages coming from SafeCriticalSection.Execute
- Small performance improvement when copying arrays
## [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.8.1] - 2020-02-18
### Changed
- IcdTimer - fixed issue that prevented OnElapsed event from firing when Length is less than (or close to) Heartbeat Interval
## [8.8.0] - 2020-01-23
### Added
- Added an overload to PriorityQueue for determing the de-duplication behaviour
## [8.7.2] - 2019-10-29
### Changed
- Fixed a bug with PriorityQueue de-duplication where a new command would be inserted in the wrong position
## [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
@@ -74,7 +291,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- New XML conversion framework for performance improvements
### Changed
- XmlUtils is now using the improved XML conversion framework
- XmlUtils is now using the improved XML conversion framework
- Better implementation of DictionaryExtensions.ToInverse
## [5.0.0] - 2018-09-14
@@ -147,8 +364,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Adding extension method for getting Informational Version from an Assembly
- Adding WeakKeyDictionary for caching
- Reflection util methods
### Changed
- JSON serialization/deserialization features moved into base converter
- Removed suffix from assembly name

View File

@@ -0,0 +1,27 @@
using System.Linq;
using NUnit.Framework;
namespace ICD.Common.Utils.Tests
{
[TestFixture]
public sealed class AnsiUtilsTest
{
[Test]
public void ToSpansTest()
{
string ansi = "\x1b[30mblack\x1b[37mwhite\x1b[0mdefault";
AnsiSpan[] spans = AnsiUtils.ToSpans(ansi).ToArray();
Assert.AreEqual(3, spans.Length);
Assert.AreEqual("black", spans[0].Text);
Assert.AreEqual("30", spans[0].Code);
Assert.AreEqual("white", spans[1].Text);
Assert.AreEqual("37", spans[1].Code);
Assert.AreEqual("default", spans[2].Text);
Assert.AreEqual("0", spans[2].Code);
}
}
}

View 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
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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

View File

@@ -133,8 +133,8 @@ namespace ICD.Common.Utils.Tests.Collections
};
Assert.AreEqual(1, dequeue[0]);
Assert.AreEqual(4, dequeue[1]);
Assert.AreEqual(3, dequeue[2]);
Assert.AreEqual(3, dequeue[1]);
Assert.AreEqual(4, dequeue[2]);
}
[Test]

View 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));
}
}
}

View File

@@ -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();
}

View File

@@ -284,6 +284,15 @@ namespace ICD.Common.Utils.Tests.Extensions
Assert.AreEqual(5, items.Length);
}
[TestCase(true)]
[TestCase(true, 1, 2, 3, 4)]
[TestCase(true, 1, 2, 2, 3, 4)]
[TestCase(false, 4, 3, 2, 1)]
public void AreOrderedTest(bool expected, params int[] items)
{
Assert.AreEqual(expected, items.AreOrdered());
}
[Test]
public void OrderTest()
{

View File

@@ -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]);
}
}
}

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Utils.Extensions;
using NUnit.Framework;
@@ -9,14 +8,14 @@ namespace ICD.Common.Utils.Tests.Extensions
public sealed class ListExtensionsTest
{
[Test]
public void AddSortedTest()
public void InsertSortedTest()
{
List<int> testList = new List<int>();
Assert.AreEqual(0, testList.AddSorted(2));
Assert.AreEqual(1, testList.AddSorted(3));
Assert.AreEqual(0, testList.AddSorted(1));
Assert.AreEqual(1, testList.AddSorted(2));
Assert.AreEqual(0, testList.InsertSorted(2));
Assert.AreEqual(1, testList.InsertSorted(3));
Assert.AreEqual(0, testList.InsertSorted(1));
Assert.AreEqual(1, testList.InsertSorted(2));
Assert.AreEqual(4, testList.Count);
Assert.AreEqual(1, testList[0]);
@@ -26,15 +25,15 @@ namespace ICD.Common.Utils.Tests.Extensions
}
[Test]
public void AddSortedComparerTest()
public void InsertSortedComparerTest()
{
List<int> testList = new List<int>();
IComparer<int> comparer = new InverseComparer();
Assert.AreEqual(0, testList.AddSorted(2, comparer));
Assert.AreEqual(0, testList.AddSorted(3, comparer));
Assert.AreEqual(2, testList.AddSorted(1, comparer));
Assert.AreEqual(1, testList.AddSorted(2, comparer));
Assert.AreEqual(0, testList.InsertSorted(2, comparer));
Assert.AreEqual(0, testList.InsertSorted(3, comparer));
Assert.AreEqual(2, testList.InsertSorted(1, comparer));
Assert.AreEqual(1, testList.InsertSorted(2, comparer));
Assert.AreEqual(4, testList.Count);
Assert.AreEqual(3, testList[0]);
@@ -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)

View 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);
}
}
}

View File

@@ -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?>")]

View File

@@ -20,9 +20,15 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.11.0" />
<Compile Remove="binNetCoreApp\**" />
<EmbeddedResource Remove="binNetCoreApp\**" />
<None Remove="binNetCoreApp\**" />
</ItemGroup>
<ItemGroup>
<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>

View File

@@ -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)
{

View File

@@ -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";

View File

@@ -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));
}
}
}

View File

@@ -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()
{

View File

@@ -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
}
}

View File

@@ -12,7 +12,7 @@ namespace ICD.Common.Utils.Tests.Services.Logging
public void TimestampTest()
{
LogItem item = new LogItem(eSeverity.Critical, null);
DateTime time = IcdEnvironment.GetLocalTime();
DateTime time = IcdEnvironment.GetUtcTime();
Assert.IsTrue((time - item.Timestamp).TotalSeconds <= 1);
}

View File

@@ -13,7 +13,7 @@ namespace ICD.Common.Utils.Tests
Assert.IsTrue(ThreadingUtils.Wait(() => true, 100));
bool complete = false;
DateTime time = IcdEnvironment.GetLocalTime();
DateTime time = IcdEnvironment.GetUtcTime();
ThreadingUtils.SafeInvoke(() =>
{
@@ -22,15 +22,15 @@ namespace ICD.Common.Utils.Tests
});
Assert.IsTrue(ThreadingUtils.Wait(() => complete, 200));
Assert.AreEqual(100, (IcdEnvironment.GetLocalTime() - time).TotalMilliseconds, 20);
Assert.AreEqual(100, (IcdEnvironment.GetUtcTime() - time).TotalMilliseconds, 20);
}
[Test]
public void Sleep()
{
DateTime now = IcdEnvironment.GetLocalTime();
DateTime now = IcdEnvironment.GetUtcTime();
ThreadingUtils.Sleep(1000);
DateTime now2 = IcdEnvironment.GetLocalTime();
DateTime now2 = IcdEnvironment.GetUtcTime();
Assert.AreEqual(1000, (now2 - now).TotalMilliseconds, 100);
}

View 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);
}
}
}

View 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();
}
}
}

View File

@@ -0,0 +1,183 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace ICD.Common.Utils
{
public static class AnsiUtils
{
public const string COLOR_RED = "\x1b[31;1m";
public const string COLOR_GREEN = "\x1b[32;1m";
public const string COLOR_YELLOW = "\x1b[33;1m";
public const string COLOR_BLUE = "\x1b[34;1m";
public const string COLOR_MAGENTA = "\x1b[35;1m";
public const string COLOR_CYAN = "\x1b[36;1m";
public const string COLOR_WHITE = "\x1b[37;1m";
public const string COLOR_YELLOW_ON_RED_BACKGROUND = "\x1b[93;41m";
public const string ANSI_RESET = "\x1b[0m";
public const string CODE_BLACK = "30";
public const string CODE_RED = "31";
public const string CODE_GREEN = "32";
public const string CODE_YELLOW = "33";
public const string CODE_BLUE = "34";
public const string CODE_MAGENTA = "35";
public const string CODE_CYAN = "36";
public const string CODE_WHITE = "37";
public const string CODE_BRIGHT_BLACK = "30;1";
public const string CODE_BRIGHT_RED = "31;1";
public const string CODE_BRIGHT_GREEN = "32;1";
public const string CODE_BRIGHT_YELLOW = "33;1";
public const string CODE_BRIGHT_BLUE = "34;1";
public const string CODE_BRIGHT_MAGENTA = "35;1";
public const string CODE_BRIGHT_CYAN = "36;1";
public const string CODE_BRIGHT_WHITE = "37;1";
/// <summary>
/// Matches ANSI escape codes, e.g. \x1b[31m and \x1b[30;1m
/// </summary>
public const string ANSI_REGEX = "(?'match'\x01b\\[(?'code'[\\d;]+)m)";
/// <summary>
/// Matches ANSI escape codes to HTML styles.
/// Color values are taken from PuTTY.
/// </summary>
private static readonly Dictionary<string, string> s_PuttyColors =
new Dictionary<string, string>
{
{CODE_BLACK, "#000000"},
{CODE_RED, "#BB0000"},
{CODE_GREEN, "#00BB00"},
{CODE_YELLOW, "#BBBB00"},
{CODE_BLUE, "#0000BB"},
{CODE_MAGENTA, "#BB00BB"},
{CODE_CYAN, "#00BBBB"},
{CODE_WHITE, "#BBBBBB"},
{CODE_BRIGHT_BLACK, "#555555"},
{CODE_BRIGHT_RED, "#FF5555"},
{CODE_BRIGHT_GREEN, "#55FF55"},
{CODE_BRIGHT_YELLOW, "#FFFF55"},
{CODE_BRIGHT_BLUE, "#5555FF"},
{CODE_BRIGHT_MAGENTA, "#FF55FF"},
{CODE_BRIGHT_CYAN, "#55FFFF"},
{CODE_BRIGHT_WHITE, "#FFFFFF"}
};
/// <summary>
/// Gets the color map matching PuTTY.
/// </summary>
public static IDictionary<string, string> PuttyColors { get { return s_PuttyColors; } }
/// <summary>
/// Constructor.
/// </summary>
static AnsiUtils()
{
#if !SIMPLSHARP
// Enables ANSI color output in windows/linux console
Pastel.ConsoleExtensions.Enable();
#endif
}
/// <summary>
/// Prefixes the given data with an ANSI control sequence and suffixes with a reset sequence.
/// </summary>
/// <param name="data"></param>
/// <param name="ansiSequence"></param>
/// <returns></returns>
public static string Format(string data, string ansiSequence)
{
// % needs to be escaped or weird things happen
data = string.IsNullOrEmpty(data) ? data : data.Replace("%", "%%");
return string.Format("{0}{1}{2}", ansiSequence, data, ANSI_RESET);
}
/// <summary>
/// Splits the given ANSI string into spans.
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static IEnumerable<AnsiSpan> ToSpans(string data)
{
if (string.IsNullOrEmpty(data))
yield break;
Regex regex = new Regex(ANSI_REGEX);
Match match = regex.Match(data);
// No matches
if (!match.Success)
yield return new AnsiSpan {Text = data};
// Find the spans
while (match.Success)
{
// Get the code
string code = match.Groups["code"].Value;
// Get the text
Match next = match.NextMatch();
int startIndex = match.Index + match.Length;
int endIndex = next.Success ? next.Index : data.Length;
string text = data.Substring(startIndex, endIndex - startIndex);
// Build the span
if (text.Length > 0)
yield return new AnsiSpan { Code = code, Text = text };
// Loop
match = next;
}
}
/// <summary>
/// Removes the bright suffix from the code if present, otherwise appends a bright suffix.
/// </summary>
/// <param name="code"></param>
/// <returns></returns>
public static string InvertBright(string code)
{
return code.EndsWith(";1")
? code.Substring(0, code.Length - 2)
: code + ";1";
}
}
public sealed class AnsiSpan
{
public string Code { get; set; }
public string Text { get; set; }
/// <summary>
/// Gets the color value for the code.
/// </summary>
/// <param name="colors"></param>
/// <param name="invertBright"></param>
/// <returns></returns>
public string GetColor(IDictionary<string, string> colors, bool invertBright)
{
if (colors == null)
throw new ArgumentNullException("colors");
return GetColor<string>(colors, invertBright);
}
/// <summary>
/// Gets the color value for the code.
/// </summary>
/// <param name="colors"></param>
/// <param name="invertBright"></param>
/// <returns></returns>
public T GetColor<T>(IDictionary<string, T> colors, bool invertBright)
{
if (colors == null)
throw new ArgumentNullException("colors");
string code = invertBright ? AnsiUtils.InvertBright(Code) : Code;
return colors[code];
}
}
}

View File

@@ -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,139 +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, 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_AttributeToTypeCache = new Dictionary<Attribute, Type>();
s_TypeToAttributesCache = new Dictionary<Type, IcdHashSet<Attribute>>();
}
#region Caching
/// <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;
s_CachedAssemblies.Add(assembly);
#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);
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);
try
{
s_TypeToAttributesCache[type] = new IcdHashSet<Attribute>(type.GetCustomAttributes<Attribute>(false));
foreach (Attribute attribute in s_TypeToAttributesCache[type])
s_AttributeToTypeCache[attribute] = type;
}
// GetMethods for Open Generic Types is not supported.
catch (NotSupportedException)
{
}
// Not sure why this happens :/
catch (InvalidProgramException)
{
}
}
#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>()
{
return s_AttributeToTypeCache.Select(kvp => kvp.Key)
.OfType<T>();
}
/// <summary>
/// Gets the first attribute on the given class type matching the generic type.
/// </summary>
@@ -161,11 +25,24 @@ namespace ICD.Common.Utils
/// <returns></returns>
[CanBeNull]
public static T GetClassAttribute<T>(Type type)
{
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>
@@ -179,39 +56,28 @@ namespace ICD.Common.Utils
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.
/// 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<Attribute> GetClassAttributes(Type type)
public static IEnumerable<T> GetClassAttributes<T>(Type type, bool inherit)
{
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];
// ReSharper disable InvokeAsExtensionMethod
return ReflectionExtensions.GetCustomAttributes<T>(
#if SIMPLSHARP
(CType)
#endif
type, inherit);
// ReSharper restore InvokeAsExtensionMethod
}
/// <summary>
@@ -237,7 +103,5 @@ namespace ICD.Common.Utils
.Where(p => ReflectionExtensions.GetCustomAttributes<T>(p, inherit).Any());
// ReSharper restore InvokeAsExtensionMethod
}
#endregion
}
}

View File

@@ -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
{
}
}

View File

@@ -0,0 +1,6 @@
namespace ICD.Common.Utils.Attributes
{
public interface IIcdAttribute
{
}
}

View File

@@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils.Attributes
{
@@ -9,90 +12,274 @@ namespace ICD.Common.Utils.Attributes
[AttributeUsage(AttributeTargets.Property |
AttributeTargets.Field |
AttributeTargets.Parameter |
AttributeTargets.ReturnValue,
AllowMultiple = false,
Inherited = true)]
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
[NotNull]
public object Min { get; private set; }
/// <summary>
/// Gets the min value for this range.
/// </summary>
public object Min { get { return m_Min; } }
[NotNull]
public object Max { get; private set; }
[NotNull]
private Type Type { get { return Min.GetType(); } }
/// <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)
{
Min = min;
Max = max;
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(short min, short max)
: this((object)min, (object)max)
{
Min = min;
Max = max;
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(uint min, uint max)
: this((object)min, (object)max)
{
Min = min;
Max = max;
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(int min, int max)
: this((object)min, (object)max)
{
Min = min;
Max = max;
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(ulong min, ulong max)
: this((object)min, (object)max)
{
Min = min;
Max = max;
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(long min, long max)
: this((object)min, (object)max)
{
Min = min;
Max = max;
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(float min, float max)
: this((object)min, (object)max)
{
Min = min;
Max = max;
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(double min, double max)
: this((object)min, (object)max)
{
Min = min;
Max = max;
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(byte min, byte max)
: this((object)min, (object)max)
{
Min = min;
Max = max;
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(sbyte min, sbyte max)
: this((object)min, (object)max)
{
Min = min;
Max = max;
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
public RangeAttribute(decimal min, decimal max)
: this((object)min, (object)max)
{
Min = min;
Max = 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
@@ -100,127 +287,239 @@ namespace ICD.Common.Utils.Attributes
#region Methods
/// <summary>
/// Returns true if the given value is within the range of Min to Max.
/// 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 bool IsInRange(object value)
[NotNull]
public static object Remap([NotNull] object value, [NotNull] Type type)
{
if (value == null)
throw new ArgumentNullException("value");
if (value.GetType() != Type)
throw new ArgumentException("the type of value does not match the type of min / max");
if (type == null)
throw new ArgumentNullException("type");
if (value is ushort)
{
var castMin = (ushort)Min;
var castMax = (ushort)Max;
var castVal = (ushort)value;
return (castVal >= castMin && castVal <= castMax);
}
if (!type.IsNumeric())
throw new ArgumentException("Target type is not numeric");
if (value is short)
{
var castMin = (short)Min;
var castMax = (short)Max;
var castVal = (short)value;
return (castVal >= castMin && castVal <= castMax);
}
if (!value.GetType().IsNumeric())
throw new ArgumentException("Source value is not numeric");
if (value is uint)
{
var castMin = (uint)Min;
var castMax = (uint)Max;
var castVal = (uint)value;
return (castVal >= castMin && castVal <= castMax);
}
if (value is int)
{
var castMin = (int)Min;
var castMax = (int)Max;
var castVal = (int)value;
return (castVal >= castMin && castVal <= castMax);
}
if (value is ulong)
{
var castMin = (ulong)Min;
var castMax = (ulong)Max;
var castVal = (ulong)value;
return (castVal >= castMin && castVal <= castMax);
}
if (value is long)
{
var castMin = (long)Min;
var castMax = (long)Max;
var castVal = (long)value;
return (castVal >= castMin && castVal <= castMax);
}
if (value is float)
{
var castMin = (float)Min;
var castMax = (float)Max;
var castVal = (float)value;
return (castVal >= castMin && castVal <= castMax);
}
if (value is double)
{
var castMin = (double)Min;
var castMax = (double)Max;
var castVal = (double)value;
return (castVal >= castMin && castVal <= castMax);
}
if (value is decimal)
{
var castMin = (decimal)Min;
var castMax = (decimal)Max;
var castVal = (decimal)value;
return (castVal >= castMin && castVal <= castMax);
}
if (value is byte)
{
var castMin = (byte)Min;
var castMax = (byte)Max;
var castVal = (byte)value;
return (castVal >= castMin && castVal <= castMax);
}
if (value is sbyte)
{
var castMin = (sbyte)Min;
var castMax = (sbyte)Max;
var castVal = (sbyte)value;
return (castVal >= castMin && castVal <= castMax);
}
throw new ArgumentException("the type of value is not a numeric type.");
double intermediate = RemapToDouble(value);
return RemapFromDouble(intermediate, type);
}
public ushort RemapRangeToUShort(double value)
/// <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([NotNull] object value)
{
return (ushort)MathUtils.MapRange((double)Min, (double)Max, ushort.MinValue, ushort.MaxValue, 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);
}
public ushort RemapRangeToUShort(float 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>
[NotNull]
public static object RemapFromDouble(double value, [NotNull] Type type)
{
return (ushort)MathUtils.MapRange((float)Min, (float)Max, ushort.MinValue, ushort.MaxValue, value);
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);
}
public ushort RemapRangeToUShort(int value)
/// <summary>
/// Remaps the given numeric value to the defined min/max.
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
[NotNull]
public object RemapMinMax([NotNull] object value)
{
return (ushort)MathUtils.MapRange((int)Min, (int)Max, ushort.MinValue, ushort.MaxValue, 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);
}
public ushort RemapRangeToUShort(ushort 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>
[NotNull]
public static object Clamp([NotNull] object value, [NotNull] Type type)
{
return MathUtils.MapRange((ushort)Min, (ushort)Max, ushort.MinValue, ushort.MaxValue, value);
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, [NotNull] 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>
/// 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>
[NotNull]
public object ClampMinMaxThenRemap([NotNull] object value, [NotNull] 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);
}
#endregion
#region Private Methods
[NotNull]
private object RemapMinMax([NotNull] object value, [NotNull] 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);
}
/// <summary>
/// Gets the min value for the given numeric type as a double.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private static double GetMinAsDouble([NotNull] 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([NotNull] 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

View File

@@ -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
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Collections
{
@@ -20,8 +21,10 @@ namespace ICD.Common.Utils.Collections
public bool IsReadOnly { get { return false; } }
[NotNull]
public ICollection<TKey> Keys { get { return m_KeyToValue.Keys; } }
[NotNull]
public ICollection<TValue> Values { get { return m_ValueToKey.Keys; } }
#endregion
@@ -35,6 +38,20 @@ namespace ICD.Common.Utils.Collections
m_ValueToKey = new Dictionary<TValue, TKey>();
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="dict"></param>
public BiDictionary([NotNull] Dictionary<TKey, TValue> dict)
: this()
{
if (dict == null)
throw new ArgumentNullException("dict");
foreach (KeyValuePair<TKey, TValue> kvp in dict)
Add(kvp.Key, kvp.Value);
}
#region Methods
public void Clear()
@@ -43,24 +60,31 @@ namespace ICD.Common.Utils.Collections
m_ValueToKey.Clear();
}
public bool ContainsKey(TKey key)
public bool ContainsKey([NotNull] TKey key)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
if (key == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("key");
return m_KeyToValue.ContainsKey(key);
}
public bool ContainsValue(TValue value)
public bool ContainsValue([NotNull] TValue value)
{
return m_ValueToKey.ContainsKey(value);
}
public void Add(TKey key, TValue value)
public void Add([NotNull] TKey key, [NotNull] TValue value)
{
// ReSharper disable once CompareNonConstrainedGenericWithNull
// ReSharper disable CompareNonConstrainedGenericWithNull
if (key == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("key");
// ReSharper disable once CompareNonConstrainedGenericWithNull
// ReSharper disable CompareNonConstrainedGenericWithNull
if (value == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("value");
if (ContainsKey(key))
@@ -73,14 +97,16 @@ namespace ICD.Common.Utils.Collections
m_ValueToKey.Add(value, key);
}
public void Set(TKey key, TValue value)
public void Set([NotNull] TKey key, [NotNull] TValue value)
{
// ReSharper disable once CompareNonConstrainedGenericWithNull
// ReSharper disable CompareNonConstrainedGenericWithNull
if (key == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("key");
// ReSharper disable once CompareNonConstrainedGenericWithNull
// ReSharper disable CompareNonConstrainedGenericWithNull
if (value == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("value");
RemoveKey(key);
@@ -89,18 +115,35 @@ namespace ICD.Common.Utils.Collections
Add(key, value);
}
public TKey GetKey(TValue value)
[NotNull]
public TKey GetKey([NotNull] TValue value)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
if (value == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("value");
return m_ValueToKey[value];
}
public TValue GetValue(TKey key)
[NotNull]
public TValue GetValue([NotNull] TKey key)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
if (key == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("key");
return m_KeyToValue[key];
}
public bool RemoveKey(TKey key)
public bool RemoveKey([NotNull] TKey key)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
if (key == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("key");
if (!ContainsKey(key))
return false;
@@ -112,8 +155,13 @@ namespace ICD.Common.Utils.Collections
return true;
}
public bool RemoveValue(TValue value)
public bool RemoveValue([NotNull] TValue value)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
if (value == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("value");
if (!ContainsValue(value))
return false;
@@ -122,13 +170,23 @@ namespace ICD.Common.Utils.Collections
return RemoveKey(key);
}
public bool TryGetValue(TKey key, out TValue value)
public bool TryGetValue([NotNull] TKey key, out TValue value)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
if (key == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("key");
return m_KeyToValue.TryGetValue(key, out value);
}
public bool TryGetKey(TValue value, out TKey key)
public bool TryGetKey([NotNull] TValue value, out TKey key)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
if (value == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("value");
return m_ValueToKey.TryGetValue(value, out key);
}
@@ -136,9 +194,10 @@ namespace ICD.Common.Utils.Collections
#region IDictionary
TValue IDictionary<TKey, TValue>.this[TKey key] { get { return GetValue(key); } set { Set(key, value); } }
[NotNull]
TValue IDictionary<TKey, TValue>.this[[NotNull] TKey key] { get { return GetValue(key); } set { Set(key, value); } }
bool IDictionary<TKey, TValue>.Remove(TKey key)
bool IDictionary<TKey, TValue>.Remove([NotNull] TKey key)
{
return RemoveKey(key);
}
@@ -162,7 +221,7 @@ namespace ICD.Common.Utils.Collections
return RemoveKey(item.Key);
}
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo([NotNull] KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
(m_KeyToValue as IDictionary<TKey, TValue>).CopyTo(array, arrayIndex);
}
@@ -171,11 +230,13 @@ namespace ICD.Common.Utils.Collections
#region IEnumerable
[NotNull]
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return m_KeyToValue.GetEnumerator();
}
[NotNull]
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();

View File

@@ -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
{
@@ -48,7 +49,7 @@ namespace ICD.Common.Utils.Collections
/// Constructor.
/// </summary>
/// <param name="items"></param>
public IcdHashSet(IEnumerable<T> items)
public IcdHashSet([NotNull] IEnumerable<T> items)
: this(EqualityComparer<T>.Default, items)
{
}
@@ -57,7 +58,7 @@ namespace ICD.Common.Utils.Collections
/// Constructor.
/// </summary>
/// <param name="comparer"></param>
public IcdHashSet(IEqualityComparer<T> comparer)
public IcdHashSet([NotNull] IEqualityComparer<T> comparer)
: this(comparer, Enumerable.Empty<T>())
{
}
@@ -67,7 +68,7 @@ namespace ICD.Common.Utils.Collections
/// </summary>
/// <param name="comparer"></param>
/// <param name="items"></param>
public IcdHashSet(IEqualityComparer<T> comparer, IEnumerable<T> items)
public IcdHashSet([NotNull] IEqualityComparer<T> comparer, [NotNull] IEnumerable<T> items)
{
if (comparer == null)
throw new ArgumentNullException("comparer");
@@ -90,7 +91,8 @@ namespace ICD.Common.Utils.Collections
/// <param name="set"></param>
/// <returns></returns>
[PublicAPI]
public IcdHashSet<T> Union(IEnumerable<T> set)
[NotNull]
public IcdHashSet<T> Union([NotNull] IEnumerable<T> set)
{
if (set == null)
throw new ArgumentNullException("set");
@@ -107,7 +109,8 @@ namespace ICD.Common.Utils.Collections
/// <param name="set"></param>
/// <returns></returns>
[PublicAPI]
public IcdHashSet<T> Subtract(IEnumerable<T> set)
[NotNull]
public IcdHashSet<T> Subtract([NotNull] IEnumerable<T> set)
{
if (set == null)
throw new ArgumentNullException("set");
@@ -126,7 +129,8 @@ namespace ICD.Common.Utils.Collections
/// <param name="set"></param>
/// <returns></returns>
[PublicAPI]
public IcdHashSet<T> Intersection(IEnumerable<T> set)
[NotNull]
public IcdHashSet<T> Intersection([NotNull] IEnumerable<T> set)
{
if (set == null)
throw new ArgumentNullException("set");
@@ -145,7 +149,8 @@ namespace ICD.Common.Utils.Collections
/// <param name="set"></param>
/// <returns></returns>
[PublicAPI]
public IcdHashSet<T> NonIntersection(IEnumerable<T> set)
[NotNull]
public IcdHashSet<T> NonIntersection([NotNull] IEnumerable<T> set)
{
if (set == null)
throw new ArgumentNullException("set");
@@ -169,7 +174,7 @@ namespace ICD.Common.Utils.Collections
/// <param name="set"></param>
/// <returns></returns>
[PublicAPI]
public bool IsSubsetOf(IcdHashSet<T> set)
public bool IsSubsetOf([NotNull] IcdHashSet<T> set)
{
if (set == null)
throw new ArgumentNullException("set");
@@ -183,7 +188,7 @@ namespace ICD.Common.Utils.Collections
/// <param name="set"></param>
/// <returns></returns>
[PublicAPI]
public bool IsProperSubsetOf(IcdHashSet<T> set)
public bool IsProperSubsetOf([NotNull] IcdHashSet<T> set)
{
if (set == null)
throw new ArgumentNullException("set");
@@ -197,7 +202,7 @@ namespace ICD.Common.Utils.Collections
/// <param name="set"></param>
/// <returns></returns>
[PublicAPI]
public bool IsSupersetOf(IcdHashSet<T> set)
public bool IsSupersetOf([NotNull] IcdHashSet<T> set)
{
if (set == null)
throw new ArgumentNullException("set");
@@ -211,7 +216,7 @@ namespace ICD.Common.Utils.Collections
/// <param name="set"></param>
/// <returns></returns>
[PublicAPI]
public bool IsProperSupersetOf(IcdHashSet<T> set)
public bool IsProperSupersetOf([NotNull] IcdHashSet<T> set)
{
if (set == null)
throw new ArgumentNullException("set");
@@ -225,7 +230,7 @@ namespace ICD.Common.Utils.Collections
/// <param name="set"></param>
/// <returns></returns>
[PublicAPI]
public bool SetEquals(IcdHashSet<T> set)
public bool SetEquals([NotNull] IcdHashSet<T> set)
{
if (set == null)
throw new ArgumentNullException("set");
@@ -242,7 +247,7 @@ namespace ICD.Common.Utils.Collections
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool Add(T item)
public bool Add([NotNull] T item)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
if (item == null)
@@ -260,7 +265,7 @@ namespace ICD.Common.Utils.Collections
/// Adds the item to the collection.
/// </summary>
/// <param name="item"></param>
void ICollection<T>.Add(T item)
void ICollection<T>.Add([NotNull] T item)
{
Add(item);
}
@@ -269,7 +274,7 @@ namespace ICD.Common.Utils.Collections
/// Adds each of the items in the sequence to the collection.
/// </summary>
/// <param name="items"></param>
public void AddRange(IEnumerable<T> items)
public void AddRange([NotNull] IEnumerable<T> items)
{
if (items == null)
throw new ArgumentNullException("items");
@@ -292,7 +297,7 @@ namespace ICD.Common.Utils.Collections
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool Contains(T item)
public bool Contains([NotNull] T item)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
if (item == null)
@@ -306,8 +311,11 @@ namespace ICD.Common.Utils.Collections
/// Copies the items of the <see cref="T:System.Collections.Generic.ICollection`1"/> to an <see cref="T:System.Array"/>, starting at a particular <see cref="T:System.Array"/> index.
/// </summary>
/// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the items copied from <see cref="T:System.Collections.Generic.ICollection`1"/>. The <see cref="T:System.Array"/> must have zero-based indexing.</param><param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param><exception cref="T:System.ArgumentNullException"><paramref name="array"/> is null.</exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="arrayIndex"/> is less than 0.</exception><exception cref="T:System.ArgumentException"><paramref name="array"/> is multidimensional.-or-<paramref name="arrayIndex"/> is equal to or greater than the length of <paramref name="array"/>.-or-The number of items in the source <see cref="T:System.Collections.Generic.ICollection`1"/> is greater than the available space from <paramref name="arrayIndex"/> to the end of the destination <paramref name="array"/>.-or-Type T cannot be cast automatically to the type of the destination <paramref name="array"/>.</exception>
public void CopyTo(T[] array, int arrayIndex)
public void CopyTo([NotNull] T[] array, int arrayIndex)
{
if (array == null)
throw new ArgumentNullException("array");
m_Dict.Keys.CopyTo(array, arrayIndex);
}
@@ -318,7 +326,7 @@ namespace ICD.Common.Utils.Collections
/// true if <paramref name="item"/> was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false. This method also returns false if <paramref name="item"/> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1"/>.
/// </returns>
/// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception>
public bool Remove(T item)
public bool Remove([NotNull] T item)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
if (item == null)
@@ -328,6 +336,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([NotNull] IEnumerable<T> items)
{
if (items == null)
throw new ArgumentNullException("items");
m_Dict.RemoveAll(items);
}
#endregion
#region IEnumerable<T>
@@ -339,6 +359,7 @@ namespace ICD.Common.Utils.Collections
/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
/// </returns>
/// <filterpriority>1</filterpriority>
[NotNull]
public IEnumerator<T> GetEnumerator()
{
return m_Dict.Keys.GetEnumerator();
@@ -351,6 +372,7 @@ namespace ICD.Common.Utils.Collections
/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
/// </returns>
/// <filterpriority>2</filterpriority>
[NotNull]
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();

View File

@@ -2,6 +2,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
@@ -19,11 +20,14 @@ namespace ICD.Common.Utils.Collections
public bool IsReadOnly { get { return false; } }
[NotNull]
public ICollection<TKey> Keys { get { return m_OrderedKeys; } }
[NotNull]
public ICollection<TValue> Values { get { return m_ValuesOrderedByKey; } }
public TValue this[TKey key]
[CanBeNull]
public TValue this[[NotNull] TKey key]
{
get { return m_Dictionary[key]; }
set
@@ -32,13 +36,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);
}
}
@@ -56,7 +55,7 @@ namespace ICD.Common.Utils.Collections
/// Constructor.
/// </summary>
/// <param name="comparer"></param>
public IcdOrderedDictionary(IComparer<TKey> comparer)
public IcdOrderedDictionary([NotNull] IComparer<TKey> comparer)
: this(comparer, EqualityComparer<TKey>.Default)
{
}
@@ -66,7 +65,7 @@ namespace ICD.Common.Utils.Collections
/// </summary>
/// <param name="comparer"></param>
/// <param name="equalityComparer"></param>
public IcdOrderedDictionary(IComparer<TKey> comparer, IEqualityComparer<TKey> equalityComparer)
public IcdOrderedDictionary([NotNull] IComparer<TKey> comparer, [NotNull] IEqualityComparer<TKey> equalityComparer)
{
if (comparer == null)
throw new ArgumentNullException("comparer");
@@ -84,7 +83,7 @@ namespace ICD.Common.Utils.Collections
/// Constructor.
/// </summary>
/// <param name="dictionary"></param>
public IcdOrderedDictionary(IEnumerable<KeyValuePair<TKey, TValue>> dictionary)
public IcdOrderedDictionary([NotNull] IEnumerable<KeyValuePair<TKey, TValue>> dictionary)
: this()
{
if (dictionary == null)
@@ -96,22 +95,27 @@ namespace ICD.Common.Utils.Collections
#region Methods
[NotNull]
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return m_OrderedKeys.Select(k => new KeyValuePair<TKey, TValue>(k, m_Dictionary[k]))
.GetEnumerator();
}
public void Add(TKey key, TValue value)
public void Add([NotNull] TKey key, [CanBeNull] TValue value)
{
// ReSharper disable once CompareNonConstrainedGenericWithNull
// ReSharper disable CompareNonConstrainedGenericWithNull
if (key == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
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.InsertSorted(key, m_Comparer);
m_ValuesOrderedByKey.Insert(index, value);
m_Dictionary[key] = value;
}
public void Clear()
@@ -121,15 +125,21 @@ namespace ICD.Common.Utils.Collections
m_Dictionary.Clear();
}
public bool ContainsKey(TKey key)
public bool ContainsKey([NotNull] TKey key)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
if (key == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("key");
return m_Dictionary.ContainsKey(key);
}
public bool Remove(TKey key)
public bool Remove([NotNull] TKey key)
{
// ReSharper disable once CompareNonConstrainedGenericWithNull
// ReSharper disable CompareNonConstrainedGenericWithNull
if (key == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("key");
if (!m_Dictionary.Remove(key))
@@ -143,8 +153,13 @@ namespace ICD.Common.Utils.Collections
return true;
}
public bool TryGetValue(TKey key, out TValue value)
public bool TryGetValue([NotNull] TKey key, out TValue value)
{
// ReSharper disable CompareNonConstrainedGenericWithNull
if (key == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("key");
return m_Dictionary.TryGetValue(key, out value);
}
@@ -152,6 +167,7 @@ namespace ICD.Common.Utils.Collections
#region Private Methods
[NotNull]
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
@@ -169,8 +185,11 @@ namespace ICD.Common.Utils.Collections
EqualityComparer<TValue>.Default.Equals(value, item.Value);
}
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int index)
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo([NotNull] KeyValuePair<TKey, TValue>[] array, int index)
{
if (array == null)
throw new ArgumentNullException("array");
foreach (KeyValuePair<TKey, TValue> kvp in this)
{
array.SetValue(kvp, index);

View File

@@ -30,6 +30,7 @@ namespace ICD.Common.Utils.Collections
/// <summary>
/// Gets a reference for locking.
/// </summary>
[NotNull]
public object SyncRoot { get { return this; } }
#endregion
@@ -59,7 +60,7 @@ namespace ICD.Common.Utils.Collections
/// </summary>
/// <param name="item"></param>
[PublicAPI]
public void Enqueue(T item)
public void Enqueue([CanBeNull] T item)
{
Enqueue(item, int.MaxValue);
}
@@ -71,16 +72,24 @@ namespace ICD.Common.Utils.Collections
/// <param name="item"></param>
/// <param name="priority"></param>
[PublicAPI]
public void Enqueue(T item, int priority)
public void Enqueue([CanBeNull] T item, int priority)
{
List<T> queue;
if (!m_PriorityToQueue.TryGetValue(priority, out queue))
{
queue = new List<T>();
m_PriorityToQueue.Add(priority, queue);
}
m_PriorityToQueue.GetOrAddNew(priority, () => new List<T>())
.Add(item);
m_Count++;
}
queue.Add(item);
/// <summary>
/// Adds the item to the queue with the given priority at the given index.
/// </summary>
/// <param name="item"></param>
/// <param name="priority"></param>
/// <param name="position"></param>
[PublicAPI]
public void Enqueue([CanBeNull] T item, int priority, int position)
{
m_PriorityToQueue.GetOrAddNew(priority, ()=> new List<T>())
.Insert(position, item);
m_Count++;
}
@@ -89,30 +98,22 @@ namespace ICD.Common.Utils.Collections
/// </summary>
/// <param name="item"></param>
[PublicAPI]
public void EnqueueFirst(T item)
public void EnqueueFirst([CanBeNull] T item)
{
const int priority = int.MinValue;
List<T> queue;
if (!m_PriorityToQueue.TryGetValue(priority, out queue))
{
queue = new List<T>();
m_PriorityToQueue.Add(priority, queue);
}
queue.Insert(0, item);
m_PriorityToQueue.GetOrAddNew(int.MinValue, () => new List<T>())
.Insert(0, item);
m_Count++;
}
/// <summary>
/// Removes any items in the queue matching the predicate.
/// Inserts the given item in the position of the first removed item, or at the end of the queue.
/// This is useful for reducing duplication, or replacing items with something more pertinant.
/// Appends the given item at the end of the given priority level.
/// This is useful for reducing duplication, or replacing items with something more pertinent.
/// </summary>
/// <param name="item"></param>
/// <param name="remove"></param>
[PublicAPI]
public void EnqueueRemove(T item, Func<T, bool> remove)
public void EnqueueRemove([CanBeNull] T item, [NotNull] Func<T, bool> remove)
{
if (remove == null)
throw new ArgumentNullException("remove");
@@ -122,19 +123,38 @@ namespace ICD.Common.Utils.Collections
/// <summary>
/// Removes any items in the queue matching the predicate.
/// Inserts the given item in the position of the first removed item, or at the end of the queue.
/// This is useful for reducing duplication, or replacing items with something more pertinant.
/// Appends the given item at the end of the given priority level.
/// This is useful for reducing duplication, or replacing items with something more pertinent.
/// </summary>
/// <param name="item"></param>
/// <param name="remove"></param>
/// <param name="priority"></param>
[PublicAPI]
public void EnqueueRemove(T item, Func<T, bool> remove, int priority)
public void EnqueueRemove([CanBeNull] T item, [NotNull] Func<T, bool> remove, int priority)
{
if (remove == null)
throw new ArgumentNullException("remove");
bool inserted = false;
EnqueueRemove(item, remove, priority, false);
}
/// <summary>
/// Removes any items in the queue matching the predicate.
/// Appends the given item at the end of the given priority level.
/// This is useful for reducing duplication, or replacing items with something more pertinent.
/// </summary>
/// <param name="item"></param>
/// <param name="remove"></param>
/// <param name="priority"></param>
/// <param name="deDuplicateToEndOfQueue"></param>
[PublicAPI]
public void EnqueueRemove([CanBeNull] T item, [NotNull] Func<T, bool> remove, int priority, bool deDuplicateToEndOfQueue)
{
if (remove == null)
throw new ArgumentNullException("remove");
int lowestMatchingPriority = int.MaxValue;
int? firstMatchingIndex = null;
foreach (KeyValuePair<int, List<T>> kvp in m_PriorityToQueue.ToArray())
{
@@ -144,8 +164,11 @@ namespace ICD.Common.Utils.Collections
.Reverse()
.ToArray();
if (removeIndices.Length == 0)
continue;
if (removeIndices.Any() && kvp.Key < lowestMatchingPriority )
{
lowestMatchingPriority = kvp.Key;
firstMatchingIndex = removeIndices.Last();
}
foreach (int removeIndex in removeIndices)
{
@@ -153,26 +176,20 @@ namespace ICD.Common.Utils.Collections
m_Count--;
}
if (!inserted)
{
int insertIndex = removeIndices[0];
if (insertIndex >= kvp.Value.Count)
kvp.Value.Add(item);
else
kvp.Value.Insert(insertIndex, item);
m_Count++;
inserted = true;
}
if (kvp.Value.Count == 0)
m_PriorityToQueue.Remove(kvp.Key);
}
if (!inserted)
if(deDuplicateToEndOfQueue)
Enqueue(item, priority);
else
{
if(firstMatchingIndex == null)
Enqueue(item, lowestMatchingPriority);
else
Enqueue(item, lowestMatchingPriority, firstMatchingIndex.Value);
}
}
/// <summary>
@@ -180,6 +197,7 @@ namespace ICD.Common.Utils.Collections
/// </summary>
/// <returns></returns>
[PublicAPI]
[CanBeNull]
public T Dequeue()
{
T output;
@@ -227,6 +245,7 @@ namespace ICD.Common.Utils.Collections
/// Gets an enumerator for the items.
/// </summary>
/// <returns></returns>
[NotNull]
public IEnumerator<T> GetEnumerator()
{
return m_PriorityToQueue.Values
@@ -239,8 +258,11 @@ namespace ICD.Common.Utils.Collections
/// </summary>
/// <param name="array"></param>
/// <param name="index"></param>
public void CopyTo(Array array, int index)
public void CopyTo([NotNull] Array array, int index)
{
if (array == null)
throw new ArgumentNullException("array");
foreach (T item in this)
array.SetValue(item, index++);
}
@@ -253,6 +275,7 @@ namespace ICD.Common.Utils.Collections
/// Gets an enumerator for the items.
/// </summary>
/// <returns></returns>
[NotNull]
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using ICD.Common.Properties;
using ICD.Common.Utils.EventArguments;
using ICD.Common.Utils.Extensions;
using ICD.Common.Utils.Timers;
@@ -32,6 +33,7 @@ namespace ICD.Common.Utils.Collections
bool ICollection.IsSynchronized { get { return true; } }
[NotNull]
object ICollection.SyncRoot { get { return this; } }
#endregion
@@ -56,14 +58,23 @@ namespace ICD.Common.Utils.Collections
{
OnItemDequeued = null;
m_DequeueTimer.Dispose();
m_QueueSection.Enter();
try
{
m_DequeueTimer.Dispose();
}
finally
{
m_QueueSection.Leave();
}
}
/// <summary>
/// Enqueues the given item.
/// </summary>
/// <param name="item"></param>
public void Enqueue(T item)
public void Enqueue([CanBeNull] T item)
{
m_QueueSection.Enter();
@@ -149,18 +160,23 @@ namespace ICD.Common.Utils.Collections
#region IEnumerable/ICollection
[NotNull]
public IEnumerator<T> GetEnumerator()
{
return m_QueueSection.Execute(() => m_Queue.ToList(m_Queue.Count).GetEnumerator());
}
[NotNull]
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
void ICollection.CopyTo(Array array, int index)
void ICollection.CopyTo([NotNull] Array array, int index)
{
if (array == null)
throw new ArgumentNullException("array");
m_QueueSection.Enter();
try

View File

@@ -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

View File

@@ -1,108 +0,0 @@
using System;
namespace ICD.Common.Utils
{
public enum eConsoleColor
{
Red,
Green,
Yellow,
Blue,
Magenta,
Cyan,
White,
YellowOnRed
}
public static class ConsoleColorExtensions
{
public const string CONSOLE_RED = "\x1B[31;1m";
public const string CONSOLE_GREEN = "\x1B[32;1m";
public const string CONSOLE_YELLOW = "\x1B[33;1m";
public const string CONSOLE_BLUE = "\x1B[34;1m";
public const string CONSOLE_MAGENTA = "\x1B[35;1m";
public const string CONSOLE_CYAN = "\x1B[36;1m";
public const string CONSOLE_WHITE = "\x1B[37;1m";
public const string CONSOLE_YELLOW_ON_RED_BACKGROUND = "\x1B[93;41m";
public const string CONSOLE_RESET = "\x1B[0m";
public static string FormatAnsi(this eConsoleColor extends, string data)
{
return string.Format("{0}{1}{2}", extends.ToAnsiPrefix(), data, CONSOLE_RESET);
}
public static string ToAnsiPrefix(this eConsoleColor extends)
{
switch (extends)
{
case eConsoleColor.Red:
return CONSOLE_RED;
case eConsoleColor.Green:
return CONSOLE_GREEN;
case eConsoleColor.Yellow:
return CONSOLE_YELLOW;
case eConsoleColor.Blue:
return CONSOLE_BLUE;
case eConsoleColor.Magenta:
return CONSOLE_MAGENTA;
case eConsoleColor.Cyan:
return CONSOLE_CYAN;
case eConsoleColor.White:
return CONSOLE_WHITE;
case eConsoleColor.YellowOnRed:
return CONSOLE_YELLOW_ON_RED_BACKGROUND;
default:
throw new ArgumentOutOfRangeException("extends");
}
}
#if STANDARD
public static ConsoleColor ToForegroundConsoleColor(this eConsoleColor extends)
{
switch (extends)
{
case eConsoleColor.Red:
return ConsoleColor.Red;
case eConsoleColor.Green:
return ConsoleColor.Green;
case eConsoleColor.Yellow:
case eConsoleColor.YellowOnRed:
return ConsoleColor.Yellow;
case eConsoleColor.Blue:
return ConsoleColor.Blue;
case eConsoleColor.Magenta:
return ConsoleColor.Magenta;
case eConsoleColor.Cyan:
return ConsoleColor.Cyan;
case eConsoleColor.White:
return ConsoleColor.White;
default:
throw new ArgumentOutOfRangeException("extends");
}
}
public static ConsoleColor ToBackgroundConsoleColor(this eConsoleColor extends)
{
switch (extends)
{
case eConsoleColor.Red:
case eConsoleColor.Green:
case eConsoleColor.Yellow:
case eConsoleColor.Blue:
case eConsoleColor.Magenta:
case eConsoleColor.Cyan:
case eConsoleColor.White:
return ConsoleColor.Black;
case eConsoleColor.YellowOnRed:
return ConsoleColor.Red;
default:
throw new ArgumentOutOfRangeException("extends");
}
}
#endif
}
}

View File

@@ -11,33 +11,81 @@ namespace ICD.Common.Utils.Csv
private const string DOUBLE_QUOTE_MARK = "\"\"";
private readonly IcdTextWriter m_Writer;
private readonly string m_Seperator;
private readonly string m_LineTerminator;
private readonly bool m_AlwaysEscape;
private readonly CsvWriterSettings m_Settings;
private bool m_NewLine;
#region Properties
private string Separator { get { return m_Settings.InsertSpaceAfterComma ? ", " : ","; } }
private string LineTerminator { get { return m_Settings.NewLineSequence; } }
#endregion
#region Constructors
/// <summary>
/// Constructor.
/// </summary>
public CsvWriter(IcdTextWriter writer, bool spaceAfterComma, bool alwaysEscape, string newline, params string[] header)
public CsvWriter([NotNull] IcdTextWriter writer, [NotNull] CsvWriterSettings settings, [NotNull] params string[] header)
{
if (writer == null)
throw new ArgumentNullException("writer");
if (settings == null)
throw new ArgumentNullException("settings");
if (header == null)
throw new ArgumentNullException("header");
m_NewLine = true;
m_Writer = writer;
m_Seperator = spaceAfterComma ? ", " : ",";
m_AlwaysEscape = alwaysEscape;
m_LineTerminator = newline;
m_Settings = settings;
if(header.Any())
if (header.Any())
AppendRow(header);
}
/// <summary>
/// Deconstructor.
/// </summary>
~CsvWriter()
{
Dispose();
}
/// <summary>
/// Instantiates a new CsvWriter with the properties given in the CsvWriterSettings.
/// </summary>
/// <param name="writer"></param>
/// <param name="settings"></param>
/// <param name="header"></param>
/// <returns></returns>
[PublicAPI]
public static CsvWriter Create([NotNull] IcdTextWriter writer, [NotNull] CsvWriterSettings settings,
[NotNull] params string[] header)
{
if (writer == null)
throw new ArgumentNullException("writer");
if (settings == null)
throw new ArgumentNullException("settings");
if (header == null)
throw new ArgumentNullException("header");
return new CsvWriter(writer, settings, header);
}
#endregion
public void Dispose()
{
m_Writer.Dispose();
}
#region Methods
/// <summary>
/// Calls ToString() for each item and adds the row to the builder.
/// </summary>
@@ -82,9 +130,9 @@ namespace ICD.Common.Utils.Csv
value = value ?? string.Empty;
if (!m_NewLine)
m_Writer.WrappedTextWriter.Write(m_Seperator);
m_Writer.WrappedTextWriter.Write(Separator);
if (m_AlwaysEscape || value.Contains(","))
if (m_Settings.AlwaysEscapeEveryValue || value.Contains(","))
{
value = value.Replace(QUOTATION_MARK, DOUBLE_QUOTE_MARK);
@@ -107,31 +155,11 @@ namespace ICD.Common.Utils.Csv
[PublicAPI]
public void AppendNewline()
{
m_Writer.WrappedTextWriter.Write(m_LineTerminator);
m_Writer.WrappedTextWriter.Write(LineTerminator);
m_NewLine = true;
}
public void Dispose()
{
m_Writer.Dispose();
}
/// <summary>
/// Instantiates a new CsvWriter with the properties given in the CsvWriterSettings.
/// </summary>
/// <param name="writer"></param>
/// <param name="settings"></param>
/// <param name="header"></param>
/// <returns></returns>
[PublicAPI]
public static CsvWriter Create(IcdTextWriter writer, CsvWriterSettings settings, params string[] header)
{
return new CsvWriter(writer,
settings.InsertSpaceAfterComma,
settings.AlwaysEscapeEveryValue,
settings.NewLineSequence,
header);
}
#endregion
}
}
}

Binary file not shown.

View File

@@ -0,0 +1,37 @@
using System;
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;
}
/// <summary>
/// Creates a DateTime from the given number of milliseconds since the epoch (1970-01-01T00:00:00Z)
/// </summary>
/// <param name="milliseconds">milliseconds since the epoch</param>
/// <returns></returns>
public static DateTime FromEpochMilliseconds(long milliseconds)
{
return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(milliseconds);
}
/// <summary>
/// Creates a DateTime from the given number of seconds since the epoch (1970-01-01T00:00:00Z)
/// </summary>
/// <param name="seconds">seconds since the epoch</param>
/// <returns></returns>
public static DateTime FromEpochSeconds(long seconds)
{
return FromEpochMilliseconds(seconds * 1000);
}
}
}

View 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);
}
}
}

View File

@@ -18,7 +18,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <returns></returns>
[CanBeNull]
public static string GetPath(this Assembly extends)
public static string GetPath([NotNull]this Assembly extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -29,7 +29,7 @@ namespace ICD.Common.Utils.Extensions
#endif
.CodeBase;
if (path == null)
if (string.IsNullOrEmpty(path))
{
#if STANDARD
path = extends.Location;
@@ -51,7 +51,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static DateTime GetCreationTime(this Assembly extends)
public static DateTime GetCreationTime([NotNull]this Assembly extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -66,7 +66,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static string GetInformationalVersion(this Assembly extends)
public static string GetInformationalVersion([NotNull]this Assembly extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -85,7 +85,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="version"></param>
/// <returns></returns>
[PublicAPI]
public static bool TryGetInformationalVersion(this Assembly extends, out string version)
public static bool TryGetInformationalVersion([NotNull]this Assembly extends, out string version)
{
if (extends == null)
throw new ArgumentNullException("extends");

View File

@@ -0,0 +1,91 @@
using System;
using System.Globalization;
using ICD.Common.Properties;
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([NotNull]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([NotNull]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([NotNull]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");
}
}
}

View File

@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Extensions
{
@@ -37,14 +39,29 @@ namespace ICD.Common.Utils.Extensions
/// <param name="inclusive">Whether or not to include times equal to the target time</param>
/// <param name="times"></param>
/// <returns></returns>
public static DateTime? NextEarliestTime(this DateTime target, bool inclusive, params DateTime[] times)
public static DateTime? NextEarliestTime(this DateTime target, bool inclusive, [NotNull] params DateTime[] times)
{
if (times == null)
throw new ArgumentNullException("times");
return target.NextEarliestTime(inclusive, (IEnumerable<DateTime>)times);
}
/// <summary>
/// Returns the closest DateTime to the target time that is greater than the target time
/// </summary>
/// <param name="target"></param>
/// <param name="inclusive">Whether or not to include times equal to the target time</param>
/// <param name="times"></param>
/// <returns></returns>
public static DateTime? NextEarliestTime(this DateTime target, bool inclusive, [NotNull] IEnumerable<DateTime> times)
{
if (times == null)
throw new ArgumentNullException("times");
DateTime earliestTime;
bool success = times.OrderBy(dt => dt).TryFirst(dt => inclusive ? target <= dt : target < dt, out earliestTime);
return success ? earliestTime : (DateTime?) null;
return success ? earliestTime : (DateTime?)null;
}
/// <summary>
@@ -54,14 +71,149 @@ namespace ICD.Common.Utils.Extensions
/// <param name="inclusive">Whether or not to include times equal to the target time</param>
/// <param name="times"></param>
/// <returns></returns>
public static DateTime? PreviousLatestTime(this DateTime target, bool inclusive, params DateTime[] times)
public static DateTime? PreviousLatestTime(this DateTime target, bool inclusive, [NotNull] params DateTime[] times)
{
if (times == null)
throw new ArgumentNullException("null");
throw new ArgumentNullException("times");
return target.PreviousLatestTime(inclusive, (IEnumerable<DateTime>)times);
}
/// <summary>
/// Returns the closest DateTime to the target time that is less than the target time
/// </summary>
/// <param name="target"></param>
/// <param name="inclusive">Whether or not to include times equal to the target time</param>
/// <param name="times"></param>
/// <returns></returns>
public static DateTime? PreviousLatestTime(this DateTime target, bool inclusive, [NotNull] IEnumerable<DateTime> times)
{
if (times == null)
throw new ArgumentNullException("times");
DateTime latestTime;
bool success = times.OrderByDescending(dt => dt).TryFirst(dt => inclusive ? target >= dt : target > dt, out latestTime);
return success ? latestTime : (DateTime?) null;
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);
}
/// <summary>
/// Returns the given date in unix timestamp format.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[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);
}
/// <summary>
/// Adds the given number of years to the date, and checks if the day is still valid (basically only for leap days).
/// </summary>
/// <param name="extends"></param>
/// <param name="years"></param>
/// <returns></returns>
public static DateTime AddYearsAndWrap(this DateTime extends, int years)
{
years += extends.Year;
// need to check days in month due to leap year
int daysInMonth = DateTime.DaysInMonth(years, extends.Month);
int day = daysInMonth < extends.Day ? daysInMonth : extends.Day;
return new DateTime(years, extends.Month, day, extends.Hour, extends.Minute, extends.Second, extends.Millisecond);
}
/// <summary>
/// Adds the given number of months to the date, wrapping every 12 months, and lowering the day in the month is not valid.
/// </summary>
/// <param name="extends"></param>
/// <param name="months"></param>
/// <returns></returns>
public static DateTime AddMonthsAndWrap(this DateTime extends, int months)
{
months = MathUtils.Modulus(months + extends.Month - 1, 12) + 1;
int daysInMonth = DateTime.DaysInMonth(extends.Year, months);
int day = daysInMonth < extends.Day ? daysInMonth : extends.Day;
return new DateTime(extends.Year, months, day, extends.Hour, extends.Minute, extends.Second, extends.Millisecond);
}
/// <summary>
/// Adds the given number of days to the date, wrapping when the number of days exceeds the days in a month.
/// </summary>
/// <param name="extends"></param>
/// <param name="days"></param>
/// <returns></returns>
public static DateTime AddDaysAndWrap(this DateTime extends, int days)
{
days = MathUtils.Modulus(days + extends.Day - 1, DateTime.DaysInMonth(extends.Year, extends.Month)) + 1;
return new DateTime(extends.Year, extends.Month, days, extends.Hour, extends.Minute, extends.Second, extends.Millisecond);
}
/// <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 DateTime AddHoursAndWrap(this DateTime extends, int hours)
{
hours = MathUtils.Modulus(hours + extends.Hour, 24);
return new DateTime(extends.Year, extends.Month, extends.Day, hours, extends.Minute, extends.Second, extends.Millisecond);
}
/// <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 DateTime AddHoursAndWrap12Hour(this DateTime extends, int hours)
{
int currentHour = extends.Hour;
bool am = extends.Hour < 12;
int current12Hour = MathUtils.Modulus(currentHour, 12);
int new12Hour = MathUtils.Modulus(current12Hour + hours, 12);
return am
? new DateTime(extends.Year, extends.Month, extends.Day, new12Hour, extends.Minute, extends.Second, extends.Millisecond)
: new DateTime(extends.Year, extends.Month, extends.Day, new12Hour + 12, extends.Minute, extends.Second, extends.Millisecond);
}
/// <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 DateTime AddMinutesAndWrap(this DateTime extends, int minutes)
{
minutes = MathUtils.Modulus(minutes + extends.Minute, 60);
return new DateTime(extends.Year, extends.Month, extends.Day, extends.Hour, minutes, extends.Second, extends.Millisecond);
}
}
}

View File

@@ -14,11 +14,15 @@ namespace ICD.Common.Utils.Extensions
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <param name="keys"></param>
public static void RemoveAll<TKey, TValue>(this IDictionary<TKey, TValue> extends, IEnumerable<TKey> keys)
public static void RemoveAll<TKey, TValue>([NotNull] this IDictionary<TKey, TValue> extends,
[NotNull] IEnumerable<TKey> keys)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (keys == null)
throw new ArgumentNullException("keys");
foreach (TKey key in keys)
extends.Remove(key);
}
@@ -32,7 +36,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="value"></param>
/// <returns>False if value is not found in the dictionary.</returns>
[PublicAPI]
public static bool RemoveValue<TKey, TValue>(this IDictionary<TKey, TValue> extends, TValue value)
public static bool RemoveValue<TKey, TValue>([NotNull] this IDictionary<TKey, TValue> extends, TValue value)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -49,7 +53,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="value"></param>
[PublicAPI]
public static void RemoveAllValues<TKey, TValue>(this IDictionary<TKey, TValue> extends, TValue value)
public static void RemoveAllValues<TKey, TValue>([NotNull] this IDictionary<TKey, TValue> extends, TValue value)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -68,12 +72,12 @@ namespace ICD.Common.Utils.Extensions
/// <returns></returns>
[CanBeNull]
[PublicAPI]
public static TValue GetDefault<TKey, TValue>(this IDictionary<TKey, TValue> extends, TKey key)
public static TValue GetDefault<TKey, TValue>([NotNull] this IDictionary<TKey, TValue> extends,
[NotNull] TKey key)
{
if (extends == null)
throw new ArgumentNullException("extends");
// ReSharper disable once CompareNonConstrainedGenericWithNull
if (key == null)
throw new ArgumentNullException("key");
@@ -90,12 +94,13 @@ namespace ICD.Common.Utils.Extensions
/// <param name="defaultValue"></param>
/// <returns></returns>
[PublicAPI]
public static TValue GetDefault<TKey, TValue>(this IDictionary<TKey, TValue> extends, TKey key, TValue defaultValue)
public static TValue GetDefault<TKey, TValue>([NotNull] this IDictionary<TKey, TValue> extends,
[NotNull] TKey key,
TValue defaultValue)
{
if (extends == null)
throw new ArgumentNullException("extends");
// ReSharper disable once CompareNonConstrainedGenericWithNull
if (key == null)
throw new ArgumentNullException("key");
@@ -112,15 +117,14 @@ namespace ICD.Common.Utils.Extensions
/// <param name="key"></param>
/// <param name="defaultValue"></param>
/// <returns></returns>
[CanBeNull]
[PublicAPI]
public static TValue GetOrAddDefault<TKey, TValue>(this IDictionary<TKey, TValue> extends, TKey key,
public static TValue GetOrAddDefault<TKey, TValue>([NotNull] this IDictionary<TKey, TValue> extends,
[NotNull] TKey key,
TValue defaultValue)
{
if (extends == null)
throw new ArgumentNullException("extends");
// ReSharper disable once CompareNonConstrainedGenericWithNull
if (key == null)
throw new ArgumentNullException("key");
@@ -130,6 +134,65 @@ namespace ICD.Common.Utils.Extensions
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>([NotNull] this IDictionary<TKey, TValue> extends,
[NotNull] 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>([NotNull] this IDictionary<TKey, TValue> extends,
[NotNull] TKey key,
[NotNull] Func<TValue> valueFunc)
{
if (extends == null)
throw new ArgumentNullException("extends");
// ReSharper disable CompareNonConstrainedGenericWithNull
if (key == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
throw new ArgumentNullException("key");
if (valueFunc == null)
throw new ArgumentNullException("valueFunc");
TValue value;
if (!extends.TryGetValue(key, out value))
{
value = valueFunc();
extends.Add(key, value);
}
return value;
}
/// <summary>
/// Gets a key for the given value.
/// </summary>
@@ -140,7 +203,7 @@ namespace ICD.Common.Utils.Extensions
/// <returns></returns>
/// <exception cref="ArgumentOutOfRangeException">The value does not exist in the dictionary.</exception>
[PublicAPI]
public static TKey GetKey<TKey, TValue>(this IDictionary<TKey, TValue> extends, TValue value)
public static TKey GetKey<TKey, TValue>([NotNull] this IDictionary<TKey, TValue> extends, TValue value)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -163,7 +226,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="key"></param>
/// <returns></returns>
[PublicAPI]
public static bool TryGetKey<TKey, TValue>(this IDictionary<TKey, TValue> extends, TValue value, out TKey key)
public static bool TryGetKey<TKey, TValue>([NotNull] this IDictionary<TKey, TValue> extends, TValue value,
out TKey key)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -180,7 +244,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="value"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<TKey> GetKeys<TKey, TValue>(this IDictionary<TKey, TValue> extends, TValue value)
public static IEnumerable<TKey> GetKeys<TKey, TValue>([NotNull] this IDictionary<TKey, TValue> extends,
TValue value)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -198,8 +263,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="other"></param>
/// <returns></returns>
[PublicAPI]
public static bool Update<TKey, TValue>(this IDictionary<TKey, TValue> extends,
IEnumerable<KeyValuePair<TKey, TValue>> other)
public static bool Update<TKey, TValue>([NotNull] this IDictionary<TKey, TValue> extends,
[NotNull] IEnumerable<KeyValuePair<TKey, TValue>> other)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -220,9 +285,9 @@ namespace ICD.Common.Utils.Extensions
/// <param name="comparer"></param>
/// <returns></returns>
[PublicAPI]
public static bool Update<TKey, TValue>(this IDictionary<TKey, TValue> extends,
IEnumerable<KeyValuePair<TKey, TValue>> other,
IEqualityComparer<TValue> comparer)
public static bool Update<TKey, TValue>([NotNull] this IDictionary<TKey, TValue> extends,
[NotNull] IEnumerable<KeyValuePair<TKey, TValue>> other,
[NotNull] IEqualityComparer<TValue> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -230,6 +295,9 @@ namespace ICD.Common.Utils.Extensions
if (other == null)
throw new ArgumentNullException("other");
if (comparer == null)
throw new ArgumentNullException("comparer");
bool change = false;
foreach (KeyValuePair<TKey, TValue> pair in other)
@@ -253,7 +321,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="items"></param>
[PublicAPI]
public static void AddRange<TKey, TValue>(this IDictionary<TKey, TValue> extends, IEnumerable<KeyValuePair<TKey, TValue>> items)
public static void AddRange<TKey, TValue>([NotNull] this IDictionary<TKey, TValue> extends,
[NotNull] IEnumerable<KeyValuePair<TKey, TValue>> items)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -274,8 +343,9 @@ namespace ICD.Common.Utils.Extensions
/// <param name="items"></param>
/// <param name="getKey"></param>
[PublicAPI]
public static void AddRange<TKey, TValue>(this IDictionary<TKey, TValue> extends, IEnumerable<TValue> items,
Func<TValue, TKey> getKey)
public static void AddRange<TKey, TValue>([NotNull] this IDictionary<TKey, TValue> extends,
[NotNull] IEnumerable<TValue> items,
[NotNull] Func<TValue, TKey> getKey)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -299,8 +369,9 @@ namespace ICD.Common.Utils.Extensions
/// <param name="items"></param>
/// <param name="getValue"></param>
[PublicAPI]
public static void AddRange<TKey, TValue>(this IDictionary<TKey, TValue> extends, IEnumerable<TKey> items,
Func<TKey, TValue> getValue)
public static void AddRange<TKey, TValue>([NotNull] this IDictionary<TKey, TValue> extends,
[NotNull] IEnumerable<TKey> items,
[NotNull] Func<TKey, TValue> getValue)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -323,8 +394,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="items"></param>
[PublicAPI]
public static void AddRange<TKey, TValue>(this Dictionary<TKey, TValue> extends,
IEnumerable<KeyValuePair<TKey, TValue>> items)
public static void AddRange<TKey, TValue>([NotNull] this Dictionary<TKey, TValue> extends,
[NotNull] IEnumerable<KeyValuePair<TKey, TValue>> items)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -345,12 +416,15 @@ namespace ICD.Common.Utils.Extensions
/// <param name="other"></param>
/// <returns></returns>
[PublicAPI]
public static bool DictionaryEqual<TKey, TValue>(this IDictionary<TKey, TValue> extends,
IDictionary<TKey, TValue> other)
public static bool DictionaryEqual<TKey, TValue>([NotNull] this IDictionary<TKey, TValue> extends,
[NotNull] IDictionary<TKey, TValue> other)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (other == null)
throw new ArgumentNullException("other");
return extends.DictionaryEqual(other, EqualityComparer<TValue>.Default);
}
@@ -364,13 +438,16 @@ namespace ICD.Common.Utils.Extensions
/// <param name="valueComparer"></param>
/// <returns></returns>
[PublicAPI]
public static bool DictionaryEqual<TKey, TValue>(this IDictionary<TKey, TValue> extends,
IDictionary<TKey, TValue> other,
IEqualityComparer<TValue> valueComparer)
public static bool DictionaryEqual<TKey, TValue>([NotNull] this IDictionary<TKey, TValue> extends,
[NotNull] IDictionary<TKey, TValue> other,
[NotNull] IEqualityComparer<TValue> valueComparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (other == null)
throw new ArgumentNullException("other");
if (valueComparer == null)
throw new ArgumentNullException("valueComparer");
@@ -387,20 +464,21 @@ namespace ICD.Common.Utils.Extensions
/// <param name="valueComparer"></param>
/// <returns></returns>
[PublicAPI]
public static bool DictionaryEqual<TKey, TValue>(this IDictionary<TKey, TValue> extends,
IDictionary<TKey, TValue> other,
Func<TValue, TValue, bool> valueComparer)
public static bool DictionaryEqual<TKey, TValue>([NotNull] this IDictionary<TKey, TValue> extends,
[NotNull] IDictionary<TKey, TValue> other,
[NotNull] Func<TValue, TValue, bool> valueComparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (other == null)
throw new ArgumentNullException("other");
if (valueComparer == null)
throw new ArgumentNullException("valueComparer");
if (extends == other)
return true;
if (other == null)
return false;
if (extends.Count != other.Count)
return false;
@@ -412,6 +490,7 @@ namespace ICD.Common.Utils.Extensions
if (!valueComparer(kvp.Value, secondValue))
return false;
}
return true;
}
@@ -424,7 +503,7 @@ namespace ICD.Common.Utils.Extensions
/// <returns></returns>
[PublicAPI]
public static IEnumerable<KeyValuePair<TKey, TValue>> OrderByKey<TKey, TValue>(
this IEnumerable<KeyValuePair<TKey, TValue>> extends)
[NotNull] this IEnumerable<KeyValuePair<TKey, TValue>> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -440,7 +519,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<TValue> OrderValuesByKey<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> extends)
public static IEnumerable<TValue> OrderValuesByKey<TKey, TValue>(
[NotNull] this IEnumerable<KeyValuePair<TKey, TValue>> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -456,7 +536,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static Dictionary<TValue, List<TKey>> ToInverse<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> extends)
public static Dictionary<TValue, List<TKey>> ToInverse<TKey, TValue>(
[NotNull] this IEnumerable<KeyValuePair<TKey, TValue>> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -477,5 +558,22 @@ namespace ICD.Common.Utils.Extensions
return output;
}
/// <summary>
/// Turns an enumerable of KeyValuePairs back into a dictionary
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(
[NotNull] this IEnumerable<KeyValuePair<TKey, TValue>> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.ToDictionary(x => x.Key, x => x.Value);
}
}
}

View File

@@ -31,6 +31,34 @@ namespace ICD.Common.Utils.Extensions
return EnumUtils.HasFlags(extends, values);
}
/// <summary>
/// Returns these enum flags, excluding the other enum flags.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="other"></param>
/// <returns></returns>
[PublicAPI]
public static T ExcludeFlags<T>(this T extends, T other)
where T : struct, IConvertible
{
return EnumUtils.ExcludeFlags(extends, other);
}
/// <summary>
/// Returns these enum flags, including the other enum flags.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="other"></param>
/// <returns></returns>
[PublicAPI]
public static T IncludeFlags<T>(this T extends, T other)
where T : struct, IConvertible
{
return EnumUtils.IncludeFlags(extends, other);
}
/// <summary>
/// Returns the enum value as a
/// </summary>

View File

@@ -17,7 +17,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="defaultItem"></param>
/// <returns></returns>
public static T FirstOrDefault<T>(this IEnumerable<T> extends, T defaultItem)
public static T FirstOrDefault<T>([NotNull] this IEnumerable<T> extends, T defaultItem)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -34,7 +34,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="predicate"></param>
/// <param name="defaultItem"></param>
/// <returns></returns>
public static T FirstOrDefault<T>(this IEnumerable<T> extends, Func<T, bool> predicate, T defaultItem)
public static T FirstOrDefault<T>([NotNull] this IEnumerable<T> extends, [NotNull] Func<T, bool> predicate,
T defaultItem)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -53,7 +54,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="item">Outputs the first item in the sequence.</param>
/// <returns></returns>
public static bool TryFirst<T>(this IEnumerable<T> extends, out T item)
public static bool TryFirst<T>([NotNull] this IEnumerable<T> extends, out T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -80,7 +81,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="predicate"></param>
/// <param name="item">Outputs the first item in the sequence.</param>
/// <returns></returns>
public static bool TryFirst<T>(this IEnumerable<T> extends, Func<T, bool> predicate, out T item)
public static bool TryFirst<T>([NotNull] this IEnumerable<T> extends, [NotNull] Func<T, bool> predicate,
out T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -112,7 +114,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="item">Outputs the last item in the sequence.</param>
/// <returns></returns>
public static bool TryLast<T>(this IEnumerable<T> extends, out T item)
public static bool TryLast<T>([NotNull] this IEnumerable<T> extends, out T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -139,7 +141,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="predicate"></param>
/// <param name="item">Outputs the last item in the sequence.</param>
/// <returns></returns>
public static bool TryLast<T>(this IEnumerable<T> extends, Func<T, bool> predicate, out T item)
public static bool TryLast<T>([NotNull] this IEnumerable<T> extends, [NotNull] Func<T, bool> predicate,
out T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -173,7 +176,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="index"></param>
/// <param name="item"></param>
/// <returns></returns>
public static bool TryElementAt<T>(this IEnumerable<T> extends, int index, out T item)
public static bool TryElementAt<T>([NotNull] this IEnumerable<T> extends, int index, out T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -200,6 +203,7 @@ namespace ICD.Common.Utils.Extensions
item = value;
return true;
}
current++;
}
@@ -214,7 +218,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="index"></param>
/// <param name="defaultValue"></param>
/// <returns></returns>
public static T ElementAtOrDefault<T>(this IEnumerable<T> extends, int index, T defaultValue)
public static T ElementAtOrDefault<T>([NotNull] this IEnumerable<T> extends, int index, T defaultValue)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -231,7 +235,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="other"></param>
/// <param name="comparer"></param>
/// <returns></returns>
public static bool SequenceEqual<T>(this IEnumerable<T> extends, IEnumerable<T> other, IEqualityComparer<T> comparer)
public static bool SequenceEqual<T>([NotNull] this IEnumerable<T> extends, [NotNull] IEnumerable<T> other,
[NotNull] IEqualityComparer<T> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -253,7 +258,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="other"></param>
/// <param name="comparer"></param>
/// <returns></returns>
public static bool SequenceEqual<T>(this IEnumerable<T> extends, IEnumerable<T> other, Func<T, T, bool> comparer)
public static bool SequenceEqual<T>([NotNull] this IEnumerable<T> extends, [NotNull] IEnumerable<T> other,
[NotNull] Func<T, T, bool> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -298,7 +304,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="other"></param>
/// <returns></returns>
public static bool ScrambledEquals<T>(this IEnumerable<T> extends, IEnumerable<T> other)
public static bool ScrambledEquals<T>([NotNull] this IEnumerable<T> extends, [NotNull] IEnumerable<T> other)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -317,7 +323,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="other"></param>
/// <param name="comparer"></param>
/// <returns></returns>
public static bool ScrambledEquals<T>(this IEnumerable<T> extends, IEnumerable<T> other, IEqualityComparer<T> comparer)
public static bool ScrambledEquals<T>([NotNull] this IEnumerable<T> extends, [NotNull] IEnumerable<T> other,
[NotNull] IEqualityComparer<T> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -352,7 +359,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="match"></param>
/// <returns></returns>
public static int FindIndex<T>(this IEnumerable<T> extends, Predicate<T> match)
public static int FindIndex<T>([NotNull] this IEnumerable<T> extends, [NotNull] Predicate<T> match)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -370,7 +377,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="match"></param>
/// <returns></returns>
public static IEnumerable<int> FindIndices<T>(this IEnumerable<T> extends, Predicate<T> match)
public static IEnumerable<int> FindIndices<T>([NotNull] this IEnumerable<T> extends,
[NotNull] Predicate<T> match)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -388,7 +396,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="sequence"></param>
/// <param name="match"></param>
/// <returns></returns>
private static IEnumerable<int> FindIndicesIterator<T>(IEnumerable<T> sequence, Predicate<T> match)
private static IEnumerable<int> FindIndicesIterator<T>([NotNull] IEnumerable<T> sequence,
[NotNull] Predicate<T> match)
{
int index = 0;
@@ -408,7 +417,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="selectors"></param>
/// <returns></returns>
public static IEnumerable<TResult> SelectMulti<TSource, TResult>(this IEnumerable<TSource> extends,
public static IEnumerable<TResult> SelectMulti<TSource, TResult>([NotNull] this IEnumerable<TSource> extends,
[NotNull]
params Func<TSource, TResult>[] selectors)
{
if (extends == null)
@@ -427,7 +437,7 @@ namespace ICD.Common.Utils.Extensions
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
[PublicAPI]
public static void Execute<T>(this IEnumerable<T> extends)
public static void Execute<T>([NotNull] this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -446,7 +456,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="action"></param>
[PublicAPI]
public static void ForEach<T>(this IEnumerable<T> extends, Action<T> action)
public static void ForEach<T>([NotNull] this IEnumerable<T> extends, [NotNull] Action<T> action)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -464,7 +474,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="action"></param>
[PublicAPI]
public static void ForEach<T>(this IEnumerable<T> extends, Action<T, int> action)
public static void ForEach<T>([NotNull] this IEnumerable<T> extends, [NotNull] Action<T, int> action)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -485,7 +495,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="item"></param>
/// <returns></returns>
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> extends, T item)
public static IEnumerable<T> Prepend<T>([NotNull]this IEnumerable<T> extends, T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -500,7 +510,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="sequence"></param>
/// <param name="item"></param>
/// <returns></returns>
private static IEnumerable<T> PrependIterator<T>(IEnumerable<T> sequence, T item)
private static IEnumerable<T> PrependIterator<T>([NotNull]IEnumerable<T> sequence, T item)
{
yield return item;
@@ -517,7 +527,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="items"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<T> PrependMany<T>(this IEnumerable<T> extends, params T[] items)
public static IEnumerable<T> PrependMany<T>([NotNull] this IEnumerable<T> extends, [NotNull] params T[] items)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -535,7 +545,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="sequence"></param>
/// <param name="items"></param>
/// <returns></returns>
private static IEnumerable<T> PrependManyIterator<T>(IEnumerable<T> sequence, params T[] items)
private static IEnumerable<T> PrependManyIterator<T>([NotNull] IEnumerable<T> sequence,
[NotNull] params T[] items)
{
foreach (T item in items)
yield return item;
@@ -552,7 +563,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="item"></param>
/// <returns></returns>
public static IEnumerable<T> Append<T>(this IEnumerable<T> extends, T item)
public static IEnumerable<T> Append<T>([NotNull]this IEnumerable<T> extends, T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -567,7 +578,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="sequence"></param>
/// <param name="item"></param>
/// <returns></returns>
private static IEnumerable<T> AppendIterator<T>(IEnumerable<T> sequence, T item)
private static IEnumerable<T> AppendIterator<T>([NotNull]IEnumerable<T> sequence, T item)
{
foreach (T first in sequence)
yield return first;
@@ -584,7 +595,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="items"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<T> AppendMany<T>(this IEnumerable<T> extends, params T[] items)
public static IEnumerable<T> AppendMany<T>([NotNull] this IEnumerable<T> extends, [NotNull] params T[] items)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -602,7 +613,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="sequence"></param>
/// <param name="items"></param>
/// <returns></returns>
private static IEnumerable<T> AppendManyIterator<T>(IEnumerable<T> sequence, params T[] items)
private static IEnumerable<T> AppendManyIterator<T>([NotNull] IEnumerable<T> sequence,
[NotNull] params T[] items)
{
foreach (T each in sequence)
yield return each;
@@ -619,7 +631,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="count"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<T> PadRight<T>(this IEnumerable<T> extends, int count)
public static IEnumerable<T> PadRight<T>([NotNull] this IEnumerable<T> extends, int count)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -634,7 +646,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="sequence"></param>
/// <param name="count"></param>
/// <returns></returns>
private static IEnumerable<T> PadRightIterator<T>(IEnumerable<T> sequence, int count)
private static IEnumerable<T> PadRightIterator<T>([NotNull] IEnumerable<T> sequence, int count)
{
int index = 0;
@@ -648,13 +660,57 @@ namespace ICD.Common.Utils.Extensions
yield return default(T);
}
/// <summary>
/// Returns true if the given sequence is ordered.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
public static bool AreOrdered<T>([NotNull] this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.AreOrdered(Comparer<T>.Default);
}
/// <summary>
/// Returns true if the given sequence is ordered.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="comparer"></param>
/// <returns></returns>
public static bool AreOrdered<T>([NotNull] this IEnumerable<T> extends, [NotNull] IComparer<T> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (comparer == null)
throw new ArgumentNullException("comparer");
bool first = true;
T previous = default(T);
foreach (T item in extends)
{
if (!first && comparer.Compare(item, previous) < 0)
return false;
first = false;
previous = item;
}
return true;
}
/// <summary>
/// Default ordering for the items in the sequence.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
public static IOrderedEnumerable<T> Order<T>(this IEnumerable<T> extends)
public static IOrderedEnumerable<T> Order<T>([NotNull] this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -669,7 +725,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="comparer"></param>
/// <returns></returns>
public static IOrderedEnumerable<T> Order<T>(this IEnumerable<T> extends, IComparer<T> comparer)
public static IOrderedEnumerable<T> Order<T>([NotNull] this IEnumerable<T> extends,
[NotNull] IComparer<T> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -687,7 +744,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="comparer"></param>
/// <returns></returns>
public static IOrderedEnumerable<T> OrderDescending<T>(this IEnumerable<T> extends, IComparer<T> comparer)
public static IOrderedEnumerable<T> OrderDescending<T>([NotNull] this IEnumerable<T> extends,
[NotNull] IComparer<T> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -705,7 +763,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="item"></param>
/// <returns></returns>
public static IEnumerable<T> Except<T>(this IEnumerable<T> extends, T item)
public static IEnumerable<T> Except<T>([NotNull] this IEnumerable<T> extends, T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -721,7 +779,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="item"></param>
/// <param name="comparer"></param>
/// <returns></returns>
public static IEnumerable<T> Except<T>(this IEnumerable<T> extends, T item, IEqualityComparer<T> comparer)
public static IEnumerable<T> Except<T>([NotNull] this IEnumerable<T> extends, T item,
[NotNull] IEqualityComparer<T> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -732,6 +791,22 @@ namespace ICD.Common.Utils.Extensions
return extends.Where(i => !comparer.Equals(item, i));
}
/// <summary>
/// Removes any null elements from an enumerable of nullable value types
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<T> ExceptNulls<T>([NotNull] this IEnumerable<T?> extends)
where T : struct
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.OfType<T>();
}
/// <summary>
/// Copies all the elements of the current one-dimensional array to the specified one-dimensional array
/// starting at the specified destination array index. The index is specified as a 32-bit integer.
@@ -740,7 +815,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="array"></param>
/// <param name="index"></param>
public static void CopyTo<T>(this IEnumerable<T> extends, T[] array, int index)
public static void CopyTo<T>([NotNull] this IEnumerable<T> extends, [NotNull] T[] array, int index)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -769,7 +844,7 @@ namespace ICD.Common.Utils.Extensions
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
public static IcdHashSet<T> ToIcdHashSet<T>(this IEnumerable<T> extends)
public static IcdHashSet<T> ToIcdHashSet<T>([NotNull] this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -784,7 +859,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="comparer"></param>
/// <returns></returns>
public static IcdHashSet<T> ToIcdHashSet<T>(this IEnumerable<T> extends, IEqualityComparer<T> comparer)
public static IcdHashSet<T> ToIcdHashSet<T>([NotNull] this IEnumerable<T> extends,
[NotNull] IEqualityComparer<T> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -802,7 +878,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="count"></param>
/// <returns></returns>
public static T[] ToArray<T>(this IEnumerable<T> extends, int count)
public static T[] ToArray<T>([NotNull] this IEnumerable<T> extends, int count)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -810,11 +886,29 @@ namespace ICD.Common.Utils.Extensions
if (count < 0)
throw new ArgumentOutOfRangeException("count");
T[] array = new T[count];
int i = 0;
// Source is already an array
T[] arrayCast = extends as T[];
if (arrayCast != null)
{
T[] output = new T[count];
Array.Copy(arrayCast, output, count);
return output;
}
// Dumb sequence case
T[] array = new T[count];
int i = 0;
foreach (T item in extends)
{
array[i++] = item;
if (i >= count)
break;
}
if (i != count)
throw new ArgumentOutOfRangeException("count");
return array;
}
@@ -825,7 +919,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="count"></param>
/// <returns></returns>
public static List<T> ToList<T>(this IEnumerable<T> extends, int count)
public static List<T> ToList<T>([NotNull] this IEnumerable<T> extends, int count)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -845,7 +939,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static Dictionary<int, T> ToIndexedDictionary<T>(this IEnumerable<T> extends)
public static Dictionary<int, T> ToIndexedDictionary<T>([NotNull] this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -862,7 +956,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static Dictionary<uint, T> ToIndexedDictionaryUInt<T>(this IEnumerable<T> extends)
public static Dictionary<uint, T> ToIndexedDictionaryUInt<T>([NotNull] this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -873,19 +967,49 @@ namespace ICD.Common.Utils.Extensions
}
/// <summary>
/// Turns an enumerable of KeyValuePairs back into a dictionary
/// Returns true if all of the items in the sequence are equal, or the sequence is empty.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <typeparam name="TItem"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> extends)
public static bool IsDistinct<TItem>([NotNull] this IEnumerable<TItem> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.ToDictionary(x => x.Key, x => x.Value);
IEqualityComparer<TItem> comparer = EqualityComparer<TItem>.Default;
return extends.IsDistinct(comparer);
}
/// <summary>
/// Returns true if all of the items in the sequence are equal, or the sequence is empty.
/// </summary>
/// <typeparam name="TItem"></typeparam>
/// <param name="extends"></param>
/// <param name="comparer"></param>
/// <returns></returns>
public static bool IsDistinct<TItem>([NotNull] this IEnumerable<TItem> extends, [NotNull] IEqualityComparer<TItem> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
TItem other = default(TItem);
bool first = true;
foreach (TItem item in extends)
{
if (first)
{
other = item;
first = false;
continue;
}
if (!comparer.Equals(item, other))
return false;
}
return true;
}
/// <summary>
@@ -897,8 +1021,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="getProperty"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<TItem> Distinct<TItem, TProperty>(this IEnumerable<TItem> extends,
Func<TItem, TProperty> getProperty)
public static IEnumerable<TItem> Distinct<TItem, TProperty>([NotNull] this IEnumerable<TItem> extends,
[NotNull] Func<TItem, TProperty> getProperty)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -920,8 +1044,9 @@ namespace ICD.Common.Utils.Extensions
/// <param name="propertyComparer"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<TItem> Distinct<TItem, TProperty>(this IEnumerable<TItem> extends,
public static IEnumerable<TItem> Distinct<TItem, TProperty>([NotNull] this IEnumerable<TItem> extends,
Func<TItem, TProperty> getProperty,
[NotNull]
IEqualityComparer<TProperty> propertyComparer)
{
if (extends == null)
@@ -942,7 +1067,7 @@ namespace ICD.Common.Utils.Extensions
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
public static T Random<T>(this IEnumerable<T> extends)
public static T Random<T>([NotNull] this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -967,7 +1092,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="other"></param>
/// <returns></returns>
[PublicAPI]
public static T Unanimous<T>(this IEnumerable<T> extends, T other)
public static T Unanimous<T>([NotNull] this IEnumerable<T> extends, T other)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -985,7 +1110,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="result"></param>
/// <returns></returns>
[PublicAPI]
public static bool Unanimous<T>(this IEnumerable<T> extends, out T result)
public static bool Unanimous<T>([NotNull] this IEnumerable<T> extends, out T result)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -1003,7 +1128,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="result"></param>
/// <returns></returns>
[PublicAPI]
public static bool Unanimous<T>(this IEnumerable<T> extends, IEqualityComparer<T> comparer, out T result)
public static bool Unanimous<T>([NotNull] this IEnumerable<T> extends, [NotNull] IEqualityComparer<T> comparer,
out T result)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -1042,7 +1168,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="partitionSize"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> extends, int partitionSize)
public static IEnumerable<IEnumerable<T>> Partition<T>([NotNull] this IEnumerable<T> extends, int partitionSize)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -1056,7 +1182,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="sequence"></param>
/// <param name="partitionSize"></param>
/// <returns></returns>
private static IEnumerable<IEnumerable<T>> PartitionIterator<T>(IEnumerable<T> sequence, int partitionSize)
private static IEnumerable<IEnumerable<T>> PartitionIterator<T>([NotNull] IEnumerable<T> sequence,
int partitionSize)
{
using (IEnumerator<T> enumerator = sequence.GetEnumerator())
{
@@ -1065,7 +1192,7 @@ namespace ICD.Common.Utils.Extensions
}
}
private static IEnumerable<T> YieldBatchElements<T>(IEnumerator<T> source, int partitionSize)
private static IEnumerable<T> YieldBatchElements<T>([NotNull] IEnumerator<T> source, int partitionSize)
{
if (source == null)
throw new ArgumentNullException("source");
@@ -1086,7 +1213,7 @@ namespace ICD.Common.Utils.Extensions
/// <typeparam name="T">Type of the object.</typeparam>
/// <param name="item">The instance that will be wrapped.</param>
/// <returns>An IEnumerable&lt;T&gt; consisting of a single item.</returns>
public static IEnumerable<T> Yield<T>(this T item)
public static IEnumerable<T> Yield<T>([CanBeNull] this T item)
{
yield return item;
}
@@ -1097,7 +1224,7 @@ namespace ICD.Common.Utils.Extensions
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
public static IEnumerable<T[]> GetAdjacentPairs<T>(this IEnumerable<T> extends)
public static IEnumerable<T[]> GetAdjacentPairs<T>([NotNull] this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -1111,7 +1238,7 @@ namespace ICD.Common.Utils.Extensions
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
private static IEnumerable<T[]> GetAdjacentPairsIterator<T>(IEnumerable<T> extends)
private static IEnumerable<T[]> GetAdjacentPairsIterator<T>([NotNull] IEnumerable<T> extends)
{
T previous = default(T);
bool first = true;
@@ -1119,7 +1246,7 @@ namespace ICD.Common.Utils.Extensions
foreach (T item in extends)
{
if (!first)
yield return new[] { previous, item };
yield return new[] {previous, item};
first = false;
previous = item;
@@ -1133,7 +1260,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="getDelta"></param>
/// <returns></returns>
public static T GetClosest<T>(this IEnumerable<T> extends, Func<T, int> getDelta)
public static T GetClosest<T>([NotNull] this IEnumerable<T> extends, [NotNull] Func<T, int> getDelta)
{
return extends.MinBy(n => Math.Abs(getDelta(n)));
}
@@ -1156,8 +1283,8 @@ namespace ICD.Common.Utils.Extensions
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="selector"/> is null</exception>
/// <exception cref="InvalidOperationException"><paramref name="source"/> is empty</exception>
[PublicAPI]
public static TSource MinBy<TSource, TKey>(this IEnumerable<TSource> source,
Func<TSource, TKey> selector)
public static TSource MinBy<TSource, TKey>([NotNull] this IEnumerable<TSource> source,
[NotNull] Func<TSource, TKey> selector)
{
if (source == null)
throw new ArgumentNullException("source");
@@ -1187,8 +1314,9 @@ namespace ICD.Common.Utils.Extensions
/// or <paramref name="comparer"/> is null</exception>
/// <exception cref="InvalidOperationException"><paramref name="source"/> is empty</exception>
[PublicAPI]
public static TSource MinBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector,
IComparer<TKey> comparer)
public static TSource MinBy<TSource, TKey>([NotNull] this IEnumerable<TSource> source,
[NotNull] Func<TSource, TKey> selector,
[NotNull] IComparer<TKey> comparer)
{
if (source == null)
throw new ArgumentNullException("source");
@@ -1224,19 +1352,57 @@ namespace ICD.Common.Utils.Extensions
}
/// <summary>
/// Removes any null elements from an enumerable of nullable value types
/// Returns the minimum value from the sequence, otherwise the default value.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<T> ExceptNulls<T>(this IEnumerable<T?> extends)
where T : struct
public static T MinOrDefault<T>([NotNull] this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.OfType<T>();
Comparer<T> comparer = Comparer<T>.Default;
T value = default(T);
bool first = true;
foreach (T x in extends)
{
if (first)
{
first = false;
value = x;
continue;
}
if (comparer.Compare(x, value) < 0)
value = x;
}
return value;
}
/// <summary>
/// Returns the maximum value from the sequence, otherwise the default value.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
public static T MaxOrDefault<T>([NotNull] this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
Comparer<T> comparer = Comparer<T>.Default;
T value = default(T);
foreach (T x in extends)
{
if (comparer.Compare(x, value) > 0)
value = x;
}
return value;
}
/// <summary>
@@ -1245,7 +1411,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static byte Sum(this IEnumerable<byte> extends)
public static byte Sum([NotNull] this IEnumerable<byte> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -1264,7 +1430,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<T> Consolidate<T>(this IEnumerable<T> extends)
public static IEnumerable<T> Consolidate<T>([NotNull] this IEnumerable<T> extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -1284,7 +1450,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="comparer"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<T> Consolidate<T>(this IEnumerable<T> extends, IComparer<T> comparer)
public static IEnumerable<T> Consolidate<T>([NotNull] this IEnumerable<T> extends,
[NotNull] IComparer<T> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -1306,7 +1473,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="sequence"></param>
/// <param name="comparer"></param>
/// <returns></returns>
private static IEnumerable<T> ConsolidateIterator<T>(IEnumerable<T> sequence, IComparer<T> comparer)
private static IEnumerable<T> ConsolidateIterator<T>([NotNull] IEnumerable<T> sequence,
[NotNull] IComparer<T> comparer)
{
bool first = true;
T last = default(T);
@@ -1332,7 +1500,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="predicate"></param>
/// <returns></returns>
[PublicAPI]
public static bool AnyAndAll<T>(this IEnumerable<T> extends, Func<T, bool> predicate)
public static bool AnyAndAll<T>([NotNull] this IEnumerable<T> extends, [NotNull] Func<T, bool> predicate)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -1351,19 +1519,40 @@ namespace ICD.Common.Utils.Extensions
return any;
}
/// <summary>
/// Combines the corresponding elements of two sequences, producing a sequence of KeyValuePairs.
/// </summary>
/// <typeparam name="TFirst"></typeparam>
/// <typeparam name="TSecond"></typeparam>
/// <param name="extends"></param>
/// <param name="second"></param>
public static IEnumerable<KeyValuePair<TFirst, TSecond>> Zip<TFirst, TSecond>(
[NotNull] this IEnumerable<TFirst> extends,
[NotNull] IEnumerable<TSecond> second)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (second == null)
throw new ArgumentNullException("second");
return extends.Zip(second, (f, s) => new KeyValuePair<TFirst, TSecond>(f, s));
}
#if SIMPLSHARP
/// <summary>
/// Applies a specified function to the corresponding elements of two sequences, producing a sequence of the results.
/// </summary>
/// <typeparam name="TFirst"></typeparam>
/// <typeparam name="TSecond"></typeparam>
/// <param name="first"></param>
/// <param name="extends"></param>
/// <param name="second"></param>
/// <param name="callback"></param>
public static void Zip<TFirst, TSecond>(this IEnumerable<TFirst> first,
IEnumerable<TSecond> second,
Action<TFirst, TSecond> callback)
public static void Zip<TFirst, TSecond>([NotNull]this IEnumerable<TFirst> extends,
[NotNull]IEnumerable<TSecond> second,
[NotNull]Action<TFirst, TSecond> callback)
{
if (first == null)
if (extends == null)
throw new ArgumentNullException("first");
if (second == null)
@@ -1372,7 +1561,7 @@ namespace ICD.Common.Utils.Extensions
if (callback == null)
throw new ArgumentNullException("callback");
using (IEnumerator<TFirst> enumerator1 = first.GetEnumerator())
using (IEnumerator<TFirst> enumerator1 = extends.GetEnumerator())
{
using (IEnumerator<TSecond> enumerator2 = second.GetEnumerator())
{
@@ -1382,51 +1571,6 @@ namespace ICD.Common.Utils.Extensions
}
}
// since S# can't do anonymous types
private struct TryParseStruct<T>
{
public readonly T value;
public readonly bool isParsed;
public TryParseStruct(T value, bool isParsed)
{
this.value = value;
this.isParsed = isParsed;
}
}
// since Func<...,T> can't specify `out` parameters
public delegate bool TryParseDelegate<T>(string input, out T output);
/// <summary>
/// Attempts to parse each value of the enumerable,
/// throwing away the values that don't parse correctly.
/// </summary>
/// <typeparam name="T">type to parse to</typeparam>
/// <param name="extends">enumerable of strings to parse</param>
/// <param name="tryParseFunc">TryParse function for given type</param>
/// <returns>enumerable of successfully parsed values</returns>
public static IEnumerable<T> TryParseSkipFailures<T>(this IEnumerable<string> extends,
TryParseDelegate<T> tryParseFunc)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (tryParseFunc == null)
throw new ArgumentNullException("tryParseFunc");
return extends.Select(str =>
{
T value;
bool isParsed = tryParseFunc(str, out value);
return new TryParseStruct<T>(value, isParsed);
})
.Where(v => v.isParsed)
.Select(v => v.value);
}
#if SIMPLSHARP
/// <summary>
/// Applies a specified function to the corresponding elements of two sequences, producing a sequence of the results.
/// </summary>
@@ -1437,9 +1581,9 @@ namespace ICD.Common.Utils.Extensions
/// <param name="other"></param>
/// <param name="callback"></param>
/// <returns></returns>
public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> extends,
IEnumerable<TSecond> other,
Func<TFirst, TSecond, TResult> callback)
public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>([NotNull]this IEnumerable<TFirst> extends,
[NotNull]IEnumerable<TSecond> other,
[NotNull]Func<TFirst, TSecond, TResult> callback)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -1463,9 +1607,9 @@ namespace ICD.Common.Utils.Extensions
/// <param name="second"></param>
/// <param name="callback"></param>
/// <returns></returns>
private static IEnumerable<TResult> ZipIterator<TFirst, TSecond, TResult>(IEnumerable<TFirst> first,
IEnumerable<TSecond> second,
Func<TFirst, TSecond, TResult> callback)
private static IEnumerable<TResult> ZipIterator<TFirst, TSecond, TResult>([NotNull]IEnumerable<TFirst> first,
[NotNull]IEnumerable<TSecond> second,
[NotNull]Func<TFirst, TSecond, TResult> callback)
{
using (IEnumerator<TFirst> enumerator1 = first.GetEnumerator())
{
@@ -1476,7 +1620,6 @@ namespace ICD.Common.Utils.Extensions
}
}
}
#endif
}
}

View File

@@ -1,9 +1,5 @@
using System;
#if SIMPLSHARP
using Crestron.SimplSharp.Reflection;
#else
using System.Reflection;
#endif
using ICD.Common.Properties;
namespace ICD.Common.Utils.Extensions
{
@@ -17,7 +13,7 @@ namespace ICD.Common.Utils.Extensions
/// </summary>
/// <param name="extends"></param>
/// <param name="sender"></param>
public static void Raise(this EventHandler extends, object sender)
public static void Raise([CanBeNull] this EventHandler extends, object sender)
{
if (extends != null)
extends(sender, EventArgs.Empty);
@@ -30,7 +26,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="sender"></param>
/// <param name="args"></param>
public static void Raise<T>(this EventHandler<T> extends, object sender, T args)
public static void Raise<T>([CanBeNull]this EventHandler<T> extends, object sender, [NotNull]T args)
where T : EventArgs
{
if (args == null)
@@ -39,22 +35,5 @@ namespace ICD.Common.Utils.Extensions
if (extends != null)
extends(sender, args);
}
/// <summary>
/// Cross-platform shim for getting MethodInfo for the delegate.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static MethodInfo GetMethodInfo(this Delegate extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
#if SIMPLSHARP
return extends.GetMethod();
#else
return extends.Method;
#endif
}
}
}

View File

@@ -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();
}
}
}
}

View File

@@ -0,0 +1,304 @@
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>([NotNull] 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>([NotNull] this JsonReader extends, [NotNull] 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([NotNull] this JsonReader extends, [NotNull] JsonSerializer serializer,
[NotNull] 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([NotNull] 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([NotNull] 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([NotNull] 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 long.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static long GetValueAsLong([NotNull] this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.TokenType == JsonToken.Integer)
return (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 unsigned long.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static ulong GetValueAsULong([NotNull] this JsonReader extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (extends.TokenType == JsonToken.Integer)
return (ulong)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([NotNull] 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([NotNull] 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>([NotNull] 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([NotNull] 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([NotNull] 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([NotNull] this JsonReader extends, [NotNull] string format,
IFormatProvider provider)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (format == null)
throw new ArgumentNullException("format");
#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);
}
}
}

View File

@@ -0,0 +1,335 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
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>
[CanBeNull]
public static IEnumerable<TItem> DeserializeArray<TItem>([NotNull] this JsonSerializer extends,
[NotNull] 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>
[CanBeNull]
public static IEnumerable<TItem> DeserializeArray<TItem>([NotNull] this JsonSerializer extends,
[NotNull] JsonReader reader,
[NotNull] 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 null;
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>
[NotNull]
private static IEnumerable<TItem> DeserializeArrayIterator<TItem>(
[NotNull] JsonSerializer serializer, [NotNull] JsonReader reader,
[NotNull] 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>
[CanBeNull]
public static IEnumerable<KeyValuePair<TKey, TValue>> DeserializeDict<TKey, TValue>(
[NotNull] this JsonSerializer extends,
[NotNull] 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>
[CanBeNull]
public static IEnumerable<KeyValuePair<TKey, TValue>> DeserializeDict<TKey, TValue>(
[NotNull] this JsonSerializer extends,
[NotNull] JsonReader reader,
[NotNull] Func<JsonSerializer, JsonReader, TKey> readKey,
[NotNull] 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>(
[NotNull] this JsonSerializer extends,
[NotNull] JsonReader reader,
[NotNull] Func<JsonSerializer, JsonReader, TKey> readKey,
[NotNull] 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>([NotNull] this JsonSerializer extends, [NotNull] JsonWriter writer,
[CanBeNull] IEnumerable<TItem> items)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (writer == null)
throw new ArgumentNullException("writer");
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>([NotNull] this JsonSerializer extends, [NotNull] JsonWriter writer,
[CanBeNull] IEnumerable<TItem> items,
[NotNull] 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>([NotNull] this JsonSerializer extends,
[NotNull] JsonWriter writer,
[CanBeNull] 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>([NotNull] this JsonSerializer extends,
[NotNull] JsonWriter writer,
[CanBeNull] IEnumerable<KeyValuePair<TKey, TValue>> items,
[NotNull] Action<JsonSerializer, JsonWriter, TKey> writeKey,
[NotNull] 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>(
[NotNull] this JsonSerializer extends,
[NotNull] JsonWriter writer, KeyValuePair<TKey, TValue> kvp,
[NotNull] Action<JsonSerializer, JsonWriter, TKey> writeKey,
[NotNull] 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();
}
}
}

View 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");
}
}
}
}

View 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([NotNull]this JsonWriter extends, [CanBeNull]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([NotNull]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([NotNull]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([NotNull]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([NotNull]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([NotNull]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([NotNull]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([NotNull]this JsonWriter extends, string propertyName, Type value)
{
if (extends == null)
throw new ArgumentNullException("extends");
extends.WritePropertyName(propertyName);
extends.WriteType(value);
}
}
}

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
using ICD.Common.Utils.Comparers;
@@ -11,14 +10,159 @@ namespace ICD.Common.Utils.Extensions
/// </summary>
public static class ListExtensions
{
#region Add Sorted
/// <summary>
/// Adds the items into a sorted list.
/// Attempts to add the item to the sorted list.
/// Returns false if the item already exists in the list.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="item"></param>
/// <returns></returns>
[PublicAPI]
public static bool AddSorted<T>([NotNull] this IList<T> extends, T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.AddSorted(item, Comparer<T>.Default);
}
/// <summary>
/// Attempts to add the item to the sorted list.
/// Returns false if the item already exists in the list.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TProp"></typeparam>
/// <param name="extends"></param>
/// <param name="item"></param>
/// <param name="predicate"></param>
[PublicAPI]
public static bool AddSorted<T, TProp>([NotNull] this IList<T> extends, T item,
[NotNull] Func<T, TProp> predicate)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (predicate == null)
throw new ArgumentNullException("predicate");
PredicateComparer<T, TProp> comparer = new PredicateComparer<T, TProp>(predicate);
return extends.AddSorted(item, comparer);
}
/// <summary>
/// Attempts to add the item to the sorted list.
/// Returns false if the item already exists in the list.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="item"></param>
/// <param name="comparer"></param>
/// <returns></returns>
[PublicAPI]
public static bool AddSorted<T>([NotNull] this IList<T> extends, T item, [NotNull] IComparer<T> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (comparer == null)
throw new ArgumentNullException("comparer");
int index = extends.BinarySearch(item, comparer);
if (index >= 0)
return false;
index = ~index;
extends.Insert(index, item);
return true;
}
#endregion
#region Remove Sorted
/// <summary>
/// Attempts to remove the item from the sorted list.
/// Returns false if the item does not exist in the list.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="item"></param>
/// <returns></returns>
[PublicAPI]
public static bool RemoveSorted<T>([NotNull] this IList<T> extends, T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.RemoveSorted(item, Comparer<T>.Default);
}
/// <summary>
/// Attempts to remove the item from the sorted list.
/// Returns false if the item does not exist in the list.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TProp"></typeparam>
/// <param name="extends"></param>
/// <param name="item"></param>
/// <param name="predicate"></param>
[PublicAPI]
public static bool RemoveSorted<T, TProp>([NotNull] this IList<T> extends, T item,
[NotNull] Func<T, TProp> predicate)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (predicate == null)
throw new ArgumentNullException("predicate");
PredicateComparer<T, TProp> comparer = new PredicateComparer<T, TProp>(predicate);
return extends.RemoveSorted(item, comparer);
}
/// <summary>
/// Attempts to remove the item from the sorted list.
/// Returns false if the item does not exist in the list.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="item"></param>
/// <param name="comparer"></param>
/// <returns></returns>
[PublicAPI]
public static bool RemoveSorted<T>([NotNull] this IList<T> extends, T item, [NotNull] IComparer<T> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (comparer == null)
throw new ArgumentNullException("comparer");
int index = extends.BinarySearch(item, comparer);
if (index < 0)
return false;
extends.RemoveAt(index);
return true;
}
#endregion
#region Insert Sorted
/// <summary>
/// Inserts the items into a sorted list.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="items"></param>
[PublicAPI]
public static void AddSorted<T>(this List<T> extends, IEnumerable<T> items)
public static void InsertSorted<T>([NotNull] this IList<T> extends, [NotNull] IEnumerable<T> items)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -26,18 +170,19 @@ namespace ICD.Common.Utils.Extensions
if (items == null)
throw new ArgumentNullException("items");
extends.AddSorted(items, Comparer<T>.Default);
extends.InsertSorted(items, Comparer<T>.Default);
}
/// <summary>
/// Adds the items into a sorted list.
/// Inserts the items into a sorted list.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <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 InsertSorted<T>([NotNull] this IList<T> extends, [NotNull] IEnumerable<T> items,
[NotNull] IComparer<T> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -48,11 +193,11 @@ namespace ICD.Common.Utils.Extensions
if (comparer == null)
throw new ArgumentNullException("comparer");
items.ForEach(i => extends.AddSorted(i, comparer));
items.ForEach(i => extends.InsertSorted(i, comparer));
}
/// <summary>
/// Adds the items into a sorted list.
/// Inserts the items into a sorted list.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TProp"></typeparam>
@@ -60,7 +205,8 @@ 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 InsertSorted<T, TProp>([NotNull] this IList<T> extends, [NotNull] IEnumerable<T> items,
[NotNull] Func<T, TProp> predicate)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -72,33 +218,55 @@ namespace ICD.Common.Utils.Extensions
throw new ArgumentNullException("predicate");
PredicateComparer<T, TProp> comparer = new PredicateComparer<T, TProp>(predicate);
extends.AddSorted(items, comparer);
extends.InsertSorted(items, comparer);
}
/// <summary>
/// Adds the item into a sorted list.
/// Inserts the item into a sorted list.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="item"></param>
[PublicAPI]
public static int AddSorted<T>(this List<T> extends, T item)
public static int InsertSorted<T>([NotNull] this IList<T> extends, T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.AddSorted(item, Comparer<T>.Default);
return extends.InsertSorted(item, Comparer<T>.Default);
}
/// <summary>
/// Adds the item into a sorted list.
/// Inserts the item into a sorted list.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TProp"></typeparam>
/// <param name="extends"></param>
/// <param name="item"></param>
/// <param name="predicate"></param>
[PublicAPI]
public static int InsertSorted<T, TProp>([NotNull] this IList<T> extends, T item,
[NotNull] Func<T, TProp> predicate)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (predicate == null)
throw new ArgumentNullException("predicate");
PredicateComparer<T, TProp> comparer = new PredicateComparer<T, TProp>(predicate);
return extends.InsertSorted(item, comparer);
}
/// <summary>
/// Inserts the item into a sorted list.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <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 InsertSorted<T>([NotNull] this IList<T> extends, T item, [NotNull] IComparer<T> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -115,8 +283,48 @@ namespace ICD.Common.Utils.Extensions
return index;
}
#endregion
#region Contains Sorted
/// <summary>
/// Adds the item into a sorted list.
/// Returns true if the sorted list contains the given item.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="item"></param>
/// <returns></returns>
[PublicAPI]
public static bool ContainsSorted<T>([NotNull] this IList<T> extends, T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.ContainsSorted(item, Comparer<T>.Default);
}
/// <summary>
/// Returns true if the sorted list contains the given item.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="item"></param>
/// <param name="comparer"></param>
/// <returns></returns>
[PublicAPI]
public static bool ContainsSorted<T>([NotNull] this IList<T> extends, T item, [NotNull] IComparer<T> comparer)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (comparer == null)
throw new ArgumentNullException("comparer");
return extends.BinarySearch(item, comparer) >= 0;
}
/// <summary>
/// Returns true if the sorted list contains the given item.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TProp"></typeparam>
@@ -124,7 +332,8 @@ 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 bool ContainsSorted<T, TProp>([NotNull] this IList<T> extends, T item,
[NotNull] Func<T, TProp> predicate)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -133,48 +342,61 @@ namespace ICD.Common.Utils.Extensions
throw new ArgumentNullException("predicate");
PredicateComparer<T, TProp> comparer = new PredicateComparer<T, TProp>(predicate);
return extends.AddSorted(item, comparer);
return extends.ContainsSorted(item, comparer);
}
#endregion
#region Binary Search
/// <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>([NotNull] this IList<T> extends, T item, [NotNull] 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;
// Array
T[] array = extends as T[];
if (array != null)
return Array.BinarySearch(array, 0, array.Length, item, comparer);
extends.AddRange(Enumerable.Repeat(item, pad));
// List
List<T> list = extends as List<T>;
if (list != null)
return list.BinarySearch(item, comparer);
// IList
int lo = 0;
int hi = extends.Count - 1;
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;
}
#endregion
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Text;
using ICD.Common.Properties;
#if SIMPLSHARP
using Crestron.SimplSharp.Reflection;
#else
@@ -15,8 +16,11 @@ namespace ICD.Common.Utils.Extensions
/// </summary>
/// <param name="method">The Method</param>
/// <returns>Method signature</returns>
public static string GetSignature(this MethodInfo method)
public static string GetSignature([NotNull]this MethodInfo method)
{
if (method == null)
throw new ArgumentNullException("method");
return method.GetSignature(false);
}
@@ -26,8 +30,11 @@ namespace ICD.Common.Utils.Extensions
/// <param name="method">The Method</param>
/// <param name="callable">Return as a callable string(public void a(string b) would return a(b))</param>
/// <returns>Method signature</returns>
public static string GetSignature(this MethodInfo method, bool callable)
public static string GetSignature([NotNull]this MethodInfo method, bool callable)
{
if (method == null)
throw new ArgumentNullException("method");
bool firstParam = true;
StringBuilder sigBuilder = new StringBuilder();
@@ -123,5 +130,22 @@ namespace ICD.Common.Utils.Extensions
return sigBuilder.ToString();
}
/// <summary>
/// Cross-platform shim for getting MethodInfo for the delegate.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static MethodInfo GetMethodInfo([NotNull]this Delegate extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
#if SIMPLSHARP
return extends.GetMethod();
#else
return extends.Method;
#endif
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using ICD.Common.Properties;
#if SIMPLSHARP
using Crestron.SimplSharp.Reflection;
#else
@@ -14,7 +15,7 @@ namespace ICD.Common.Utils.Extensions
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static bool GetIsOut(this ParameterInfo extends)
public static bool GetIsOut([NotNull] this ParameterInfo extends)
{
if (extends == null)
throw new ArgumentNullException("extends");

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Extensions
{
@@ -11,7 +12,7 @@ namespace ICD.Common.Utils.Extensions
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="items"></param>
public static void EnqueueRange<T>(this Queue<T> extends, IEnumerable<T> items)
public static void EnqueueRange<T>([NotNull] this Queue<T> extends, [NotNull] IEnumerable<T> items)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -30,7 +31,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="item"></param>
/// <returns></returns>
public static bool Dequeue<T>(this Queue<T> extends, out T item)
public static bool Dequeue<T>([NotNull] this Queue<T> extends, out T item)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -43,5 +44,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>([NotNull] 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;
}
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
#if SIMPLSHARP
using Crestron.SimplSharp.Reflection;
#else
@@ -20,8 +21,7 @@ namespace ICD.Common.Utils.Extensions
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
public static IEnumerable<T> GetCustomAttributes<T>(this ICustomAttributeProvider extends)
where T : Attribute
public static IEnumerable<T> GetCustomAttributes<T>([NotNull] this ICustomAttributeProvider extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -36,7 +36,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="inherits"></param>
/// <returns></returns>
public static IEnumerable<T> GetCustomAttributes<T>(this ICustomAttributeProvider extends, bool inherits)
public static IEnumerable<T> GetCustomAttributes<T>([NotNull] this ICustomAttributeProvider extends,
bool inherits)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -58,8 +59,7 @@ namespace ICD.Common.Utils.Extensions
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <returns></returns>
public static T GetCustomAttribute<T>(this ICustomAttributeProvider extends)
where T : Attribute
public static T GetCustomAttribute<T>([NotNull] this ICustomAttributeProvider extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -74,8 +74,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="inherits"></param>
/// <returns></returns>
public static T GetCustomAttribute<T>(this ICustomAttributeProvider extends, bool inherits)
where T : Attribute
public static T GetCustomAttribute<T>([NotNull] this ICustomAttributeProvider extends, bool inherits)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -89,16 +88,18 @@ namespace ICD.Common.Utils.Extensions
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="inherits"></param>
/// <returns></returns>
public static IEnumerable<T> GetCustomAttributesIncludingBaseInterfaces<T>(this Type extends)
public static IEnumerable<T> GetCustomAttributesIncludingBaseInterfaces<T>([NotNull] this Type extends)
where T : Attribute
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.GetCustomAttributes<T>(true)
.Union(extends.GetInterfaces()
.SelectMany(interfaceType => interfaceType
.GetCustomAttributes<T>(true)))
.Distinct();
.Union(extends.GetInterfaces()
.SelectMany(interfaceType => interfaceType
.GetCustomAttributes<T>(true)))
.Distinct();
}
/// <summary>
@@ -106,23 +107,25 @@ namespace ICD.Common.Utils.Extensions
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="extends"></param>
/// <param name="inherits"></param>
/// <returns></returns>
public static IEnumerable<T> GetCustomAttributesIncludingBaseInterfaces<T>(this MemberInfo extends)
public static IEnumerable<T> GetCustomAttributesIncludingBaseInterfaces<T>([NotNull] this MemberInfo extends)
where T : Attribute
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.GetCustomAttributes<T>(true)
.Union(extends.DeclaringType?
.GetInterfaces()
.SelectMany(interfaceType => interfaceType
.GetMember(
extends.Name,
extends.MemberType,
BindingFlags.Instance)
.FirstOrDefault()?
.GetCustomAttributes<T>(true) ?? Enumerable.Empty<T>())?
.Except(null) ?? Enumerable.Empty<T>())
.Distinct();
.Union(extends.DeclaringType?
.GetInterfaces()
.SelectMany(interfaceType => interfaceType
.GetMember(extends.Name,
extends.MemberType,
BindingFlags.Instance)
.FirstOrDefault()?
.GetCustomAttributes<T>(true) ??
Enumerable.Empty<T>())?
.Except(null) ?? Enumerable.Empty<T>())
.Distinct();
}
#endif
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Text;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Extensions
{
@@ -9,7 +10,7 @@ namespace ICD.Common.Utils.Extensions
/// Empties the StringBuilder.
/// </summary>
/// <param name="extends"></param>
public static void Clear(this StringBuilder extends)
public static void Clear([NotNull] this StringBuilder extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -23,7 +24,7 @@ namespace ICD.Common.Utils.Extensions
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static string Pop(this StringBuilder extends)
public static string Pop([NotNull] this StringBuilder extends)
{
if (extends == null)
throw new ArgumentNullException("extends");

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Extensions
@@ -15,7 +16,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="first"></param>
/// <returns></returns>
[PublicAPI]
public static int IndexOf(this string extends, IEnumerable<string> items, out string first)
public static int IndexOf([NotNull] this string extends, [NotNull] IEnumerable<string> items, out string first)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -52,7 +53,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="character"></param>
/// <returns></returns>
[PublicAPI]
public static bool StartsWith(this string extends, char character)
public static bool StartsWith([NotNull] this string extends, char character)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -67,7 +68,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="character"></param>
/// <returns></returns>
[PublicAPI]
public static bool EndsWith(this string extends, char character)
public static bool EndsWith([NotNull] this string extends, char character)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -83,7 +84,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="delimeter"></param>
/// <param name="count"></param>
/// <returns></returns>
public static IEnumerable<string> Split(this string extends, char delimeter, int count)
[NotNull]
public static IEnumerable<string> Split([NotNull] this string extends, char delimeter, int count)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -102,7 +104,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="delimeter"></param>
/// <param name="count"></param>
/// <returns></returns>
private static IEnumerable<string> SplitIterator(string value, char delimeter, int count)
[NotNull]
private static IEnumerable<string> SplitIterator([NotNull] string value, char delimeter, int count)
{
while (count > 1)
{
@@ -125,7 +128,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="chunkSize"></param>
/// <returns></returns>
[PublicAPI]
public static IEnumerable<string> Split(this string extends, int chunkSize)
[NotNull]
public static IEnumerable<string> Split([NotNull] this string extends, int chunkSize)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -134,7 +138,8 @@ namespace ICD.Common.Utils.Extensions
throw new InvalidOperationException("chunkSize must be greater than 0");
return Enumerable.Range(0, (int)Math.Ceiling(extends.Length / (double)chunkSize))
.Select(i => extends.Substring(i * chunkSize, Math.Min(chunkSize, extends.Length - (i * chunkSize))));
.Select(i => extends.Substring(i * chunkSize,
Math.Min(chunkSize, extends.Length - (i * chunkSize))));
}
/// <summary>
@@ -143,7 +148,8 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static string RemoveWhitespace(this string extends)
[NotNull]
public static string RemoveWhitespace([NotNull] this string extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -152,12 +158,13 @@ namespace ICD.Common.Utils.Extensions
}
/// <summary>
/// Removes all occurances of the given string.
/// Removes all occurrences of the given string.
/// </summary>
/// <param name="extends"></param>
/// <param name="other"></param>
/// <returns></returns>
public static string Remove(this string extends, string other)
[NotNull]
public static string Remove([NotNull] this string extends, [NotNull] string other)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -176,19 +183,21 @@ namespace ICD.Common.Utils.Extensions
}
/// <summary>
/// Removes all occurances the given characters from the string.
/// Removes all occurrences the given characters from the string.
/// </summary>
/// <param name="extends"></param>
/// <param name="characters"></param>
/// <returns></returns>
[PublicAPI]
public static string Remove(this string extends, IEnumerable<char> characters)
[NotNull]
public static string Remove([NotNull] this string extends, IEnumerable<char> characters)
{
if (extends == null)
throw new ArgumentNullException("extends");
if (characters == null)
throw new ArgumentNullException("characters");
var cSet = characters.ToIcdHashSet();
return new string(extends.Where(c => !cSet.Contains(c)).ToArray());
@@ -200,7 +209,7 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <returns></returns>
[PublicAPI]
public static bool IsNumeric(this string extends)
public static bool IsNumeric([NotNull] this string extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -214,12 +223,89 @@ namespace ICD.Common.Utils.Extensions
/// <param name="extends"></param>
/// <param name="character"></param>
/// <returns></returns>
public static bool Contains(this string extends, char character)
public static bool Contains([NotNull] this string extends, char character)
{
if (extends == null)
throw new ArgumentNullException("extends");
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([NotNull] this string extends)
{
if (extends == null)
throw new ArgumentNullException("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);
}
}
/// <summary>
/// Strips all of the non-printable characters and control codes from the string.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static string ToPrintableCharacters([NotNull] this string extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
// Strip ANSI escape sequences
extends = Regex.Replace(extends, AnsiUtils.ANSI_REGEX, string.Empty);
// Strip control characters
extends = Regex.Replace(extends, @"\p{C}+", string.Empty);
return extends;
}
/// <summary>
/// Gets the printable length of the string.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static int GetPrintableLength([NotNull] this string extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.ToPrintableCharacters().Length;
}
/// <summary>
/// Pads the string to the number of printable characters.
/// </summary>
/// <param name="extends"></param>
/// <param name="length"></param>
/// <returns></returns>
public static string PadRightPrintable([NotNull] this string extends, int length)
{
if (extends == null)
throw new ArgumentNullException("extends");
int printableLength = extends.GetPrintableLength();
int actualLength = extends.Length;
int delta = actualLength - printableLength;
return extends.PadRight(length + delta);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICD.Common.Properties;
using ICD.Common.Utils.Collections;
#if SIMPLSHARP
using Crestron.SimplSharp.Reflection;
@@ -62,6 +63,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 +75,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>
@@ -79,7 +84,7 @@ namespace ICD.Common.Utils.Extensions
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static bool CanBeNull(this Type extends)
public static bool CanBeNull([NotNull]this Type extends)
{
if (extends == null)
throw new ArgumentException("extends");
@@ -92,7 +97,7 @@ namespace ICD.Common.Utils.Extensions
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static bool IsNumeric(this Type extends)
public static bool IsNumeric([NotNull]this Type extends)
{
if (extends == null)
throw new ArgumentException("extends");
@@ -105,7 +110,7 @@ namespace ICD.Common.Utils.Extensions
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static bool IsSignedNumeric(this Type extends)
public static bool IsSignedNumeric([NotNull]this Type extends)
{
if (extends == null)
throw new ArgumentException("extends");
@@ -118,7 +123,7 @@ namespace ICD.Common.Utils.Extensions
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static bool IsDecimalNumeric(this Type extends)
public static bool IsDecimalNumeric([NotNull]this Type extends)
{
if (extends == null)
throw new ArgumentException("extends");
@@ -131,7 +136,7 @@ namespace ICD.Common.Utils.Extensions
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static bool IsIntegerNumeric(this Type extends)
public static bool IsIntegerNumeric([NotNull]this Type extends)
{
if (extends == null)
throw new ArgumentException("extends");
@@ -144,7 +149,8 @@ namespace ICD.Common.Utils.Extensions
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static Assembly GetAssembly(this Type extends)
[NotNull]
public static Assembly GetAssembly([NotNull]this Type extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -158,13 +164,26 @@ 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>([NotNull]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>
/// <param name="from"></param>
/// <param name="to"></param>
/// <returns></returns>
public static bool IsAssignableTo(this Type from, Type to)
public static bool IsAssignableTo([NotNull]this Type from, [NotNull]Type to)
{
if (from == null)
throw new ArgumentNullException("from");
@@ -180,7 +199,8 @@ namespace ICD.Common.Utils.Extensions
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static IEnumerable<Type> GetAllTypes(this Type extends)
[NotNull]
public static IEnumerable<Type> GetAllTypes([NotNull]this Type extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -204,7 +224,8 @@ namespace ICD.Common.Utils.Extensions
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static IEnumerable<Type> GetBaseTypes(this Type extends)
[NotNull]
public static IEnumerable<Type> GetBaseTypes([NotNull]this Type extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -219,7 +240,8 @@ namespace ICD.Common.Utils.Extensions
return types;
}
private static IEnumerable<Type> GetBaseTypesIterator(Type type)
[NotNull]
private static IEnumerable<Type> GetBaseTypesIterator([NotNull] Type type)
{
do
{
@@ -240,7 +262,8 @@ namespace ICD.Common.Utils.Extensions
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static IEnumerable<Type> GetImmediateInterfaces(this Type extends)
[NotNull]
public static IEnumerable<Type> GetImmediateInterfaces([NotNull]this Type extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -269,7 +292,8 @@ namespace ICD.Common.Utils.Extensions
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static IEnumerable<Type> GetMinimalInterfaces(this Type extends)
[NotNull]
public static IEnumerable<Type> GetMinimalInterfaces([NotNull]this Type extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -297,7 +321,8 @@ namespace ICD.Common.Utils.Extensions
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static string GetNameWithoutGenericArity(this Type extends)
[NotNull]
public static string GetNameWithoutGenericArity([NotNull]this Type extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -307,12 +332,137 @@ 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>
[NotNull]
public static string GetMinimalName([NotNull]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>
[NotNull]
public static string GetNameWithoutAssemblyDetails([NotNull]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>
[NotNull]
private static string RemoveAssemblyDetails([NotNull] 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>
/// <param name="extends">Type. May be generic or nullable</param>
/// <returns>Full type name, fully qualified namespaces</returns>
public static string GetSyntaxName(this Type extends)
[NotNull]
public static string GetSyntaxName([NotNull]this Type extends)
{
if (extends == null)
throw new ArgumentNullException("extends");

View File

@@ -1,5 +1,6 @@
using System;
using System.Linq;
using ICD.Common.Properties;
namespace ICD.Common.Utils.Extensions
{
@@ -10,7 +11,8 @@ namespace ICD.Common.Utils.Extensions
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static string GetUserName(this Uri extends)
[NotNull]
public static string GetUserName([NotNull] this Uri extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
@@ -23,12 +25,42 @@ namespace ICD.Common.Utils.Extensions
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static string GetPassword(this Uri extends)
[NotNull]
public static string GetPassword([NotNull] this Uri extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.UserInfo.Split(':').Skip(1).FirstOrDefault(string.Empty);
}
/// <summary>
/// Returns true if the URI matches the default http://localhost/
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static bool GetIsDefault([NotNull] this Uri extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
return extends.ToString() == "http://localhost/";
}
/// <summary>
/// Returns the string representation of the given URI, replacing the password with asterixes.
/// </summary>
/// <param name="extends"></param>
/// <returns></returns>
public static string ToPrivateString([NotNull] this Uri extends)
{
if (extends == null)
throw new ArgumentNullException("extends");
IcdUriBuilder builder = new IcdUriBuilder(extends);
builder.Password = builder.Password == null ? null : StringUtils.PasswordFormat(builder.Password);
return builder.ToString();
}
}
}

File diff suppressed because it is too large Load Diff

View 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);
}
}
}

View File

@@ -39,11 +39,17 @@
<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="Pastel" Version="1.3.1" />
<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>

View File

@@ -74,10 +74,11 @@
<Reference Include="System.Data" />
</ItemGroup>
<ItemGroup>
<Compile Include="AnsiUtils.cs" />
<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,10 +86,12 @@
<Compile Include="Comparers\FileNameEqualityComparer.cs" />
<Compile Include="Comparers\PredicateComparer.cs" />
<Compile Include="Comparers\SequenceComparer.cs" />
<Compile Include="ConsoleColor.cs" />
<Compile Include="eConsoleColor.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" />
@@ -102,21 +105,32 @@
<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="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="NullObject.cs" />
<Compile Include="ProcessorUtils.SimplSharp.cs" />
<Compile Include="ProcessorUtils.Standard.cs" />
<Compile Include="ProgramUtils.SimplSharp.cs" />
@@ -154,7 +168,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" />
@@ -185,6 +199,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" />
@@ -202,6 +217,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" />

View File

@@ -100,5 +100,11 @@ namespace ICD.Common.Utils.IO
{
return new IcdStreamWriter(File.AppendText(path));
}
public static void WriteAllBytes(string path, byte[] bytes)
{
using (FileStream stream = File.OpenWrite(path))
stream.Write(bytes, 0, bytes.Length);
}
}
}

View File

@@ -17,5 +17,10 @@ namespace ICD.Common.Utils.IO
public IcdStreamWriter(StreamWriter baseStreamWriter) : base(baseStreamWriter)
{
}
public void WriteLine(string value)
{
WrappedStreamWriter.WriteLine(value);
}
}
}

View File

@@ -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,32 @@ 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);
#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)
@@ -71,14 +81,8 @@ namespace ICD.Common.Utils
public static void PrintLine(eConsoleColor color, string message)
{
#if SIMPLSHARP
PrintLine(color.FormatAnsi(message));
#else
System.Console.ForegroundColor = color.ToForegroundConsoleColor();
System.Console.BackgroundColor = color.ToBackgroundConsoleColor();
System.Console.WriteLine(message);
System.Console.ResetColor();
#endif
string ansi = color.FormatAnsi(message);
PrintLine(ansi);
}
public static void PrintLine(eConsoleColor color, string message, params object[] args)
@@ -90,10 +94,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)
@@ -104,14 +110,8 @@ namespace ICD.Common.Utils
public static void Print(eConsoleColor color, string message)
{
#if SIMPLSHARP
Print(color.FormatAnsi(message));
#else
System.Console.ForegroundColor = color.ToForegroundConsoleColor();
System.Console.BackgroundColor = color.ToBackgroundConsoleColor();
System.Console.Write(message);
System.Console.ResetColor();
#endif
string ansi = color.FormatAnsi(message);
Print(ansi);
}
public static void Print(eConsoleColor color, string message, params object[] args)

View File

@@ -3,11 +3,19 @@ using System;
using System.Collections.Generic;
using Crestron.SimplSharp;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils
{
public static partial class IcdEnvironment
{
/// <summary>
/// For some reason crestron returns "Invalid Value" for ethernet parameters sometimes :/
/// </summary>
private const string INVALID_VALUE = "Invalid Value";
#region Properties
public static string NewLine { get { return CrestronEnvironment.NewLine; } }
public static eRuntimeEnvironment RuntimeEnvironment
@@ -30,9 +38,27 @@ 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);
foreach (EthernetAdapterType type in EnumUtils.GetValuesExceptNone<EthernetAdapterType>())
{
string address;
try
{
short id = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(type);
if (id >= InitialParametersClass.NumberOfEthernetInterfaces)
continue;
address = CrestronEthernetHelper.GetEthernetParameter(param, id);
}
catch (ArgumentException)
{
continue;
}
if (!string.IsNullOrEmpty(address) && !address.Equals(INVALID_VALUE))
yield return address;
}
}
}
@@ -46,12 +72,98 @@ namespace ICD.Common.Utils
{
const CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET param =
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS;
const EthernetAdapterType type = EthernetAdapterType.EthernetLANAdapter;
short id = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(type);
yield return CrestronEthernetHelper.GetEthernetParameter(param, id);
foreach (EthernetAdapterType type in EnumUtils.GetValuesExceptNone<EthernetAdapterType>())
{
string macAddress;
try
{
short id = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(type);
if (id >= InitialParametersClass.NumberOfEthernetInterfaces)
continue;
macAddress = CrestronEthernetHelper.GetEthernetParameter(param, id);
}
catch (ArgumentException)
{
continue;
}
if (!string.IsNullOrEmpty(macAddress) && !macAddress.Equals(INVALID_VALUE))
yield return macAddress;
}
}
}
/// <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;
try
{
short id = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(type);
if (id >= InitialParametersClass.NumberOfEthernetInterfaces)
return null;
string status = CrestronEthernetHelper.GetEthernetParameter(param, id);
if (!string.IsNullOrEmpty(status) && !status.Equals(INVALID_VALUE))
return status;
return null;
}
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;
foreach (EthernetAdapterType type in EnumUtils.GetValuesExceptNone<EthernetAdapterType>())
{
string hostname;
try
{
short id = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(type);
if (id >= InitialParametersClass.NumberOfEthernetInterfaces)
continue;
hostname = CrestronEthernetHelper.GetEthernetParameter(param, id);
}
catch (ArgumentException)
{
continue;
}
if (!string.IsNullOrEmpty(hostname) && !hostname.Equals(INVALID_VALUE))
yield return hostname;
}
}
}
#endregion
/// <summary>
/// Static constructor.
/// </summary>
@@ -68,6 +180,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)

View File

@@ -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,53 @@ namespace ICD.Common.Utils
}
}
/// <summary>
/// Gets the dhcp status of the processor.
/// </summary>
[PublicAPI]
public static string DhcpStatus
{
get
{
try
{
bool enabled =
NetworkInterface.GetAllNetworkInterfaces()
.Where(ni => ni.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 ||
ni.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
.Select(ni => ni.GetIPProperties().GetIPv4Properties().IsDhcpEnabled)
.FirstOrDefault();
return enabled.ToString();
}
catch(PlatformNotSupportedException)
{
return false.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();
#endif
}
/// <summary>
/// Converts 12 digit address to XX:XX:XX... format
/// </summary>

View File

@@ -1,4 +1,6 @@
using System;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils
{
@@ -54,5 +56,56 @@ 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);
}
/// <summary>
/// Gets UTC time
/// Uses GetLocalTime so Crestron Env will have ms percision
/// </summary>
/// <returns></returns>
public static DateTime GetUtcTime()
{
return GetLocalTime().ToUniversalTime();
}
}
}

View File

@@ -25,13 +25,12 @@ namespace ICD.Common.Utils
try
{
message = eConsoleColor.Red.FormatAnsi(message);
#if SIMPLSHARP
message = FormatConsoleColor(message, ConsoleColorExtensions.CONSOLE_RED);
ErrorLog.Error(message);
#else
System.Console.ForegroundColor = ConsoleColor.Red;
System.Console.Error.WriteLine(message);
System.Console.ResetColor();
Console.Error.WriteLine("Error - {0} - {1}", IcdEnvironment.GetLocalTime(), message);
#endif
}
finally
@@ -53,13 +52,13 @@ namespace ICD.Common.Utils
try
{
message = eConsoleColor.Yellow.FormatAnsi(message);
#if SIMPLSHARP
message = FormatConsoleColor(message, ConsoleColorExtensions.CONSOLE_YELLOW);
ErrorLog.Warn(message);
#else
System.Console.ForegroundColor = ConsoleColor.Yellow;
System.Console.Error.WriteLine(message);
System.Console.ResetColor();
Console.Error.WriteLine("Warn - {0} - {1}", IcdEnvironment.GetLocalTime(), message);
#endif
}
finally
@@ -81,13 +80,12 @@ namespace ICD.Common.Utils
try
{
message = eConsoleColor.Blue.FormatAnsi(message);
#if SIMPLSHARP
message = FormatConsoleColor(message, ConsoleColorExtensions.CONSOLE_BLUE);
ErrorLog.Notice(message);
#else
System.Console.ForegroundColor = ConsoleColor.Blue;
System.Console.Error.WriteLine(message);
System.Console.ResetColor();
Console.Error.WriteLine("Notice - {0} - {1}", IcdEnvironment.GetLocalTime(), message);
#endif
}
finally
@@ -109,13 +107,12 @@ namespace ICD.Common.Utils
try
{
message = eConsoleColor.Green.FormatAnsi(message);
#if SIMPLSHARP
message = FormatConsoleColor(message, ConsoleColorExtensions.CONSOLE_GREEN);
ErrorLog.Ok(message);
#else
System.Console.ForegroundColor = ConsoleColor.Green;
System.Console.Error.WriteLine(message);
System.Console.ResetColor();
Console.Error.WriteLine("OK - {0} - {1}", IcdEnvironment.GetLocalTime(), message);
#endif
}
finally
@@ -137,15 +134,17 @@ namespace ICD.Common.Utils
try
{
#if !SIMPLSHARP
message = string.Format("{0}: {1}", ex.GetType().Name, message);
#endif
message = eConsoleColor.YellowOnRed.FormatAnsi(message);
#if SIMPLSHARP
message = FormatConsoleColor(message, ConsoleColorExtensions.CONSOLE_YELLOW_ON_RED_BACKGROUND);
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.Error.WriteLine("Except - {0} - {1}", IcdEnvironment.GetLocalTime(), message);
Console.Error.WriteLine(ex.StackTrace);
#endif
}
finally
@@ -168,13 +167,12 @@ namespace ICD.Common.Utils
try
{
message = eConsoleColor.Cyan.FormatAnsi(message);
#if SIMPLSHARP
message = FormatConsoleColor(message, ConsoleColorExtensions.CONSOLE_CYAN);
ErrorLog.Info(message);
#else
System.Console.ForegroundColor = ConsoleColor.Cyan;
System.Console.Error.WriteLine(message);
System.Console.ResetColor();
Console.Error.WriteLine("Info - {0} - {1}", IcdEnvironment.GetLocalTime(), message);
#endif
}
finally
@@ -188,16 +186,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);
}
}
}

View File

@@ -4,6 +4,7 @@ using System.Linq;
#endif
using System.Text;
using System.Text.RegularExpressions;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
namespace ICD.Common.Utils
@@ -13,6 +14,8 @@ namespace ICD.Common.Utils
/// </summary>
public sealed class IcdUriBuilder
{
private string m_Query;
#region Properties
/// <summary>
@@ -43,7 +46,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.
@@ -66,7 +69,7 @@ namespace ICD.Common.Utils
/// Constructor.
/// </summary>
public IcdUriBuilder()
: this((Uri)null)
: this(new Uri("http://localhost/"))
{
}
@@ -83,10 +86,10 @@ namespace ICD.Common.Utils
/// Constructor.
/// </summary>
/// <param name="uri"></param>
public IcdUriBuilder(Uri uri)
public IcdUriBuilder([NotNull] Uri uri)
{
if (uri == null)
return;
throw new ArgumentNullException("uri");
if (!uri.IsAbsoluteUri)
uri = new Uri(Uri.UriSchemeHttp + Uri.SchemeDelimiter + uri);
@@ -96,7 +99,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();
}
@@ -107,20 +110,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);
@@ -134,8 +137,7 @@ namespace ICD.Common.Utils
builder.Append('@');
}
string host = string.IsNullOrEmpty(Host) ? "localhost" : Host;
builder.Append(host);
builder.Append(Host);
if (Port != 0)
{
@@ -150,10 +152,7 @@ namespace ICD.Common.Utils
// Query
if (!string.IsNullOrEmpty(Query))
{
builder.Append('?');
builder.Append(Query);
}
// Fragment
if (!string.IsNullOrEmpty(Fragment))

View File

@@ -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;
}

View File

@@ -5,7 +5,6 @@ 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
{
@@ -18,106 +17,6 @@ namespace ICD.Common.Utils.Json
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 data as a DateTime value.
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static DateTime ParseDateTime(string data)
{
return DateTime.Parse(data);
}
/// <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");
return ParseDateTime((string)token);
}
/// <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 (FormatException)
{
return false;
}
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>
@@ -240,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.
@@ -323,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);
}
}
}

View 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;
}
}
}

View File

@@ -72,12 +72,30 @@ namespace ICD.Common.Utils
public static double MapRange(double inputStart, double inputEnd, double outputStart, double outputEnd, double value)
{
if (inputStart.Equals(inputEnd))
throw new DivideByZeroException();
return outputStart;
double 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>
/// <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))
return outputStart;
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,55 @@ 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+ compatibility issues</remarks>
public static int Modulus(int number, int mod)
{
int remainder = number % mod;
return remainder < 0 ? remainder + mod : remainder;
}
/// <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+ compatibility issues</remarks>
public static long Modulus(long number, long mod)
{
long remainder = number % mod;
return remainder < 0 ? remainder + mod : remainder;
}
/// <summary>
/// Converts the value to a percentage.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
/// <param name="value"></param>
/// <returns></returns>
public static float ToPercent(float min, float max, float value)
{
return MapRange(min, max, 0.0f, 1.0f, value);
}
/// <summary>
/// Converts the value from a percentage.
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
/// <param name="percent"></param>
/// <returns></returns>
public static float FromPercent(float min, float max, float percent)
{
return MapRange(0.0f, 1.0f, min, max, percent);
}
}
}

View File

@@ -0,0 +1,121 @@
using System;
using System.Collections.Generic;
namespace ICD.Common.Utils
{
/// <summary>
/// Convenience wrapper for supporting null keys in hash tables.
/// </summary>
/// <typeparam name="T"></typeparam>
public struct NullObject<T> : IEquatable<NullObject<T>>, IComparable<NullObject<T>>
{
#region Properties
public T Item { get; private set; }
public bool IsNull { get; private set; }
public static NullObject<T> Null { get { return new NullObject<T>(); } }
#endregion
#region Constructors
/// <summary>
/// Constructor.
/// </summary>
/// <param name="item"></param>
public NullObject(T item)
// ReSharper disable CompareNonConstrainedGenericWithNull
: this(item, item == null)
// ReSharper restore CompareNonConstrainedGenericWithNull
{
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="item"></param>
/// <param name="isnull"></param>
private NullObject(T item, bool isnull)
: this()
{
IsNull = isnull;
Item = item;
}
#endregion
public override string ToString()
{
// ReSharper disable CompareNonConstrainedGenericWithNull
return Item == null ? "NULL" : Item.ToString();
// ReSharper restore CompareNonConstrainedGenericWithNull
}
#region Casting
public static implicit operator T(NullObject<T> nullObject)
{
return nullObject.Item;
}
public static implicit operator NullObject<T>(T item)
{
return new NullObject<T>(item);
}
#endregion
#region Equality
public override bool Equals(object obj)
{
if (obj == null)
return IsNull;
if (!(obj is NullObject<T>))
return false;
return Equals((NullObject<T>)obj);
}
public bool Equals(NullObject<T> other)
{
if (IsNull)
return other.IsNull;
return !other.IsNull && Item.Equals(other.Item);
}
public override int GetHashCode()
{
if (IsNull)
return 0;
var result = Item.GetHashCode();
if (result >= 0)
result++;
return result;
}
#endregion
#region Comparable
public int CompareTo(NullObject<T> other)
{
if (IsNull && other.IsNull)
return 0;
if (IsNull)
return -1;
return Comparer<T>.Default.Compare(Item, other.Item);
}
#endregion
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
@@ -47,7 +48,7 @@ namespace ICD.Common.Utils
#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
}
}
@@ -57,15 +58,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
{
if (IcdEnvironment.RuntimeEnvironment == IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono)
return Join(RootConfigPath, "ProgramConfig");
switch (IcdEnvironment.RuntimeEnvironment)
{
case IcdEnvironment.eRuntimeEnvironment.SimplSharp:
case IcdEnvironment.eRuntimeEnvironment.SimplSharpPro:
case IcdEnvironment.eRuntimeEnvironment.Standard:
return string.Format("Program{0:D2}Config", ProgramUtils.ProgramNumber);
string directoryName = string.Format("Program{0:D2}Config", ProgramUtils.ProgramNumber);
return Join(RootConfigPath, directoryName);
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();
}
}
}
@@ -73,7 +119,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.
@@ -87,6 +136,68 @@ 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);
}
}
/// <summary>
/// Returns the absolute path to the control system web server directory.
/// </summary>
/// <value></value>
[PublicAPI]
public static string WebServerPath
{
get
{
switch (IcdEnvironment.RuntimeEnvironment)
{
case IcdEnvironment.eRuntimeEnvironment.SimplSharp:
case IcdEnvironment.eRuntimeEnvironment.SimplSharpPro:
return Join(RootPath, "HTML");
case IcdEnvironment.eRuntimeEnvironment.SimplSharpProMono:
return Join(RootPath, "Html");
case IcdEnvironment.eRuntimeEnvironment.Standard:
#if LINUX
return Join(RootPath, "var", "www", "html");
#else
return "C:\\INetPub";
#endif
default:
throw new ArgumentOutOfRangeException();
}
}
}
#endregion
#region Methods
@@ -98,6 +209,9 @@ namespace ICD.Common.Utils
/// <returns></returns>
public static string Join(params string[] items)
{
if (items == null)
throw new ArgumentNullException("items");
return items.Length > 1
? items.Skip(1).Aggregate(items.First(), IcdPath.Combine)
: items.FirstOrDefault(string.Empty);
@@ -163,6 +277,9 @@ namespace ICD.Common.Utils
[PublicAPI]
public static string GetDefaultConfigPath(params string[] localPath)
{
if (localPath == null)
throw new ArgumentNullException("localPath");
string local = Join(localPath);
// Program slot configuration
@@ -184,6 +301,9 @@ namespace ICD.Common.Utils
/// <returns></returns>
public static string GetCommonConfigPath(params string[] localPath)
{
if (localPath == null)
throw new ArgumentNullException("localPath");
string local = Join(localPath);
return Join(CommonConfigPath, local);
}
@@ -194,10 +314,83 @@ namespace ICD.Common.Utils
/// <returns></returns>
public static string GetProgramConfigPath(params string[] localPath)
{
if (localPath == null)
throw new ArgumentNullException("localPath");
string local = Join(localPath);
return Join(ProgramConfigPath, local);
}
/// <summary>
/// Appends the local path to the program data path.
/// </summary>
/// <returns></returns>
public static string GetProgramDataPath(params string[] localPath)
{
if (localPath == null)
throw new ArgumentNullException("localPath");
string local = Join(localPath);
return Join(ProgramDataPath, local);
}
/// <summary>
/// Appends the local path to the room data path.
/// </summary>
/// <returns></returns>
public static string GetRoomDataPath(int roomId, params string[] localPath)
{
if (localPath == null)
throw new ArgumentNullException("localPath");
string local = Join(localPath);
string roomDataDirectory = GetRoomDataDirectory(roomId);
return Join(ProgramDataPath, roomDataDirectory, local);
}
/// <summary>
/// Gets the directory name of the room data directory for the room with the given id.
/// </summary>
/// <param name="roomId"></param>
/// <returns></returns>
public static string GetRoomDataDirectory(int roomId)
{
return string.Format("Room{0}Data", roomId);
}
/// <summary>
/// Appends the local path to the web server path.
/// </summary>
/// <param name="localPath"></param>
/// <returns></returns>
public static string GetWebServerPath(params string[] localPath)
{
if (localPath == null)
throw new ArgumentNullException("localPath");
string local = Join(localPath);
return Join(WebServerPath, local);
}
/// <summary>
/// Gets the URL to the resource at the given web server path.
/// </summary>
/// <param name="webServerPath"></param>
/// <returns></returns>
public static string GetUrl(string webServerPath)
{
if (webServerPath == null)
throw new ArgumentNullException("webServerPath");
if (!webServerPath.StartsWith(WebServerPath))
throw new ArgumentException("Path is not in the web server directory");
string local = webServerPath.Substring(WebServerPath.Length + 1)
.Replace('\\', '/');
return string.Format("{0}/{1}", IcdEnvironment.NetworkAddresses.First(), local);
}
/// <summary>
/// Returns true if the given path exists.
/// </summary>

View File

@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Text;
using ICD.Common.Properties;
using ICD.Common.Properties;
using ICD.Common.Utils.Json;
namespace ICD.Common.Utils
{
@@ -13,72 +11,16 @@ namespace ICD.Common.Utils
#region Methods
[PublicAPI]
public static void PrintLine<TKey, TValue>(IDictionary<TKey, TValue> dictionary)
public static void PrintLine([CanBeNull] object value)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
IcdConsole.PrintLine(ToString(dictionary));
string serial = ToString(value);
IcdConsole.PrintLine(serial);
}
[PublicAPI]
public static void PrintLine<T>(IEnumerable<T> sequence)
public static string ToString([CanBeNull] object value)
{
if (sequence == null)
throw new ArgumentNullException("sequence");
IcdConsole.PrintLine(ToString(sequence));
}
[PublicAPI]
public static string ToString<TKey, TValue>(IDictionary<TKey, TValue> dictionary)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
StringBuilder builder = new StringBuilder();
builder.AppendLine("{");
foreach (KeyValuePair<TKey, TValue> kvp in dictionary)
{
builder.Append('\t');
builder.Append(ToString(kvp.Key));
builder.Append(" : ");
builder.Append(ToString(kvp.Value));
builder.Append(',');
builder.AppendLine();
}
builder.Append("}");
return builder.ToString();
}
[PublicAPI]
public static string ToString<T>(IEnumerable<T> sequence)
{
if (sequence == null)
throw new ArgumentNullException("sequence");
StringBuilder builder = new StringBuilder();
builder.AppendLine("[");
foreach (T item in sequence)
{
builder.Append('\t');
builder.Append(ToString(item));
builder.Append(',');
builder.AppendLine();
}
builder.Append("]");
return builder.ToString();
}
[PublicAPI]
public static string ToString<T>(T value)
{
// ReSharper disable once CompareNonConstrainedGenericWithNull
return StringUtils.ToRepresentation(value == null ? null : value.ToString());
return JsonUtils.Format(value);
}
#endregion

View File

@@ -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_SystemUptimeStartTimeUtc;
private static DateTime? s_ProgramUptimeStartTimeUtc;
#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_SystemUptimeStartTimeUtc == 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_SystemUptimeStartTimeUtc = IcdEnvironment.GetUtcTime() - span;
}
return IcdEnvironment.GetUtcTime() - s_SystemUptimeStartTimeUtc.Value;
}
/// <summary>
/// Gets the uptime of the current program.
/// </summary>
/// <returns></returns>
[PublicAPI]
public static TimeSpan GetProgramUptime()
{
if (s_ProgramUptimeStartTimeUtc == 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_ProgramUptimeStartTimeUtc = IcdEnvironment.GetUtcTime() - span;
}
return IcdEnvironment.GetUtcTime() - s_ProgramUptimeStartTimeUtc.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;
}
}
}

View File

@@ -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
}
}

View File

@@ -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>

View File

@@ -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

View File

@@ -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 2019")]
[assembly: AssemblyVersion("8.3.1.0")]
[assembly: AssemblyCopyright("Copyright © ICD Systems 2020")]
[assembly: AssemblyVersion("11.0.0.0")]

View File

@@ -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))

View File

@@ -4,6 +4,7 @@ using System.Linq;
using ICD.Common.Properties;
using ICD.Common.Utils.Extensions;
using ICD.Common.Utils.IO;
using MethodInfoExtensions = ICD.Common.Utils.Extensions.MethodInfoExtensions;
#if SIMPLSHARP
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharp.Reflection;
@@ -50,13 +51,7 @@ namespace ICD.Common.Utils
if (parameters == null)
throw new ArgumentNullException("parameters");
#if SIMPLSHARP
IEnumerable<CType>
#else
IEnumerable<Type>
#endif
parameterTypes = method.GetParameters().Select(p => p.ParameterType);
IEnumerable<Type> parameterTypes = method.GetParameters().Select(p => (Type)p.ParameterType);
return ParametersMatchTypes(parameterTypes, parameters);
}
@@ -80,13 +75,7 @@ namespace ICD.Common.Utils
/// <param name="types"></param>
/// <param name="parameters"></param>
/// <returns></returns>
private static bool ParametersMatchTypes(
#if SIMPLSHARP
IEnumerable<CType>
#else
IEnumerable<Type>
#endif
types, IEnumerable<object> parameters)
private static bool ParametersMatchTypes(IEnumerable<Type> types, IEnumerable<object> parameters)
{
if (types == null)
throw new ArgumentNullException("types");
@@ -94,27 +83,11 @@ namespace ICD.Common.Utils
if (parameters == null)
throw new ArgumentNullException("parameters");
return types
#if SIMPLSHARP
IList<CType>
#else
IList<Type>
.Cast<object>()
#endif
typesArray = types as
#if SIMPLSHARP
IList<CType>
#else
IList<Type>
#endif
?? types.ToArray();
IList<object> parametersArray = parameters as IList<object> ?? parameters.ToArray();
if (parametersArray.Count != typesArray.Count)
return false;
// Compares each pair of items in the two arrays.
return !parametersArray.Where((t, index) => !ParameterMatchesType(typesArray[index], t))
.Any();
.SequenceEqual(parameters, (a, b) => ParameterMatchesType((Type)a, b));
}
/// <summary>
@@ -147,6 +120,7 @@ namespace ICD.Common.Utils
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
[CanBeNull]
public static object GetDefaultValue(Type type)
{
if (type == null)
@@ -162,7 +136,7 @@ namespace ICD.Common.Utils
}
/// <summary>
/// Platform independant delegate instantiation.
/// Platform independent delegate instantiation.
/// </summary>
/// <param name="type"></param>
/// <param name="firstArgument"></param>
@@ -219,11 +193,12 @@ 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)
@@ -311,6 +286,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)
@@ -337,8 +313,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);
@@ -352,12 +329,60 @@ 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 = MethodInfoExtensions.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 = MethodInfoExtensions.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)

View File

@@ -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(", ");

View 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;
}
}
}

View File

@@ -13,9 +13,10 @@ namespace ICD.Common.Utils
if (callback == null)
throw new ArgumentNullException("callback");
Enter();
try
{
Enter();
callback();
}
finally
@@ -35,9 +36,10 @@ namespace ICD.Common.Utils
if (callback == null)
throw new ArgumentNullException("callback");
Enter();
try
{
Enter();
return callback();
}
finally

View File

@@ -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>
@@ -49,31 +43,13 @@ namespace ICD.Common.Utils.Services.Logging
{
m_Severity = severity;
m_Message = message;
m_Timestamp = IcdEnvironment.GetLocalTime().ToUniversalTime();
m_Timestamp = IcdEnvironment.GetUtcTime();
}
#endregion
#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>

View File

@@ -7,17 +7,17 @@ namespace ICD.Common.Utils.Services.Scheduler
{
public event EventHandler OnScheduledRunTimeChanged;
private DateTime? m_NextRunTime;
private DateTime? m_NextRunTimeUtc;
public DateTime? NextRunTime
public DateTime? NextRunTimeUtc
{
get { return m_NextRunTime; }
get { return m_NextRunTimeUtc; }
private set
{
if (m_NextRunTime == value)
if (m_NextRunTimeUtc == value)
return;
m_NextRunTime = value;
m_NextRunTimeUtc = value;
OnScheduledRunTimeChanged.Raise(this);
}
@@ -26,12 +26,12 @@ namespace ICD.Common.Utils.Services.Scheduler
public void Run()
{
RunFinal();
NextRunTime = GetNextRunTime();
NextRunTimeUtc = GetNextRunTimeUtc();
}
public void UpdateNextRunTime()
{
NextRunTime = GetNextRunTime();
NextRunTimeUtc = GetNextRunTimeUtc();
}
/// <summary>
@@ -42,6 +42,6 @@ namespace ICD.Common.Utils.Services.Scheduler
/// <summary>
/// Runs after RunFinal in order to set the next run time of this action
/// </summary>
public abstract DateTime? GetNextRunTime();
public abstract DateTime? GetNextRunTimeUtc();
}
}

View File

@@ -39,7 +39,7 @@ namespace ICD.Common.Utils.Services.Scheduler
try
{
Subscribe(action);
m_Actions.AddSorted(action, a => a.NextRunTime);
m_Actions.InsertSorted(action, a => a.NextRunTimeUtc);
}
finally
{
@@ -96,15 +96,15 @@ namespace ICD.Common.Utils.Services.Scheduler
private void TimerCallback()
{
DateTime currentTime = IcdEnvironment.GetLocalTime();
DateTime currentTime = IcdEnvironment.GetUtcTime();
IScheduledAction[] actionsToRun;
m_CriticalSection.Enter();
try
{
actionsToRun = m_Actions
.Where(a => a.NextRunTime <= currentTime && a.NextRunTime > m_LastRunTime)
.OrderBy(a => a.NextRunTime)
.Where(a => a.NextRunTimeUtc <= currentTime && a.NextRunTimeUtc > m_LastRunTime)
.OrderBy(a => a.NextRunTimeUtc)
.ToArray();
}
finally
@@ -135,14 +135,14 @@ namespace ICD.Common.Utils.Services.Scheduler
m_CriticalSection.Enter();
try
{
var action = m_Actions.FirstOrDefault(a => a.NextRunTime != null && a.NextRunTime > m_LastRunTime);
if (action == null || action.NextRunTime == null)
var action = m_Actions.FirstOrDefault(a => a.NextRunTimeUtc != null && a.NextRunTimeUtc > m_LastRunTime);
if (action == null || action.NextRunTimeUtc == null)
{
m_Timer.Stop();
return;
}
long msToNextAction = (long)(action.NextRunTime.Value - IcdEnvironment.GetLocalTime()).TotalMilliseconds;
long msToNextAction = (long)(action.NextRunTimeUtc.Value - IcdEnvironment.GetUtcTime()).TotalMilliseconds;
if (msToNextAction < 0)
msToNextAction = 0;
m_Timer.Reset(msToNextAction);
@@ -195,7 +195,7 @@ namespace ICD.Common.Utils.Services.Scheduler
try
{
m_Actions.Remove(action);
m_Actions.AddSorted(action, a => a.NextRunTime);
m_Actions.InsertSorted(action, a => a.NextRunTimeUtc);
}
finally
{

View File

@@ -12,7 +12,7 @@ namespace ICD.Common.Utils.Services.Scheduler
/// <summary>
/// Gets the next time this action should be run
/// </summary>
DateTime? NextRunTime { get; }
DateTime? NextRunTimeUtc { get; }
void Run();
}

View File

@@ -32,8 +32,11 @@ namespace ICD.Common.Utils.Sqlite
/// <param name="path"></param>
public static void CreateFile(string path)
{
IcdFileStream fs = IcdFile.Create(path);
fs.Close();
string directory = IcdPath.GetDirectoryName(path);
IcdDirectory.CreateDirectory(directory);
using (IcdFileStream fs = IcdFile.Create(path))
fs.Close();
}
/// <summary>

View File

@@ -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();
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -12,12 +12,30 @@ namespace ICD.Common.Utils
/// </summary>
public sealed class TableBuilder
{
#if SIMPLSHARP
private const char HORIZONTAL = '-';
private const char VERTICAL = '|';
private const char INTERSECT = '+';
#else
private const char INTERSECT = '\u253C';
private const char HORIZONTAL = '\u2500';
private const char VERTICAL = '\u2502';
private const char HORIZONTAL_DOWN = '\u252C';
private const char HORIZONTAL_UP = '\u2534';
private const char VERTICAL_RIGHT = '\u251C';
private const char VERTICAL_LEFT = '\u2524';
private const char DOWN_RIGHT = '\u250C';
private const char DOWN_LEFT = '\u2510';
private const char UP_RIGHT = '\u2514';
private const char UP_LEFT = '\u2518';
#endif
private readonly List<string[]> m_Rows;
private readonly SafeCriticalSection m_RowsSection;
private readonly string[] m_Columns;
/// <summary>
@@ -39,7 +57,6 @@ namespace ICD.Common.Utils
public TableBuilder(params string[] columns)
{
m_Rows = new List<string[]>();
m_RowsSection = new SafeCriticalSection();
m_Columns = columns;
}
@@ -49,9 +66,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 +77,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 +89,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 +123,8 @@ namespace ICD.Common.Utils
AddSeparator();
AddRow(row);
AddSeparator();
return this;
}
/// <summary>
@@ -112,30 +134,23 @@ namespace ICD.Common.Utils
{
StringBuilder sb = new StringBuilder();
m_RowsSection.Enter();
int[] columnWidths = GetColumnWidths();
try
AppendTopSeparator(sb, columnWidths);
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);
}
AppendBottomSeparator(sb, columnWidths);
return sb.ToString();
}
@@ -154,35 +169,24 @@ namespace ICD.Common.Utils
private int GetColumnWidth(int index)
{
int titleLength = m_Columns[index].Length + 1;
int titleLength = m_Columns[index].GetPrintableLength() + 1;
if (m_Rows.Count == 0)
return titleLength;
int maxColumnWidth = m_Rows.Except((string[])null)
.Max(x => x[index] != null ? x[index].Length : 0) + 1;
.Max(x => x[index] != null ? x[index].GetPrintableLength() : 0) + 1;
return (titleLength > maxColumnWidth) ? titleLength : maxColumnWidth;
return titleLength > maxColumnWidth ? titleLength : maxColumnWidth;
}
private static void AppendRow(StringBuilder builder, IList<string> row, IList<int> columnWidths)
private void AppendTopSeparator(StringBuilder builder, IList<int> columnWidths)
{
for (int index = 0; index < row.Count; index++)
{
if (index > 0)
builder.Append(' ');
#if SIMPLSHARP
// Can't do fancy tables so don't bother drawing the top row
return;
#else
builder.Append(DOWN_RIGHT).Append(HORIZONTAL);
string value = row[index] ?? string.Empty;
builder.Append(value.PadRight(columnWidths[index]));
if (index < row.Count - 1)
builder.Append(VERTICAL);
}
builder.AppendLine();
}
private static void AppendSeparator(StringBuilder sb, IList<int> columnWidths)
{
for (int index = 0; index < columnWidths.Count; index++)
{
int length = columnWidths[index];
@@ -191,14 +195,95 @@ namespace ICD.Common.Utils
if (index > 0)
length++;
sb.Append(new string(HORIZONTAL, length));
builder.Append(new string(HORIZONTAL, length));
if (index < columnWidths.Count - 1)
sb.Append(INTERSECT);
builder.Append(HORIZONTAL_DOWN);
}
sb.AppendLine();
builder.Append(DOWN_LEFT);
builder.AppendLine();
#endif
}
#endregion
private void AppendBottomSeparator(StringBuilder builder, IList<int> columnWidths)
{
#if SIMPLSHARP
AppendSeparator(builder, columnWidths);
return;
#else
builder.Append(UP_RIGHT).Append(HORIZONTAL);
for (int index = 0; index < columnWidths.Count; index++)
{
int length = columnWidths[index];
// Subsequent columns have padding
if (index > 0)
length++;
builder.Append(new string(HORIZONTAL, length));
if (index < columnWidths.Count - 1)
builder.Append(HORIZONTAL_UP);
}
builder.Append(UP_LEFT);
builder.AppendLine();
#endif
}
private static void AppendRow(StringBuilder builder, IList<string> row, IList<int> columnWidths)
{
#if !SIMPLSHARP
builder.Append(VERTICAL).Append(' ');
#endif
for (int index = 0; index < row.Count; index++)
{
if (index > 0)
builder.Append(' ');
string value = row[index] ?? string.Empty;
builder.Append(value.PadRightPrintable(columnWidths[index]));
if (index < row.Count - 1)
builder.Append(VERTICAL);
}
#if !SIMPLSHARP
builder.Append(VERTICAL);
#endif
builder.AppendLine();
}
private static void AppendSeparator(StringBuilder builder, IList<int> columnWidths)
{
#if !SIMPLSHARP
builder.Append(VERTICAL_RIGHT).Append(HORIZONTAL);
#endif
for (int index = 0; index < columnWidths.Count; index++)
{
int length = columnWidths[index];
// Subsequent columns have padding
if (index > 0)
length++;
builder.Append(new string(HORIZONTAL, length));
if (index < columnWidths.Count - 1)
builder.Append(INTERSECT);
}
#if !SIMPLSHARP
builder.Append(VERTICAL_LEFT);
#endif
builder.AppendLine();
}
#endregion
}
}

Some files were not shown because too many files have changed in this diff Show More