├── .editorconfig
├── .gitattributes
├── .github
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE
│ ├── ask-question.md
│ ├── bug-report.md
│ └── feature-request.md
└── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── .gitmodules
├── LICENSE
├── README.md
├── SixLabors.Core.sln
├── SixLabors.Core.sln.DotSettings
├── appveyor.yml
├── build.cmd
├── build.ps1
├── codecov.yml
├── gitversion.yml
├── src
└── SixLabors.Core
│ ├── Constants.cs
│ ├── GeometryUtilities.cs
│ ├── Memory
│ ├── AllocationOptions.cs
│ ├── ArrayPoolMemoryAllocator.Buffer{T}.cs
│ ├── ArrayPoolMemoryAllocator.CommonFactoryMethods.cs
│ ├── ArrayPoolMemoryAllocator.cs
│ ├── IManagedByteBuffer.cs
│ ├── Internals
│ │ ├── BasicArrayBuffer.cs
│ │ ├── BasicByteBuffer.cs
│ │ └── ManagedBufferBase.cs
│ ├── MemoryAllocator.cs
│ └── SimpleGcMemoryAllocator.cs
│ ├── Primitives
│ ├── Matrix3x2Extensions.cs
│ ├── Point.cs
│ ├── PointF.cs
│ ├── Rectangle.cs
│ ├── RectangleF.cs
│ ├── Size.cs
│ └── SizeF.cs
│ ├── Properties
│ └── AssemblyInfo.cs
│ ├── SixLabors.Core.csproj
│ └── SixLabors.Core.csproj.DotSettings
└── tests
├── CodeCoverage
├── .gitignore
├── CodeCoverage.cmd
└── packages.config
├── SixLabors.Core.Tests
├── Helpers
│ ├── DebugGuardTests.cs
│ ├── FloatRoundingComparer.cs
│ ├── GeometryUtilitiesTests.cs
│ ├── GuardTests.cs
│ └── MathFTests.cs
├── Memory
│ ├── ArrayPoolMemoryAllocatorTests.cs
│ ├── BufferExtensions.cs
│ ├── BufferTestSuite.cs
│ └── SimpleGcMemoryAllocatorTests.cs
├── Primitives
│ ├── PointFTests.cs
│ ├── PointTests.cs
│ ├── RectangleFTests.cs
│ ├── RectangleTests.cs
│ ├── SizeFTests.cs
│ └── SizeTests.cs
├── SixLabors.Core.Tests.csproj
└── TestEnvironment.cs
└── SixLabors.ruleset
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to:
3 | # treat as text and
4 | # normalize to Unix-style line endings
5 | ###############################################################################
6 | * text eol=lf
7 |
8 | ###############################################################################
9 | # Set explicit file behavior to:
10 | # treat as text and
11 | # normalize to Unix-style line endings
12 | ###############################################################################
13 | *.asm text eol=lf
14 | *.c text eol=lf
15 | *.clj text eol=lf
16 | *.cmd text eol=lf
17 | *.cpp text eol=lf
18 | *.css text eol=lf
19 | *.cxx text eol=lf
20 | *.config text eol=lf
21 | *.DotSettings text eol=lf
22 | *.erl text eol=lf
23 | *.fs text eol=lf
24 | *.fsx text eol=lf
25 | *.h text eol=lf
26 | *.htm text eol=lf
27 | *.html text eol=lf
28 | *.hs text eol=lf
29 | *.hxx text eol=lf
30 | *.java text eol=lf
31 | *.js text eol=lf
32 | *.json text eol=lf
33 | *.less text eol=lf
34 | *.lisp text eol=lf
35 | *.lua text eol=lf
36 | *.m text eol=lf
37 | *.md text eol=lf
38 | *.php text eol=lf
39 | *.props text eol=lf
40 | *.ps1 text eol=lf
41 | *.py text eol=lf
42 | *.rb text eol=lf
43 | *.resx text eol=lf
44 | *.runsettings text eol=lf
45 | *.ruleset text eol=lf
46 | *.sass text eol=lf
47 | *.scss text eol=lf
48 | *.sh text eol=lf
49 | *.sql text eol=lf
50 | *.svg text eol=lf
51 | *.targets text eol=lf
52 | *.tt text eol=crlf
53 | *.ttinclude text eol=crlf
54 | *.txt text eol=lf
55 | *.vb text eol=lf
56 | *.yml text eol=lf
57 |
58 | ###############################################################################
59 | # Set explicit file behavior to:
60 | # treat as text
61 | # normalize to Unix-style line endings and
62 | # diff as csharp
63 | ###############################################################################
64 | *.cs text eol=lf diff=csharp
65 |
66 | ###############################################################################
67 | # Set explicit file behavior to:
68 | # treat as text
69 | # normalize to Unix-style line endings and
70 | # use a union merge when resoling conflicts
71 | ###############################################################################
72 | *.csproj text eol=lf merge=union
73 | *.dbproj text eol=lf merge=union
74 | *.fsproj text eol=lf merge=union
75 | *.ncrunchproject text eol=lf merge=union
76 | *.vbproj text eol=lf merge=union
77 |
78 | ###############################################################################
79 | # Set explicit file behavior to:
80 | # treat as text
81 | # normalize to Windows-style line endings and
82 | # use a union merge when resoling conflicts
83 | ###############################################################################
84 | *.sln text eol=crlf merge=union
85 |
86 | ###############################################################################
87 | # Set explicit file behavior to:
88 | # treat as binary
89 | ###############################################################################
90 | *.bmp binary
91 | *.dll binary
92 | *.exe binary
93 | *.gif binary
94 | *.jpg binary
95 | *.png binary
96 | *.ttf binary
97 | *.snk binary
98 |
99 | ###############################################################################
100 | # Set explicit file behavior to:
101 | # diff as plain text
102 | ###############################################################################
103 | *.doc diff=astextplain
104 | *.docx diff=astextplain
105 | *.dot diff=astextplain
106 | *.pdf diff=astextplain
107 | *.pptx diff=astextplain
108 | *.rtf diff=astextplain
109 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to contribute to SixLabors.Core
2 |
3 | #### **Did you find a bug?**
4 |
5 | - Please **ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/SixLabors/Core/issues).
6 |
7 | - If you're unable to find an open issue addressing the problem, please [open a new one](https://github.com/SixLabors/Core/issues/new). Be sure to include a **title, the applicable version, a clear description**, as much relevant information as possible, and a **code sample** or an **executable test case** demonstrating the expected behavior that is not occurring. Please do not hijack existing issues.
8 |
9 | #### **Did you write a patch that fixes a bug?**
10 |
11 | * Open a new GitHub pull request with the patch.
12 |
13 | * Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable.
14 |
15 | * Before submitting, please ensure that your code matches the existing coding patterns and practise as demonstrated in the repository. These follow strict Stylecop rules :cop:.
16 |
17 | #### **Do you intend to add a new feature or change an existing one?**
18 |
19 | * Suggest your change in the [ImageSharp Gitter Chat Room](https://gitter.im/ImageSharp/General) and start writing code.
20 |
21 | * Do not open an issue on GitHub until you have collected positive feedback about the change. GitHub issues are primarily intended for bug reports and fixes.
22 |
23 | #### **Running tests and Debugging**
24 |
25 | * Debugging (running tests in Debug mode) is only supported on .NET Core 2.1, because of JIT Code Generation bugs like [dotnet/coreclr#16443](https://github.com/dotnet/coreclr/issues/16443) or [dotnet/coreclr#20657](https://github.com/dotnet/coreclr/issues/20657)
26 |
27 | #### **Do you have questions about consuming the library or the source code?**
28 |
29 | * Ask any question about how to use SixLabors.Core in the [ImageSharp Gitter Chat Room](https://gitter.im/ImageSharp/General).
30 |
31 | And please remember. SixLabors.Core is the work of a very, very, small number of developers who struggle balancing time to contribute to the project with family time and work commitments. We encourage you to pitch in and help make our vision of simple accessible imageprocessing available to all. Open Source can only exist with your help.
32 |
33 | Thanks for reading!
34 |
35 | James Jackson-South :heart:
36 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/ask-question.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Ask question
3 | about: Ask a question about this project.
4 |
5 | ---
6 |
7 | You should not create an issue but use Gitter instead: https://gitter.im/ImageSharp/General
8 |
9 | You should not create an issue but use Gitter instead: https://gitter.im/ImageSharp/General
10 |
11 | You should not create an issue but use Gitter instead: https://gitter.im/ImageSharp/General
12 |
13 | You should not create an issue but use Gitter instead: https://gitter.im/ImageSharp/General
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 |
5 | ---
6 |
7 | ### Prerequisites
8 |
9 | - [ ] I have written a descriptive issue title
10 | - [ ] I have verified that I am running the latest version of ImageSharp
11 | - [ ] I have verified if the problem exist in both `DEBUG` and `RELEASE` mode
12 | - [ ] I have searched [open](https://github.com/SixLabors/Core/issues) and [closed](https://github.com/SixLabors/Core/issues?q=is%3Aissue+is%3Aclosed) issues to ensure it has not already been reported
13 |
14 | ### Description
15 |
16 |
17 | ### Steps to Reproduce
18 |
19 |
20 | ### System Configuration
21 |
22 |
23 | - SixLabors.Core version:
24 | - Other SixLabors packages and versions:
25 | - Environment (Operating system, version and so on):
26 | - .NET Framework version:
27 | - Additional information:
28 |
29 |
30 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 |
5 | ---
6 |
7 | You should first discuss the feature on Gitter: https://gitter.im/ImageSharp/General
8 |
9 | You should first discuss the feature on Gitter: https://gitter.im/ImageSharp/General
10 |
11 | You should first discuss the feature on Gitter: https://gitter.im/ImageSharp/General
12 |
13 | You should first discuss the feature on Gitter: https://gitter.im/ImageSharp/General
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### Prerequisites
2 |
3 | - [ ] I have written a descriptive pull-request title
4 | - [ ] I have verified that there are no overlapping [pull-requests](https://github.com/SixLabors/Core/pulls) open
5 | - [ ] I have verified that I am following matches the existing coding patterns and practice as demonstrated in the repository. These follow strict Stylecop rules :cop:.
6 | - [ ] I have provided test coverage for my change (where applicable)
7 |
8 | ### Description
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # .NET Core
46 | project.lock.json
47 | project.fragment.lock.json
48 | artifacts/
49 | **/Properties/launchSettings.json
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # Visual Studio code coverage results
117 | *.coverage
118 | *.coveragexml
119 |
120 | # NCrunch
121 | _NCrunch_*
122 | .*crunch*.local.xml
123 | nCrunchTemp_*
124 |
125 | # MightyMoose
126 | *.mm.*
127 | AutoTest.Net/
128 |
129 | # Web workbench (sass)
130 | .sass-cache/
131 |
132 | # Installshield output folder
133 | [Ee]xpress/
134 |
135 | # DocProject is a documentation generator add-in
136 | DocProject/buildhelp/
137 | DocProject/Help/*.HxT
138 | DocProject/Help/*.HxC
139 | DocProject/Help/*.hhc
140 | DocProject/Help/*.hhk
141 | DocProject/Help/*.hhp
142 | DocProject/Help/Html2
143 | DocProject/Help/html
144 |
145 | # Click-Once directory
146 | publish/
147 |
148 | # Publish Web Output
149 | *.[Pp]ublish.xml
150 | *.azurePubxml
151 | # TODO: Comment the next line if you want to checkin your web deploy settings
152 | # but database connection strings (with potential passwords) will be unencrypted
153 | *.pubxml
154 | *.publishproj
155 |
156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
157 | # checkin your Azure Web App publish settings, but sensitive information contained
158 | # in these scripts will be unencrypted
159 | PublishScripts/
160 |
161 | # NuGet Packages
162 | *.nupkg
163 | # The packages folder can be ignored because of Package Restore
164 | **/packages/*
165 | # except build/, which is used as an MSBuild target.
166 | !**/packages/build/
167 | # Uncomment if necessary however generally it will be regenerated when needed
168 | #!**/packages/repositories.config
169 | # NuGet v3's project.json files produces more ignorable files
170 | *.nuget.props
171 | *.nuget.targets
172 |
173 | # Microsoft Azure Build Output
174 | csx/
175 | *.build.csdef
176 |
177 | # Microsoft Azure Emulator
178 | ecf/
179 | rcf/
180 |
181 | # Windows Store app package directories and files
182 | AppPackages/
183 | BundleArtifacts/
184 | Package.StoreAssociation.xml
185 | _pkginfo.txt
186 |
187 | # Visual Studio cache files
188 | # files ending in .cache can be ignored
189 | *.[Cc]ache
190 | # but keep track of directories ending in .cache
191 | !*.[Cc]ache/
192 |
193 | # Others
194 | ClientBin/
195 | ~$*
196 | *~
197 | *.dbmdl
198 | *.dbproj.schemaview
199 | *.jfm
200 | *.pfx
201 | *.publishsettings
202 | orleans.codegen.cs
203 |
204 | # Since there are multiple workflows, uncomment next line to ignore bower_components
205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
206 | #bower_components/
207 |
208 | # RIA/Silverlight projects
209 | Generated_Code/
210 |
211 | # Backup & report files from converting an old project file
212 | # to a newer Visual Studio version. Backup files are not needed,
213 | # because we have git ;-)
214 | _UpgradeReport_Files/
215 | Backup*/
216 | UpgradeLog*.XML
217 | UpgradeLog*.htm
218 |
219 | # SQL Server files
220 | *.mdf
221 | *.ldf
222 | *.ndf
223 |
224 | # Business Intelligence projects
225 | *.rdl.data
226 | *.bim.layout
227 | *.bim_*.settings
228 |
229 | # Microsoft Fakes
230 | FakesAssemblies/
231 |
232 | # GhostDoc plugin setting file
233 | *.GhostDoc.xml
234 |
235 | # Node.js Tools for Visual Studio
236 | .ntvs_analysis.dat
237 | node_modules/
238 |
239 | # Typescript v1 declaration files
240 | typings/
241 |
242 | # Visual Studio 6 build log
243 | *.plg
244 |
245 | # Visual Studio 6 workspace options file
246 | *.opt
247 |
248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
249 | *.vbw
250 |
251 | # Visual Studio LightSwitch build output
252 | **/*.HTMLClient/GeneratedArtifacts
253 | **/*.DesktopClient/GeneratedArtifacts
254 | **/*.DesktopClient/ModelManifest.xml
255 | **/*.Server/GeneratedArtifacts
256 | **/*.Server/ModelManifest.xml
257 | _Pvt_Extensions
258 |
259 | # Paket dependency manager
260 | .paket/paket.exe
261 | paket-files/
262 |
263 | # FAKE - F# Make
264 | .fake/
265 |
266 | # JetBrains Rider
267 | .idea/
268 | *.sln.iml
269 |
270 | # CodeRush
271 | .cr/
272 |
273 | # Python Tools for Visual Studio (PTVS)
274 | __pycache__/
275 | *.pyc
276 |
277 | # Cake - Uncomment if you are using it
278 | # tools/**
279 | # !tools/packages.config
280 |
281 | # Telerik's JustMock configuration file
282 | *.jmconfig
283 |
284 | # BizTalk build output
285 | *.btp.cs
286 | *.btm.cs
287 | *.odx.cs
288 | *.xsd.cs
289 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "shared-infrastructure"]
2 | path = shared-infrastructure
3 | url = https://github.com/SixLabors/SharedInfrastructure.git
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | The contents of this repository have been integrated into https://github.com/SixLabors/ImageSharp
2 |
--------------------------------------------------------------------------------
/SixLabors.Core.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.28803.352
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{C317F1B1-D75E-4C6D-83EB-80367343E0D7}"
7 | ProjectSection(SolutionItems) = preProject
8 | appveyor.yml = appveyor.yml
9 | .github\ISSUE_TEMPLATE\ask-question.md = .github\ISSUE_TEMPLATE\ask-question.md
10 | .github\ISSUE_TEMPLATE\bug-report.md = .github\ISSUE_TEMPLATE\bug-report.md
11 | build.cmd = build.cmd
12 | codecov.yml = codecov.yml
13 | .github\CONTRIBUTING.md = .github\CONTRIBUTING.md
14 | .github\ISSUE_TEMPLATE\feature-request.md = .github\ISSUE_TEMPLATE\feature-request.md
15 | gitversion.yml = gitversion.yml
16 | .github\PULL_REQUEST_TEMPLATE.md = .github\PULL_REQUEST_TEMPLATE.md
17 | README.md = README.md
18 | shared-infrastructure\.editorconfig = shared-infrastructure\.editorconfig
19 | EndProjectSection
20 | EndProject
21 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{815C0625-CD3D-440F-9F80-2D83856AB7AE}"
22 | EndProject
23 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{56801022-D71A-4FBE-BC5B-CBA08E2284EC}"
24 | EndProject
25 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SixLabors.Core", "src\SixLabors.Core\SixLabors.Core.csproj", "{09E744EC-4852-4FC7-BE78-C1B399F17967}"
26 | EndProject
27 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SixLabors.Core.Tests", "tests\SixLabors.Core.Tests\SixLabors.Core.Tests.csproj", "{F836E8E6-B4D9-4208-8346-140C74678B91}"
28 | EndProject
29 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CodeCoverage", "CodeCoverage", "{10A74B46-930F-49E3-A579-BC3A6A23321D}"
30 | ProjectSection(SolutionItems) = preProject
31 | tests\CodeCoverage\CodeCoverage.cmd = tests\CodeCoverage\CodeCoverage.cmd
32 | EndProjectSection
33 | EndProject
34 | Global
35 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
36 | Debug|Any CPU = Debug|Any CPU
37 | Release|Any CPU = Release|Any CPU
38 | EndGlobalSection
39 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
40 | {09E744EC-4852-4FC7-BE78-C1B399F17967}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
41 | {09E744EC-4852-4FC7-BE78-C1B399F17967}.Debug|Any CPU.Build.0 = Debug|Any CPU
42 | {09E744EC-4852-4FC7-BE78-C1B399F17967}.Release|Any CPU.ActiveCfg = Release|Any CPU
43 | {09E744EC-4852-4FC7-BE78-C1B399F17967}.Release|Any CPU.Build.0 = Release|Any CPU
44 | {F836E8E6-B4D9-4208-8346-140C74678B91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
45 | {F836E8E6-B4D9-4208-8346-140C74678B91}.Debug|Any CPU.Build.0 = Debug|Any CPU
46 | {F836E8E6-B4D9-4208-8346-140C74678B91}.Release|Any CPU.ActiveCfg = Release|Any CPU
47 | {F836E8E6-B4D9-4208-8346-140C74678B91}.Release|Any CPU.Build.0 = Release|Any CPU
48 | EndGlobalSection
49 | GlobalSection(SolutionProperties) = preSolution
50 | HideSolutionNode = FALSE
51 | EndGlobalSection
52 | GlobalSection(NestedProjects) = preSolution
53 | {09E744EC-4852-4FC7-BE78-C1B399F17967} = {815C0625-CD3D-440F-9F80-2D83856AB7AE}
54 | {F836E8E6-B4D9-4208-8346-140C74678B91} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC}
55 | {10A74B46-930F-49E3-A579-BC3A6A23321D} = {C317F1B1-D75E-4C6D-83EB-80367343E0D7}
56 | EndGlobalSection
57 | GlobalSection(ExtensibilityGlobals) = postSolution
58 | SolutionGuid = {0DED1AC8-37DA-4EC2-8CAE-40E31CD439DE}
59 | EndGlobalSection
60 | GlobalSection(Performance) = preSolution
61 | HasPerformanceSessions = true
62 | EndGlobalSection
63 | EndGlobal
64 |
--------------------------------------------------------------------------------
/SixLabors.Core.sln.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | DO_NOT_SHOW
3 | DO_NOT_SHOW
4 | DO_NOT_SHOW
5 | DO_NOT_SHOW
6 | <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: 0.0.{build}
2 | image: Visual Studio 2017
3 |
4 |
5 | before_build:
6 | - git submodule -q update --init
7 | - cmd: dotnet --version
8 |
9 | build_script:
10 | - cmd: build.cmd
11 | - cmd: tests\CodeCoverage\CodeCoverage.cmd
12 |
13 | after_build:
14 | - cmd: appveyor PushArtifact "artifacts\SixLabors.Core.%APPVEYOR_BUILD_VERSION%.nupkg"
15 |
16 | deploy:
17 | - provider: NuGet
18 | server: https://www.myget.org/F/sixlabors/api/v2/package
19 | symbol_server: https://www.myget.org/F/sixlabors/symbols/api/v2/package
20 | api_key:
21 | secure: V/lEHP0UeMWIpWd0fiNlY2IgbCnJKQlGdRksECdJbOBdaE20Fl0RNL7WyqHe02o4
22 | artifact: /.*\.nupkg/
23 | on:
24 | branch: master
25 |
26 | # prevent the double build when a branch has an active PR
27 | skip_branch_with_pr: true
28 |
29 | test: off
30 |
--------------------------------------------------------------------------------
/build.cmd:
--------------------------------------------------------------------------------
1 | @echo Off
2 |
3 | PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& '.\build.ps1'"
4 |
5 | if not "%errorlevel%"=="0" goto failure
6 |
7 | :success
8 | ECHO successfully built project
9 | REM exit 0
10 | goto end
11 |
12 | :failure
13 | ECHO failed to build.
14 | REM exit -1
15 | goto end
16 |
17 | :end
--------------------------------------------------------------------------------
/build.ps1:
--------------------------------------------------------------------------------
1 |
2 | # lets calulat the correct version here
3 | $fallbackVersion = "1.0.0";
4 | $version = ''
5 |
6 | $tagRegex = '^v?(\d+\.\d+\.\d+)(-([a-zA-Z]+)\.?(\d*))?$'
7 |
8 | # we are running on the build server
9 | $isVersionTag = $env:APPVEYOR_REPO_TAG_NAME -match $tagRegex
10 |
11 | if($isVersionTag){
12 |
13 | Write-Debug "Building commit tagged with a compatable version number"
14 |
15 | $version = $matches[1]
16 | $postTag = $matches[3]
17 | $count = $matches[4]
18 | Write-Debug "version number: ${version} post tag: ${postTag} count: ${count}"
19 | if("$postTag" -ne ""){
20 | $version = "${version}-${postTag}"
21 | }
22 | if("$count" -ne ""){
23 | # for consistancy with previous releases we pad the counter to only 4 places
24 | $padded = $count.Trim().Trim('0').PadLeft(4,"0");
25 | Write-Debug "count '$count', padded '${padded}'"
26 |
27 | $version = "${version}${padded}"
28 | }
29 | }else {
30 |
31 | Write-Debug "Untagged"
32 | $lastTag = (git tag --list --sort=-taggerdate) | Out-String
33 | $list = $lastTag.Split("`n")
34 | foreach ($tag in $list) {
35 |
36 | Write-Debug "testing ${tag}"
37 | $tag = $tag.Trim();
38 | if($tag -match $tagRegex){
39 | Write-Debug "matched ${tag}"
40 | $version = $matches[1];
41 | break;
42 | }
43 | }
44 |
45 | if("$version" -eq ""){
46 | $version = $fallbackVersion
47 | Write-Debug "Failed to discover base version Fallback to '${version}'"
48 | }else{
49 |
50 | Write-Debug "Discovered base version from tags '${version}'"
51 | }
52 |
53 | $buildNumber = $env:APPVEYOR_BUILD_NUMBER
54 |
55 | # build number replacement is padded to 6 places
56 | $buildNumber = "$buildNumber".Trim().Trim('0').PadLeft(6,"0");
57 | if("$env:APPVEYOR_PULL_REQUEST_NUMBER" -ne ""){
58 | Write-Debug "building a PR"
59 |
60 | $prNumber = "$env:APPVEYOR_PULL_REQUEST_NUMBER".Trim().Trim('0').PadLeft(5,"0");
61 | # this is a PR
62 | $version = "${version}-PullRequest${prNumber}${buildNumber}";
63 | }else{
64 | Write-Debug "building a branch commit"
65 |
66 | # this is a general branch commit
67 | $branch = $env:APPVEYOR_REPO_BRANCH
68 |
69 | if("$branch" -eq ""){
70 | $branch = ((git rev-parse --abbrev-ref HEAD) | Out-String).Trim()
71 |
72 | if("$branch" -eq ""){
73 | $branch = "unknown"
74 | }
75 | }
76 |
77 | $branch = $branch.Replace("/","-").ToLower()
78 |
79 | if($branch.ToLower() -eq "master"){
80 | $branch = "dev"
81 | }
82 |
83 | $version = "${version}-${branch}${buildNumber}";
84 | }
85 | }
86 |
87 | if("$env:APPVEYOR_API_URL" -ne ""){
88 | # update appveyor build number for this build
89 | Invoke-RestMethod -Method "PUT" `
90 | -Uri "${env:APPVEYOR_API_URL}api/build" `
91 | -Body "{version:'${version}'}" `
92 | -ContentType "application/json"
93 | }
94 |
95 | Write-Host "Building version '${version}'"
96 | dotnet restore /p:packageversion=$version
97 |
98 | Write-Host "Building projects"
99 | dotnet build -c Release /p:packageversion=$version
100 |
101 | if ($LASTEXITCODE ){ Exit $LASTEXITCODE }
102 |
103 | if ( $env:CI -ne "True") {
104 | dotnet test ./tests/SixLabors.Core.Tests/SixLabors.Core.Tests.csproj --no-build -c Release
105 | }
106 | if ($LASTEXITCODE ){ Exit $LASTEXITCODE }
107 |
108 | Write-Host "Packaging projects"
109 | dotnet pack ./src/SixLabors.Core/ -c Release --output ../../artifacts --no-build /p:packageversion=$version
110 | if ($LASTEXITCODE ){ Exit $LASTEXITCODE }
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | codecov:
2 | branch: develop
3 | notify:
4 | require_ci_to_pass: true
5 | comment: off
6 | coverage:
7 | precision: 2
8 | range:
9 | - 70.0
10 | - 100.0
11 | round: down
12 | status:
13 | changes: false
14 | patch: true
15 | project: true
16 | parsers:
17 | gcov:
18 | branch_detection:
19 | conditional: true
20 | loop: true
21 | macro: false
22 | method: false
--------------------------------------------------------------------------------
/gitversion.yml:
--------------------------------------------------------------------------------
1 | # to create a new package you create a new release/tag
2 | # in github appveyor will build it without the -cixxx tag
3 | # it will then be deployable cleanly to nuget.org
4 |
5 | branches:
6 | master:
7 | tag: ci
8 | mode: ContinuousDeployment
9 | increment: Minor
10 | prevent-increment-of-merged-branch-version: false
11 | track-merge-target: true
12 | pull-request:
13 | regex: (pull|pull\-requests|pr)[/-]
14 | mode: ContinuousDelivery
15 | tag: PullRequest
16 | increment: Inherit
17 | prevent-increment-of-merged-branch-version: false
18 | tag-number-pattern: '[/-](?\d+)[-/]'
19 | track-merge-target: false
20 | tracks-release-branches: false
21 | is-release-branch: false
22 | otherbranches:
23 | regex: '.*'
24 | mode: ContinuousDeployment
25 | tag: ci
26 | increment: Patch
27 | prevent-increment-of-merged-branch-version: false
28 | track-merge-target: true
29 | is-release-branch: false
30 | ignore:
31 | sha: []
--------------------------------------------------------------------------------
/src/SixLabors.Core/Constants.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace SixLabors
5 | {
6 | ///
7 | /// Common constants used throughout the project.
8 | ///
9 | internal static class Constants
10 | {
11 | ///
12 | /// The epsilon for comparing floating point numbers.
13 | ///
14 | public static readonly float Epsilon = 0.001f;
15 | }
16 | }
--------------------------------------------------------------------------------
/src/SixLabors.Core/GeometryUtilities.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Runtime.CompilerServices;
6 |
7 | namespace SixLabors
8 | {
9 | ///
10 | /// Utility class for common geometric functions.
11 | ///
12 | public static class GeometryUtilities
13 | {
14 | ///
15 | /// Converts a degree (360-periodic) angle to a radian (2*Pi-periodic) angle.
16 | ///
17 | /// The angle in degrees.
18 | ///
19 | /// The representing the degree as radians.
20 | ///
21 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
22 | public static float DegreeToRadian(float degree) => degree * (MathF.PI / 180F);
23 |
24 | ///
25 | /// Converts a radian (2*Pi-periodic) angle to a degree (360-periodic) angle.
26 | ///
27 | /// The angle in radians.
28 | ///
29 | /// The representing the degree as radians.
30 | ///
31 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
32 | public static float RadianToDegree(float radian) => radian / (MathF.PI / 180F);
33 | }
34 | }
--------------------------------------------------------------------------------
/src/SixLabors.Core/Memory/AllocationOptions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace SixLabors.Memory
5 | {
6 | ///
7 | /// Options for allocating buffers.
8 | ///
9 | public enum AllocationOptions
10 | {
11 | ///
12 | /// Indicates that the buffer should just be allocated.
13 | ///
14 | None,
15 |
16 | ///
17 | /// Indicates that the allocated buffer should be cleaned following allocation.
18 | ///
19 | Clean
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/SixLabors.Core/Memory/ArrayPoolMemoryAllocator.Buffer{T}.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Buffers;
6 | using System.Runtime.InteropServices;
7 | using SixLabors.Memory.Internals;
8 |
9 | namespace SixLabors.Memory
10 | {
11 | ///
12 | /// Contains and .
13 | ///
14 | public partial class ArrayPoolMemoryAllocator
15 | {
16 | ///
17 | /// The buffer implementation of .
18 | ///
19 | private class Buffer : ManagedBufferBase
20 | where T : struct
21 | {
22 | ///
23 | /// The length of the buffer.
24 | ///
25 | private readonly int length;
26 |
27 | ///
28 | /// A weak reference to the source pool.
29 | ///
30 | ///
31 | /// By using a weak reference here, we are making sure that array pools and their retained arrays are always GC-ed
32 | /// after a call to , regardless of having buffer instances still being in use.
33 | ///
34 | private WeakReference> sourcePoolReference;
35 |
36 | public Buffer(byte[] data, int length, ArrayPool sourcePool)
37 | {
38 | this.Data = data;
39 | this.length = length;
40 | this.sourcePoolReference = new WeakReference>(sourcePool);
41 | }
42 |
43 | ///
44 | /// Gets the buffer as a byte array.
45 | ///
46 | protected byte[] Data { get; private set; }
47 |
48 | ///
49 | public override Span GetSpan() => MemoryMarshal.Cast(this.Data.AsSpan()).Slice(0, this.length);
50 |
51 | ///
52 | protected override void Dispose(bool disposing)
53 | {
54 | if (!disposing || this.Data is null || this.sourcePoolReference is null)
55 | {
56 | return;
57 | }
58 |
59 | if (this.sourcePoolReference.TryGetTarget(out ArrayPool pool))
60 | {
61 | pool.Return(this.Data);
62 | }
63 |
64 | this.sourcePoolReference = null;
65 | this.Data = null;
66 | }
67 |
68 | protected override object GetPinnableObject() => this.Data;
69 | }
70 |
71 | ///
72 | /// The implementation of .
73 | ///
74 | private sealed class ManagedByteBuffer : Buffer, IManagedByteBuffer
75 | {
76 | public ManagedByteBuffer(byte[] data, int length, ArrayPool sourcePool)
77 | : base(data, length, sourcePool)
78 | {
79 | }
80 |
81 | ///
82 | public byte[] Array => this.Data;
83 | }
84 | }
85 | }
--------------------------------------------------------------------------------
/src/SixLabors.Core/Memory/ArrayPoolMemoryAllocator.CommonFactoryMethods.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace SixLabors.Memory
5 | {
6 | ///
7 | /// Contains common factory methods and configuration constants.
8 | ///
9 | public partial class ArrayPoolMemoryAllocator
10 | {
11 | ///
12 | /// The default value for: maximum size of pooled arrays in bytes.
13 | /// Currently set to 24MB, which is equivalent to 8 megapixels of raw RGBA32 data.
14 | ///
15 | internal const int DefaultMaxPooledBufferSizeInBytes = 24 * 1024 * 1024;
16 |
17 | ///
18 | /// The value for: The threshold to pool arrays in which has less buckets for memory safety.
19 | ///
20 | private const int DefaultBufferSelectorThresholdInBytes = 8 * 1024 * 1024;
21 |
22 | ///
23 | /// The default bucket count for .
24 | ///
25 | private const int DefaultLargePoolBucketCount = 6;
26 |
27 | ///
28 | /// The default bucket count for .
29 | ///
30 | private const int DefaultNormalPoolBucketCount = 16;
31 |
32 | ///
33 | /// This is the default. Should be good for most use cases.
34 | ///
35 | /// The memory manager.
36 | public static ArrayPoolMemoryAllocator CreateDefault()
37 | {
38 | return new ArrayPoolMemoryAllocator(
39 | DefaultMaxPooledBufferSizeInBytes,
40 | DefaultBufferSelectorThresholdInBytes,
41 | DefaultLargePoolBucketCount,
42 | DefaultNormalPoolBucketCount);
43 | }
44 |
45 | ///
46 | /// For environments with very limited memory capabilities, only small buffers like image rows are pooled.
47 | ///
48 | /// The memory manager.
49 | public static ArrayPoolMemoryAllocator CreateWithMinimalPooling()
50 | {
51 | return new ArrayPoolMemoryAllocator(64 * 1024, 32 * 1024, 8, 24);
52 | }
53 |
54 | ///
55 | /// For environments with limited memory capabilities, only small array requests are pooled, which can result in reduced throughput.
56 | ///
57 | /// The memory manager.
58 | public static ArrayPoolMemoryAllocator CreateWithModeratePooling()
59 | {
60 | return new ArrayPoolMemoryAllocator(1024 * 1024, 32 * 1024, 16, 24);
61 | }
62 |
63 | ///
64 | /// For environments where memory capabilities are not an issue, the maximum amount of array requests are pooled which results in optimal throughput.
65 | ///
66 | /// The memory manager.
67 | public static ArrayPoolMemoryAllocator CreateWithAggressivePooling()
68 | {
69 | return new ArrayPoolMemoryAllocator(128 * 1024 * 1024, 32 * 1024 * 1024, 16, 32);
70 | }
71 | }
72 | }
--------------------------------------------------------------------------------
/src/SixLabors.Core/Memory/ArrayPoolMemoryAllocator.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Buffers;
6 | using System.Runtime.CompilerServices;
7 |
8 | namespace SixLabors.Memory
9 | {
10 | ///
11 | /// Implements by allocating memory from .
12 | ///
13 | public sealed partial class ArrayPoolMemoryAllocator : MemoryAllocator
14 | {
15 | private readonly int maxArraysPerBucketNormalPool;
16 |
17 | private readonly int maxArraysPerBucketLargePool;
18 |
19 | ///
20 | /// The for small-to-medium buffers which is not kept clean.
21 | ///
22 | private ArrayPool normalArrayPool;
23 |
24 | ///
25 | /// The for huge buffers, which is not kept clean.
26 | ///
27 | private ArrayPool largeArrayPool;
28 |
29 | ///
30 | /// Initializes a new instance of the class.
31 | ///
32 | public ArrayPoolMemoryAllocator()
33 | : this(DefaultMaxPooledBufferSizeInBytes, DefaultBufferSelectorThresholdInBytes)
34 | {
35 | }
36 |
37 | ///
38 | /// Initializes a new instance of the class.
39 | ///
40 | /// The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated.
41 | public ArrayPoolMemoryAllocator(int maxPoolSizeInBytes)
42 | : this(maxPoolSizeInBytes, GetLargeBufferThresholdInBytes(maxPoolSizeInBytes))
43 | {
44 | }
45 |
46 | ///
47 | /// Initializes a new instance of the class.
48 | ///
49 | /// The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated.
50 | /// Arrays over this threshold will be pooled in which has less buckets for memory safety.
51 | public ArrayPoolMemoryAllocator(int maxPoolSizeInBytes, int poolSelectorThresholdInBytes)
52 | : this(maxPoolSizeInBytes, poolSelectorThresholdInBytes, DefaultLargePoolBucketCount, DefaultNormalPoolBucketCount)
53 | {
54 | }
55 |
56 | ///
57 | /// Initializes a new instance of the class.
58 | ///
59 | /// The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated.
60 | /// The threshold to pool arrays in which has less buckets for memory safety.
61 | /// Max arrays per bucket for the large array pool.
62 | /// Max arrays per bucket for the normal array pool.
63 | public ArrayPoolMemoryAllocator(int maxPoolSizeInBytes, int poolSelectorThresholdInBytes, int maxArraysPerBucketLargePool, int maxArraysPerBucketNormalPool)
64 | {
65 | Guard.MustBeGreaterThan(maxPoolSizeInBytes, 0, nameof(maxPoolSizeInBytes));
66 | Guard.MustBeLessThanOrEqualTo(poolSelectorThresholdInBytes, maxPoolSizeInBytes, nameof(poolSelectorThresholdInBytes));
67 |
68 | this.MaxPoolSizeInBytes = maxPoolSizeInBytes;
69 | this.PoolSelectorThresholdInBytes = poolSelectorThresholdInBytes;
70 | this.maxArraysPerBucketLargePool = maxArraysPerBucketLargePool;
71 | this.maxArraysPerBucketNormalPool = maxArraysPerBucketNormalPool;
72 |
73 | this.InitArrayPools();
74 | }
75 |
76 | ///
77 | /// Gets the maximum size of pooled arrays in bytes.
78 | ///
79 | public int MaxPoolSizeInBytes { get; }
80 |
81 | ///
82 | /// Gets the threshold to pool arrays in which has less buckets for memory safety.
83 | ///
84 | public int PoolSelectorThresholdInBytes { get; }
85 |
86 | ///
87 | public override void ReleaseRetainedResources()
88 | {
89 | this.InitArrayPools();
90 | }
91 |
92 | ///
93 | public override IMemoryOwner Allocate(int length, AllocationOptions options = AllocationOptions.None)
94 | {
95 | Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length));
96 | int itemSizeBytes = Unsafe.SizeOf();
97 | int bufferSizeInBytes = length * itemSizeBytes;
98 | if (bufferSizeInBytes < 0)
99 | {
100 | throw new ArgumentOutOfRangeException(
101 | nameof(length),
102 | $"{nameof(ArrayPoolMemoryAllocator)} can not allocate {length} elements of {typeof(T).Name}.");
103 | }
104 |
105 | ArrayPool pool = this.GetArrayPool(bufferSizeInBytes);
106 | byte[] byteArray = pool.Rent(bufferSizeInBytes);
107 |
108 | var buffer = new Buffer(byteArray, length, pool);
109 | if (options == AllocationOptions.Clean)
110 | {
111 | buffer.GetSpan().Clear();
112 | }
113 |
114 | return buffer;
115 | }
116 |
117 | ///
118 | public override IManagedByteBuffer AllocateManagedByteBuffer(int length, AllocationOptions options = AllocationOptions.None)
119 | {
120 | Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length));
121 |
122 | ArrayPool pool = this.GetArrayPool(length);
123 | byte[] byteArray = pool.Rent(length);
124 |
125 | var buffer = new ManagedByteBuffer(byteArray, length, pool);
126 | if (options == AllocationOptions.Clean)
127 | {
128 | buffer.GetSpan().Clear();
129 | }
130 |
131 | return buffer;
132 | }
133 |
134 | private static int GetLargeBufferThresholdInBytes(int maxPoolSizeInBytes)
135 | {
136 | return maxPoolSizeInBytes / 4;
137 | }
138 |
139 | private ArrayPool GetArrayPool(int bufferSizeInBytes)
140 | {
141 | return bufferSizeInBytes <= this.PoolSelectorThresholdInBytes ? this.normalArrayPool : this.largeArrayPool;
142 | }
143 |
144 | private void InitArrayPools()
145 | {
146 | this.largeArrayPool = ArrayPool.Create(this.MaxPoolSizeInBytes, this.maxArraysPerBucketLargePool);
147 | this.normalArrayPool = ArrayPool.Create(this.PoolSelectorThresholdInBytes, this.maxArraysPerBucketNormalPool);
148 | }
149 | }
150 | }
--------------------------------------------------------------------------------
/src/SixLabors.Core/Memory/IManagedByteBuffer.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Buffers;
5 |
6 | namespace SixLabors.Memory
7 | {
8 | ///
9 | /// Represents a byte buffer backed by a managed array. Useful for interop with classic .NET API-s.
10 | ///
11 | public interface IManagedByteBuffer : IMemoryOwner
12 | {
13 | ///
14 | /// Gets the managed array backing this buffer instance.
15 | ///
16 | byte[] Array { get; }
17 | }
18 | }
--------------------------------------------------------------------------------
/src/SixLabors.Core/Memory/Internals/BasicArrayBuffer.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Runtime.CompilerServices;
6 |
7 | namespace SixLabors.Memory.Internals
8 | {
9 | ///
10 | /// Wraps an array as an instance.
11 | ///
12 | ///
13 | internal class BasicArrayBuffer : ManagedBufferBase
14 | where T : struct
15 | {
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | /// The array.
20 | /// The length of the buffer.
21 | public BasicArrayBuffer(T[] array, int length)
22 | {
23 | DebugGuard.MustBeLessThanOrEqualTo(length, array.Length, nameof(length));
24 | this.Array = array;
25 | this.Length = length;
26 | }
27 |
28 | ///
29 | /// Initializes a new instance of the class.
30 | ///
31 | /// The array.
32 | public BasicArrayBuffer(T[] array)
33 | : this(array, array.Length)
34 | {
35 | }
36 |
37 | ///
38 | /// Gets the array.
39 | ///
40 | public T[] Array { get; }
41 |
42 | ///
43 | /// Gets the length.
44 | ///
45 | public int Length { get; }
46 |
47 | ///
48 | public override Span GetSpan() => this.Array.AsSpan(0, this.Length);
49 |
50 | ///
51 | protected override void Dispose(bool disposing)
52 | {
53 | }
54 |
55 | ///
56 | protected override object GetPinnableObject()
57 | {
58 | return this.Array;
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/src/SixLabors.Core/Memory/Internals/BasicByteBuffer.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | namespace SixLabors.Memory.Internals
5 | {
6 | ///
7 | /// Provides an based on .
8 | ///
9 | internal sealed class BasicByteBuffer : BasicArrayBuffer, IManagedByteBuffer
10 | {
11 | ///
12 | /// Initializes a new instance of the class.
13 | ///
14 | /// The byte array.
15 | internal BasicByteBuffer(byte[] array)
16 | : base(array)
17 | {
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/src/SixLabors.Core/Memory/Internals/ManagedBufferBase.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Buffers;
5 | using System.Runtime.InteropServices;
6 |
7 | namespace SixLabors.Memory.Internals
8 | {
9 | ///
10 | /// Provides a base class for implementations by implementing pinning logic for adaption.
11 | ///
12 | /// The element type.
13 | internal abstract class ManagedBufferBase : MemoryManager
14 | where T : struct
15 | {
16 | private GCHandle pinHandle;
17 |
18 | ///
19 | public override unsafe MemoryHandle Pin(int elementIndex = 0)
20 | {
21 | if (!this.pinHandle.IsAllocated)
22 | {
23 | this.pinHandle = GCHandle.Alloc(this.GetPinnableObject(), GCHandleType.Pinned);
24 | }
25 |
26 | void* ptr = (void*)this.pinHandle.AddrOfPinnedObject();
27 | return new MemoryHandle(ptr, this.pinHandle);
28 | }
29 |
30 | ///
31 | public override void Unpin()
32 | {
33 | if (this.pinHandle.IsAllocated)
34 | {
35 | this.pinHandle.Free();
36 | }
37 | }
38 |
39 | ///
40 | /// Gets the object that should be pinned.
41 | ///
42 | /// The pinnable .
43 | protected abstract object GetPinnableObject();
44 | }
45 | }
--------------------------------------------------------------------------------
/src/SixLabors.Core/Memory/MemoryAllocator.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Buffers;
5 |
6 | namespace SixLabors.Memory
7 | {
8 | ///
9 | /// Memory managers are used to allocate memory for image processing operations.
10 | ///
11 | public abstract class MemoryAllocator
12 | {
13 | ///
14 | /// Allocates an , holding a of length .
15 | ///
16 | /// Type of the data stored in the buffer.
17 | /// Size of the buffer to allocate.
18 | /// The allocation options.
19 | /// A buffer of values of type .
20 | public abstract IMemoryOwner Allocate(int length, AllocationOptions options = AllocationOptions.None)
21 | where T : struct;
22 |
23 | ///
24 | /// Allocates an .
25 | ///
26 | /// The requested buffer length.
27 | /// The allocation options.
28 | /// The .
29 | public abstract IManagedByteBuffer AllocateManagedByteBuffer(int length, AllocationOptions options = AllocationOptions.None);
30 |
31 | ///
32 | /// Releases all retained resources not being in use.
33 | /// Eg: by resetting array pools and letting GC to free the arrays.
34 | ///
35 | public virtual void ReleaseRetainedResources()
36 | {
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/SixLabors.Core/Memory/SimpleGcMemoryAllocator.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Buffers;
6 | using SixLabors.Memory.Internals;
7 |
8 | namespace SixLabors.Memory
9 | {
10 | ///
11 | /// Implements by newing up arrays by the GC on every allocation requests.
12 | ///
13 | public sealed class SimpleGcMemoryAllocator : MemoryAllocator
14 | {
15 | ///
16 | public override IMemoryOwner Allocate(int length, AllocationOptions options = AllocationOptions.None)
17 | {
18 | Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length));
19 |
20 | return new BasicArrayBuffer(new T[length]);
21 | }
22 |
23 | ///
24 | public override IManagedByteBuffer AllocateManagedByteBuffer(int length, AllocationOptions options = AllocationOptions.None)
25 | {
26 | Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length));
27 |
28 | return new BasicByteBuffer(new byte[length]);
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/src/SixLabors.Core/Primitives/Matrix3x2Extensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Numerics;
5 |
6 | namespace SixLabors.Primitives
7 | {
8 | ///
9 | /// Extension methods for the struct.
10 | ///
11 | public static class Matrix3x2Extensions
12 | {
13 | ///
14 | /// Creates a translation matrix from the given vector.
15 | ///
16 | /// The translation position.
17 | /// A translation matrix.
18 | public static Matrix3x2 CreateTranslation(PointF position) => Matrix3x2.CreateTranslation(position);
19 |
20 | ///
21 | /// Creates a scale matrix that is offset by a given center point.
22 | ///
23 | /// Value to scale by on the X-axis.
24 | /// Value to scale by on the Y-axis.
25 | /// The center point.
26 | /// A scaling matrix.
27 | public static Matrix3x2 CreateScale(float xScale, float yScale, PointF centerPoint) => Matrix3x2.CreateScale(xScale, yScale, centerPoint);
28 |
29 | ///
30 | /// Creates a scale matrix from the given vector scale.
31 | ///
32 | /// The scale to use.
33 | /// A scaling matrix.
34 | public static Matrix3x2 CreateScale(SizeF scales) => Matrix3x2.CreateScale(scales);
35 |
36 | ///
37 | /// Creates a scale matrix from the given vector scale with an offset from the given center point.
38 | ///
39 | /// The scale to use.
40 | /// The center offset.
41 | /// A scaling matrix.
42 | public static Matrix3x2 CreateScale(SizeF scales, PointF centerPoint) => Matrix3x2.CreateScale(scales, centerPoint);
43 |
44 | ///
45 | /// Creates a scale matrix that scales uniformly with the given scale with an offset from the given center.
46 | ///
47 | /// The uniform scale to use.
48 | /// The center offset.
49 | /// A scaling matrix.
50 | public static Matrix3x2 CreateScale(float scale, PointF centerPoint) => Matrix3x2.CreateScale(scale, centerPoint);
51 |
52 | ///
53 | /// Creates a skew matrix from the given angles in degrees.
54 | ///
55 | /// The X angle, in degrees.
56 | /// The Y angle, in degrees.
57 | /// A skew matrix.
58 | public static Matrix3x2 CreateSkewDegrees(float degreesX, float degreesY) => Matrix3x2.CreateSkew(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY));
59 |
60 | ///
61 | /// Creates a skew matrix from the given angles in radians and a center point.
62 | ///
63 | /// The X angle, in radians.
64 | /// The Y angle, in radians.
65 | /// The center point.
66 | /// A skew matrix.
67 | public static Matrix3x2 CreateSkew(float radiansX, float radiansY, PointF centerPoint) => Matrix3x2.CreateSkew(radiansX, radiansY, centerPoint);
68 |
69 | ///
70 | /// Creates a skew matrix from the given angles in degrees and a center point.
71 | ///
72 | /// The X angle, in degrees.
73 | /// The Y angle, in degrees.
74 | /// The center point.
75 | /// A skew matrix.
76 | public static Matrix3x2 CreateSkewDegrees(float degreesX, float degreesY, PointF centerPoint) => Matrix3x2.CreateSkew(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY), centerPoint);
77 |
78 | ///
79 | /// Creates a rotation matrix using the given rotation in degrees.
80 | ///
81 | /// The amount of rotation, in degrees.
82 | /// A rotation matrix.
83 | public static Matrix3x2 CreateRotationDegrees(float degrees) => Matrix3x2.CreateRotation(GeometryUtilities.DegreeToRadian(degrees));
84 |
85 | ///
86 | /// Creates a rotation matrix using the given rotation in radians and a center point.
87 | ///
88 | /// The amount of rotation, in radians.
89 | /// The center point.
90 | /// A rotation matrix.
91 | public static Matrix3x2 CreateRotation(float radians, PointF centerPoint) => Matrix3x2.CreateRotation(radians, centerPoint);
92 |
93 | ///
94 | /// Creates a rotation matrix using the given rotation in degrees and a center point.
95 | ///
96 | /// The amount of rotation, in degrees.
97 | /// The center point.
98 | /// A rotation matrix.
99 | public static Matrix3x2 CreateRotationDegrees(float degrees, PointF centerPoint) => Matrix3x2.CreateRotation(GeometryUtilities.DegreeToRadian(degrees), centerPoint);
100 | }
101 | }
--------------------------------------------------------------------------------
/src/SixLabors.Core/Primitives/Point.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.ComponentModel;
6 | using System.Numerics;
7 | using System.Runtime.CompilerServices;
8 |
9 | namespace SixLabors.Primitives
10 | {
11 | ///
12 | /// Represents an ordered pair of integer x- and y-coordinates that defines a point in
13 | /// a two-dimensional plane.
14 | ///
15 | ///
16 | /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
17 | /// as it avoids the need to create new values for modification operations.
18 | ///
19 | public struct Point : IEquatable
20 | {
21 | ///
22 | /// Represents a that has X and Y values set to zero.
23 | ///
24 | public static readonly Point Empty = default;
25 |
26 | ///
27 | /// Initializes a new instance of the struct.
28 | ///
29 | /// The horizontal and vertical position of the point.
30 | public Point(int value)
31 | : this()
32 | {
33 | this.X = LowInt16(value);
34 | this.Y = HighInt16(value);
35 | }
36 |
37 | ///
38 | /// Initializes a new instance of the struct.
39 | ///
40 | /// The horizontal position of the point.
41 | /// The vertical position of the point.
42 | public Point(int x, int y)
43 | : this()
44 | {
45 | this.X = x;
46 | this.Y = y;
47 | }
48 |
49 | ///
50 | /// Initializes a new instance of the struct from the given .
51 | ///
52 | /// The size.
53 | public Point(Size size)
54 | {
55 | this.X = size.Width;
56 | this.Y = size.Height;
57 | }
58 |
59 | ///
60 | /// Gets or sets the x-coordinate of this .
61 | ///
62 | public int X { get; set; }
63 |
64 | ///
65 | /// Gets or sets the y-coordinate of this .
66 | ///
67 | public int Y { get; set; }
68 |
69 | ///
70 | /// Gets a value indicating whether this is empty.
71 | ///
72 | [EditorBrowsable(EditorBrowsableState.Never)]
73 | public bool IsEmpty => this.Equals(Empty);
74 |
75 | ///
76 | /// Creates a with the coordinates of the specified .
77 | ///
78 | /// The point.
79 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
80 | public static implicit operator PointF(Point point) => new PointF(point.X, point.Y);
81 |
82 | ///
83 | /// Creates a with the coordinates of the specified .
84 | ///
85 | /// The point.
86 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
87 | public static implicit operator Vector2(Point point) => new Vector2(point.X, point.Y);
88 |
89 | ///
90 | /// Creates a with the coordinates of the specified .
91 | ///
92 | /// The point.
93 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
94 | public static explicit operator Size(Point point) => new Size(point.X, point.Y);
95 |
96 | ///
97 | /// Negates the given point by multiplying all values by -1.
98 | ///
99 | /// The source point.
100 | /// The negated point.
101 | public static Point operator -(Point value) => new Point(-value.X, -value.Y);
102 |
103 | ///
104 | /// Translates a by a given .
105 | ///
106 | /// The point on the left hand of the operand.
107 | /// The size on the right hand of the operand.
108 | ///
109 | /// The .
110 | ///
111 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
112 | public static Point operator +(Point point, Size size) => Add(point, size);
113 |
114 | ///
115 | /// Translates a by the negative of a given .
116 | ///
117 | /// The point on the left hand of the operand.
118 | /// The size on the right hand of the operand.
119 | /// The .
120 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
121 | public static Point operator -(Point point, Size size) => Subtract(point, size);
122 |
123 | ///
124 | /// Multiplies by a producing .
125 | ///
126 | /// Multiplier of type .
127 | /// Multiplicand of type .
128 | /// Product of type .
129 | public static Point operator *(int left, Point right) => Multiply(right, left);
130 |
131 | ///
132 | /// Multiplies by a producing .
133 | ///
134 | /// Multiplicand of type .
135 | /// Multiplier of type .
136 | /// Product of type .
137 | public static Point operator *(Point left, int right) => Multiply(left, right);
138 |
139 | ///
140 | /// Divides by a producing .
141 | ///
142 | /// Dividend of type .
143 | /// Divisor of type .
144 | /// Result of type .
145 | public static Point operator /(Point left, int right)
146 | => new Point(left.X / right, left.Y / right);
147 |
148 | ///
149 | /// Compares two objects for equality.
150 | ///
151 | /// The on the left side of the operand.
152 | /// The on the right side of the operand.
153 | ///
154 | /// True if the current left is equal to the parameter; otherwise, false.
155 | ///
156 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
157 | public static bool operator ==(Point left, Point right) => left.Equals(right);
158 |
159 | ///
160 | /// Compares two objects for inequality.
161 | ///
162 | /// The on the left side of the operand.
163 | /// The on the right side of the operand.
164 | ///
165 | /// True if the current left is unequal to the parameter; otherwise, false.
166 | ///
167 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
168 | public static bool operator !=(Point left, Point right) => !left.Equals(right);
169 |
170 | ///
171 | /// Translates a by the negative of a given .
172 | ///
173 | /// The point on the left hand of the operand.
174 | /// The size on the right hand of the operand.
175 | /// The .
176 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
177 | public static Point Add(Point point, Size size) => new Point(unchecked(point.X + size.Width), unchecked(point.Y + size.Height));
178 |
179 | ///
180 | /// Translates a by the negative of a given value.
181 | ///
182 | /// The point on the left hand of the operand.
183 | /// The value on the right hand of the operand.
184 | /// The .
185 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
186 | public static Point Multiply(Point point, int value) => new Point(unchecked(point.X * value), unchecked(point.Y * value));
187 |
188 | ///
189 | /// Translates a by the negative of a given .
190 | ///
191 | /// The point on the left hand of the operand.
192 | /// The size on the right hand of the operand.
193 | /// The .
194 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
195 | public static Point Subtract(Point point, Size size) => new Point(unchecked(point.X - size.Width), unchecked(point.Y - size.Height));
196 |
197 | ///
198 | /// Converts a to a by performing a ceiling operation on all the coordinates.
199 | ///
200 | /// The point.
201 | /// The .
202 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
203 | public static Point Ceiling(PointF point) => new Point(unchecked((int)MathF.Ceiling(point.X)), unchecked((int)MathF.Ceiling(point.Y)));
204 |
205 | ///
206 | /// Converts a to a by performing a round operation on all the coordinates.
207 | ///
208 | /// The point.
209 | /// The .
210 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
211 | public static Point Round(PointF point) => new Point(unchecked((int)MathF.Round(point.X)), unchecked((int)MathF.Round(point.Y)));
212 |
213 | ///
214 | /// Converts a to a by performing a round operation on all the coordinates.
215 | ///
216 | /// The vector.
217 | /// The .
218 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
219 | public static Point Round(Vector2 vector) => new Point(unchecked((int)MathF.Round(vector.X)), unchecked((int)MathF.Round(vector.Y)));
220 |
221 | ///
222 | /// Converts a to a by performing a truncate operation on all the coordinates.
223 | ///
224 | /// The point.
225 | /// The .
226 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
227 | public static Point Truncate(PointF point) => new Point(unchecked((int)point.X), unchecked((int)point.Y));
228 |
229 | ///
230 | /// Transforms a point by a specified 3x2 matrix.
231 | ///
232 | /// The point to transform.
233 | /// The transformation matrix used.
234 | /// The transformed .
235 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
236 | public static Point Transform(Point point, Matrix3x2 matrix) => Round(Vector2.Transform(new Vector2(point.X, point.Y), matrix));
237 |
238 | ///
239 | /// Deconstructs this point into two integers.
240 | ///
241 | /// The out value for X.
242 | /// The out value for Y.
243 | public void Deconstruct(out int x, out int y)
244 | {
245 | x = this.X;
246 | y = this.Y;
247 | }
248 |
249 | ///
250 | /// Translates this by the specified amount.
251 | ///
252 | /// The amount to offset the x-coordinate.
253 | /// The amount to offset the y-coordinate.
254 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
255 | public void Offset(int dx, int dy)
256 | {
257 | unchecked
258 | {
259 | this.X += dx;
260 | this.Y += dy;
261 | }
262 | }
263 |
264 | ///
265 | /// Translates this by the specified amount.
266 | ///
267 | /// The used offset this .
268 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
269 | public void Offset(Point point) => this.Offset(point.X, point.Y);
270 |
271 | ///
272 | public override int GetHashCode() => HashCode.Combine(this.X, this.Y);
273 |
274 | ///
275 | public override string ToString() => $"Point [ X={this.X}, Y={this.Y} ]";
276 |
277 | ///
278 | public override bool Equals(object obj) => obj is Point other && this.Equals(other);
279 |
280 | ///
281 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
282 | public bool Equals(Point other) => this.X.Equals(other.X) && this.Y.Equals(other.Y);
283 |
284 | private static short HighInt16(int n) => unchecked((short)((n >> 16) & 0xffff));
285 |
286 | private static short LowInt16(int n) => unchecked((short)(n & 0xffff));
287 | }
288 | }
--------------------------------------------------------------------------------
/src/SixLabors.Core/Primitives/PointF.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.ComponentModel;
6 | using System.Numerics;
7 | using System.Runtime.CompilerServices;
8 |
9 | namespace SixLabors.Primitives
10 | {
11 | ///
12 | /// Represents an ordered pair of single precision floating point x- and y-coordinates that defines a point in
13 | /// a two-dimensional plane.
14 | ///
15 | ///
16 | /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
17 | /// as it avoids the need to create new values for modification operations.
18 | ///
19 | public struct PointF : IEquatable
20 | {
21 | ///
22 | /// Represents a that has X and Y values set to zero.
23 | ///
24 | public static readonly PointF Empty = default;
25 |
26 | ///
27 | /// Initializes a new instance of the struct.
28 | ///
29 | /// The horizontal position of the point.
30 | /// The vertical position of the point.
31 | public PointF(float x, float y)
32 | : this()
33 | {
34 | this.X = x;
35 | this.Y = y;
36 | }
37 |
38 | ///
39 | /// Initializes a new instance of the struct from the given .
40 | ///
41 | /// The size.
42 | public PointF(SizeF size)
43 | {
44 | this.X = size.Width;
45 | this.Y = size.Height;
46 | }
47 |
48 | ///
49 | /// Gets or sets the x-coordinate of this .
50 | ///
51 | public float X { get; set; }
52 |
53 | ///
54 | /// Gets or sets the y-coordinate of this .
55 | ///
56 | public float Y { get; set; }
57 |
58 | ///
59 | /// Gets a value indicating whether this is empty.
60 | ///
61 | [EditorBrowsable(EditorBrowsableState.Never)]
62 | public bool IsEmpty => this.Equals(Empty);
63 |
64 | ///
65 | /// Creates a with the coordinates of the specified .
66 | ///
67 | /// The vector.
68 | ///
69 | /// The .
70 | ///
71 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
72 | public static implicit operator PointF(Vector2 vector) => new PointF(vector.X, vector.Y);
73 |
74 | ///
75 | /// Creates a with the coordinates of the specified .
76 | ///
77 | /// The point.
78 | ///
79 | /// The .
80 | ///
81 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
82 | public static implicit operator Vector2(PointF point) => new Vector2(point.X, point.Y);
83 |
84 | ///
85 | /// Creates a with the coordinates of the specified by truncating each of the coordinates.
86 | ///
87 | /// The point.
88 | ///
89 | /// The .
90 | ///
91 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
92 | public static explicit operator Point(PointF point) => Point.Truncate(point);
93 |
94 | ///
95 | /// Negates the given point by multiplying all values by -1.
96 | ///
97 | /// The source point.
98 | /// The negated point.
99 | public static PointF operator -(PointF value) => new PointF(-value.X, -value.Y);
100 |
101 | ///
102 | /// Translates a by a given .
103 | ///
104 | /// The point on the left hand of the operand.
105 | /// The size on the right hand of the operand.
106 | ///
107 | /// The .
108 | ///
109 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
110 | public static PointF operator +(PointF point, SizeF size) => Add(point, size);
111 |
112 | ///
113 | /// Translates a by the negative of a given .
114 | ///
115 | /// The point on the left hand of the operand.
116 | /// The size on the right hand of the operand.
117 | /// The .
118 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
119 | public static PointF operator -(PointF point, PointF size) => Subtract(point, size);
120 |
121 | ///
122 | /// Translates a by a given .
123 | ///
124 | /// The point on the left hand of the operand.
125 | /// The size on the right hand of the operand.
126 | ///
127 | /// The .
128 | ///
129 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
130 | public static PointF operator +(PointF point, PointF size) => Add(point, size);
131 |
132 | ///
133 | /// Translates a by the negative of a given .
134 | ///
135 | /// The point on the left hand of the operand.
136 | /// The size on the right hand of the operand.
137 | /// The .
138 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
139 | public static PointF operator -(PointF point, SizeF size) => Subtract(point, size);
140 |
141 | ///
142 | /// Multiplies by a producing .
143 | ///
144 | /// Multiplier of type .
145 | /// Multiplicand of type .
146 | /// Product of type .
147 | public static PointF operator *(float left, PointF right) => Multiply(right, left);
148 |
149 | ///
150 | /// Multiplies by a producing .
151 | ///
152 | /// Multiplicand of type .
153 | /// Multiplier of type .
154 | /// Product of type .
155 | public static PointF operator *(PointF left, float right) => Multiply(left, right);
156 |
157 | ///
158 | /// Divides by a producing .
159 | ///
160 | /// Dividend of type .
161 | /// Divisor of type .
162 | /// Result of type .
163 | public static PointF operator /(PointF left, float right)
164 | => new PointF(left.X / right, left.Y / right);
165 |
166 | ///
167 | /// Compares two objects for equality.
168 | ///
169 | ///
170 | /// The on the left side of the operand.
171 | ///
172 | ///
173 | /// The on the right side of the operand.
174 | ///
175 | ///
176 | /// True if the current left is equal to the parameter; otherwise, false.
177 | ///
178 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
179 | public static bool operator ==(PointF left, PointF right) => left.Equals(right);
180 |
181 | ///
182 | /// Compares two objects for inequality.
183 | ///
184 | ///
185 | /// The on the left side of the operand.
186 | ///
187 | ///
188 | /// The on the right side of the operand.
189 | ///
190 | ///
191 | /// True if the current left is unequal to the parameter; otherwise, false.
192 | ///
193 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
194 | public static bool operator !=(PointF left, PointF right) => !left.Equals(right);
195 |
196 | ///
197 | /// Translates a by the given .
198 | ///
199 | /// The point on the left hand of the operand.
200 | /// The size on the right hand of the operand.
201 | /// The .
202 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
203 | public static PointF Add(PointF point, SizeF size) => new PointF(point.X + size.Width, point.Y + size.Height);
204 |
205 | ///
206 | /// Translates a by the given .
207 | ///
208 | /// The point on the left hand of the operand.
209 | /// The point on the right hand of the operand.
210 | /// The .
211 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
212 | public static PointF Add(PointF point, PointF pointb) => new PointF(point.X + pointb.X, point.Y + pointb.Y);
213 |
214 | ///
215 | /// Translates a by the negative of a given .
216 | ///
217 | /// The point on the left hand of the operand.
218 | /// The size on the right hand of the operand.
219 | /// The .
220 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
221 | public static PointF Subtract(PointF point, SizeF size) => new PointF(point.X - size.Width, point.Y - size.Height);
222 |
223 | ///
224 | /// Translates a by the negative of a given .
225 | ///
226 | /// The point on the left hand of the operand.
227 | /// The point on the right hand of the operand.
228 | /// The .
229 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
230 | public static PointF Subtract(PointF point, PointF pointb) => new PointF(point.X - pointb.X, point.Y - pointb.Y);
231 |
232 | ///
233 | /// Translates a by the multiplying the X and Y by the given value.
234 | ///
235 | /// The point on the left hand of the operand.
236 | /// The value on the right hand of the operand.
237 | /// The .
238 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
239 | public static PointF Multiply(PointF point, float right) => new PointF(point.X * right, point.Y * right);
240 |
241 | ///
242 | /// Transforms a point by a specified 3x2 matrix.
243 | ///
244 | /// The point to transform.
245 | /// The transformation matrix used.
246 | /// The transformed .
247 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
248 | public static PointF Transform(PointF point, Matrix3x2 matrix) => Vector2.Transform(point, matrix);
249 |
250 | ///
251 | /// Deconstructs this point into two floats.
252 | ///
253 | /// The out value for X.
254 | /// The out value for Y.
255 | public void Deconstruct(out float x, out float y)
256 | {
257 | x = this.X;
258 | y = this.Y;
259 | }
260 |
261 | ///
262 | /// Translates this by the specified amount.
263 | ///
264 | /// The amount to offset the x-coordinate.
265 | /// The amount to offset the y-coordinate.
266 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
267 | public void Offset(float dx, float dy)
268 | {
269 | this.X += dx;
270 | this.Y += dy;
271 | }
272 |
273 | ///
274 | /// Translates this by the specified amount.
275 | ///
276 | /// The used offset this .
277 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
278 | public void Offset(PointF point) => this.Offset(point.X, point.Y);
279 |
280 | ///
281 | public override int GetHashCode() => HashCode.Combine(this.X, this.Y);
282 |
283 | ///
284 | public override string ToString() => $"PointF [ X={this.X}, Y={this.Y} ]";
285 |
286 | ///
287 | public override bool Equals(object obj) => obj is PointF && this.Equals((PointF)obj);
288 |
289 | ///
290 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
291 | public bool Equals(PointF other) => this.X.Equals(other.X) && this.Y.Equals(other.Y);
292 | }
293 | }
--------------------------------------------------------------------------------
/src/SixLabors.Core/Primitives/SizeF.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.ComponentModel;
6 | using System.Numerics;
7 | using System.Runtime.CompilerServices;
8 |
9 | namespace SixLabors.Primitives
10 | {
11 | ///
12 | /// Stores an ordered pair of single precision floating points, which specify a height and width.
13 | ///
14 | ///
15 | /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
16 | /// as it avoids the need to create new values for modification operations.
17 | ///
18 | public struct SizeF : IEquatable
19 | {
20 | ///
21 | /// Represents a that has Width and Height values set to zero.
22 | ///
23 | public static readonly SizeF Empty = default;
24 |
25 | ///
26 | /// Initializes a new instance of the struct.
27 | ///
28 | /// The width of the size.
29 | /// The height of the size.
30 | public SizeF(float width, float height)
31 | {
32 | this.Width = width;
33 | this.Height = height;
34 | }
35 |
36 | ///
37 | /// Initializes a new instance of the struct.
38 | ///
39 | /// The size.
40 | public SizeF(SizeF size)
41 | : this()
42 | {
43 | this.Width = size.Width;
44 | this.Height = size.Height;
45 | }
46 |
47 | ///
48 | /// Initializes a new instance of the struct from the given .
49 | ///
50 | /// The point.
51 | public SizeF(PointF point)
52 | {
53 | this.Width = point.X;
54 | this.Height = point.Y;
55 | }
56 |
57 | ///
58 | /// Gets or sets the width of this .
59 | ///
60 | public float Width { get; set; }
61 |
62 | ///
63 | /// Gets or sets the height of this .
64 | ///
65 | public float Height { get; set; }
66 |
67 | ///
68 | /// Gets a value indicating whether this is empty.
69 | ///
70 | [EditorBrowsable(EditorBrowsableState.Never)]
71 | public bool IsEmpty => this.Equals(Empty);
72 |
73 | ///
74 | /// Creates a with the coordinates of the specified .
75 | ///
76 | /// The point.
77 | ///
78 | /// The .
79 | ///
80 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
81 | public static implicit operator Vector2(SizeF point) => new Vector2(point.Width, point.Height);
82 |
83 | ///
84 | /// Creates a with the dimensions of the specified by truncating each of the dimensions.
85 | ///
86 | /// The size.
87 | ///
88 | /// The .
89 | ///
90 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
91 | public static explicit operator Size(SizeF size) => new Size(unchecked((int)size.Width), unchecked((int)size.Height));
92 |
93 | ///
94 | /// Converts the given into a .
95 | ///
96 | /// The size.
97 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
98 | public static explicit operator PointF(SizeF size) => new PointF(size.Width, size.Height);
99 |
100 | ///
101 | /// Computes the sum of adding two sizes.
102 | ///
103 | /// The size on the left hand of the operand.
104 | /// The size on the right hand of the operand.
105 | ///
106 | /// The .
107 | ///
108 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
109 | public static SizeF operator +(SizeF left, SizeF right) => Add(left, right);
110 |
111 | ///
112 | /// Computes the difference left by subtracting one size from another.
113 | ///
114 | /// The size on the left hand of the operand.
115 | /// The size on the right hand of the operand.
116 | ///
117 | /// The .
118 | ///
119 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
120 | public static SizeF operator -(SizeF left, SizeF right) => Subtract(left, right);
121 |
122 | ///
123 | /// Multiplies by a producing .
124 | ///
125 | /// Multiplier of type .
126 | /// Multiplicand of type .
127 | /// Product of type .
128 | public static SizeF operator *(float left, SizeF right) => Multiply(right, left);
129 |
130 | ///
131 | /// Multiplies by a producing .
132 | ///
133 | /// Multiplicand of type .
134 | /// Multiplier of type .
135 | /// Product of type .
136 | public static SizeF operator *(SizeF left, float right) => Multiply(left, right);
137 |
138 | ///
139 | /// Divides by a producing .
140 | ///
141 | /// Dividend of type .
142 | /// Divisor of type .
143 | /// Result of type .
144 | public static SizeF operator /(SizeF left, float right)
145 | => new SizeF(left.Width / right, left.Height / right);
146 |
147 | ///
148 | /// Compares two objects for equality.
149 | ///
150 | /// The size on the left hand of the operand.
151 | /// The size on the right hand of the operand.
152 | ///
153 | /// True if the current left is equal to the parameter; otherwise, false.
154 | ///
155 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
156 | public static bool operator ==(SizeF left, SizeF right) => left.Equals(right);
157 |
158 | ///
159 | /// Compares two objects for inequality.
160 | ///
161 | /// The size on the left hand of the operand.
162 | /// The size on the right hand of the operand.
163 | ///
164 | /// True if the current left is unequal to the parameter; otherwise, false.
165 | ///
166 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
167 | public static bool operator !=(SizeF left, SizeF right) => !left.Equals(right);
168 |
169 | ///
170 | /// Performs vector addition of two objects.
171 | ///
172 | /// The size on the left hand of the operand.
173 | /// The size on the right hand of the operand.
174 | /// The .
175 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
176 | public static SizeF Add(SizeF left, SizeF right) => new SizeF(left.Width + right.Width, left.Height + right.Height);
177 |
178 | ///
179 | /// Contracts a by another .
180 | ///
181 | /// The size on the left hand of the operand.
182 | /// The size on the right hand of the operand.
183 | /// The .
184 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
185 | public static SizeF Subtract(SizeF left, SizeF right) => new SizeF(left.Width - right.Width, left.Height - right.Height);
186 |
187 | ///
188 | /// Transforms a size by the given matrix.
189 | ///
190 | /// The source size.
191 | /// The transformation matrix.
192 | /// A transformed size.
193 | public static SizeF Transform(SizeF size, Matrix3x2 matrix)
194 | {
195 | var v = Vector2.Transform(new Vector2(size.Width, size.Height), matrix);
196 |
197 | return new SizeF(v.X, v.Y);
198 | }
199 |
200 | ///
201 | /// Deconstructs this size into two floats.
202 | ///
203 | /// The out value for the width.
204 | /// The out value for the height.
205 | public void Deconstruct(out float width, out float height)
206 | {
207 | width = this.Width;
208 | height = this.Height;
209 | }
210 |
211 | ///
212 | public override int GetHashCode() => HashCode.Combine(this.Width, this.Height);
213 |
214 | ///
215 | public override string ToString() => $"SizeF [ Width={this.Width}, Height={this.Height} ]";
216 |
217 | ///
218 | public override bool Equals(object obj) => obj is SizeF && this.Equals((SizeF)obj);
219 |
220 | ///
221 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
222 | public bool Equals(SizeF other) => this.Width.Equals(other.Width) && this.Height.Equals(other.Height);
223 |
224 | ///
225 | /// Multiplies by a producing .
226 | ///
227 | /// Multiplicand of type .
228 | /// Multiplier of type .
229 | /// Product of type SizeF.
230 | private static SizeF Multiply(SizeF size, float multiplier) =>
231 | new SizeF(size.Width * multiplier, size.Height * multiplier);
232 | }
233 | }
--------------------------------------------------------------------------------
/src/SixLabors.Core/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System.Runtime.CompilerServices;
5 |
6 | // Ensure the internals can be tested.
7 | [assembly: InternalsVisibleTo("SixLabors.Core.Tests")]
--------------------------------------------------------------------------------
/src/SixLabors.Core/SixLabors.Core.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Low level primitives for use across Six Labors projects.
5 | $(packageversion)
6 | 0.1.0-alpha2
7 | Six Labors
8 | netstandard1.3;netstandard2.0;netcoreapp2.0;netcoreapp2.1;
9 | true
10 | true
11 | SixLabors.Core
12 | SixLabors.Core
13 | rectangle;point;size,primitives
14 | https://raw.githubusercontent.com/SixLabors/Branding/master/icons/core/sixlabors.core.128.png
15 | https://github.com/SixLabors/Core
16 | http://www.apache.org/licenses/LICENSE-2.0
17 | git
18 | https://github.com/SixLabors/Core
19 | Copyright (c) Six Labors and contributors.
20 | full
21 | SixLabors
22 | 7.3
23 |
24 |
25 |
26 | ..\..\shared-infrastructure\SixLabors.ruleset
27 |
28 |
29 |
30 |
31 | $(DefineConstants);SUPPORTS_MATHF
32 |
33 |
34 |
35 | $(DefineConstants);SUPPORTS_HASHCODE
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | All
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/src/SixLabors.Core/SixLabors.Core.csproj.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | True
--------------------------------------------------------------------------------
/tests/CodeCoverage/.gitignore:
--------------------------------------------------------------------------------
1 | /OpenCover*
--------------------------------------------------------------------------------
/tests/CodeCoverage/CodeCoverage.cmd:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | cd tests\CodeCoverage
4 |
5 | nuget restore packages.config -PackagesDirectory .
6 |
7 | cd ..
8 | cd ..
9 |
10 | dotnet restore SixLabors.Core.sln
11 | dotnet build SixLabors.Core.sln --no-incremental -c release /p:codecov=true
12 |
13 | tests\CodeCoverage\OpenCover.4.6.519\tools\OpenCover.Console.exe -target:"dotnet.exe" -targetargs:"test tests\SixLabors.Core.Tests\SixLabors.Core.Tests.csproj --no-build -c release" -searchdirs:"tests\SixLabors.Core.Tests\bin\Release\netcoreapp2.1" -register:user -output:.\SixLabors.Core.Coverage.xml -hideskipped:All -returntargetcode -oldStyle -filter:"+[SixLabors.*]*"
14 |
15 | if %errorlevel% neq 0 exit /b %errorlevel%
16 |
17 | SET PATH=C:\\Python34;C:\\Python34\\Scripts;%PATH%
18 | pip install codecov
19 | codecov -f "SixLabors.Core.Coverage.xml"
--------------------------------------------------------------------------------
/tests/CodeCoverage/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/tests/SixLabors.Core.Tests/Helpers/DebugGuardTests.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | // tell this file to enable debug conditional method calls, i.e. all the debug guard calls
5 | #define DEBUG
6 |
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Diagnostics;
10 | using System.Linq;
11 | using System.Reflection;
12 | using Xunit;
13 |
14 | namespace SixLabors.Helpers.Tests
15 | {
16 | public class DebugGuardTests
17 | {
18 | private class Foo
19 | {
20 | }
21 |
22 | [Fact]
23 | public void AllStaticMethodsOnOnDebugGuardHaveDEBUGConditional()
24 | {
25 | IEnumerable methods = typeof(DebugGuard).GetTypeInfo().GetMethods()
26 | .Where(x => x.IsStatic);
27 |
28 | foreach (MethodInfo m in methods)
29 | {
30 | IEnumerable attribs = m.GetCustomAttributes();
31 | Assert.True(attribs.Select(x => x.ConditionString).Contains("DEBUG"), $"Method '{m.Name}' does not have [Conditional(\"DEBUG\")] set.");
32 | }
33 | }
34 |
35 | [Fact]
36 | public void NotNull_WhenNull_Throws()
37 | {
38 | Foo foo = null;
39 | Assert.Throws(() => Guard.NotNull(foo, nameof(foo)));
40 | }
41 |
42 | [Fact]
43 | public void NotNull_WhenNotNull()
44 | {
45 | var foo = new Foo();
46 | Guard.NotNull(foo, nameof(foo));
47 | }
48 |
49 | [Theory]
50 | [InlineData(null, true)]
51 | [InlineData("", true)]
52 | [InlineData(" ", true)]
53 | [InlineData("$", false)]
54 | [InlineData("lol", false)]
55 | public void NotNullOrWhiteSpace(string str, bool shouldThrow)
56 | {
57 | if (shouldThrow)
58 | {
59 | Assert.ThrowsAny(() => Guard.NotNullOrWhiteSpace(str, nameof(str)));
60 | }
61 | else
62 | {
63 | Guard.NotNullOrWhiteSpace(str, nameof(str));
64 | }
65 | }
66 |
67 | [Theory]
68 | [InlineData(true)]
69 | [InlineData(false)]
70 | public void IsTrue(bool value)
71 | {
72 | if (!value)
73 | {
74 | Assert.Throws(() => Guard.IsTrue(value, nameof(value), "Boo!"));
75 | }
76 | else
77 | {
78 | Guard.IsTrue(value, nameof(value), "Boo.");
79 | }
80 | }
81 |
82 | [Theory]
83 | [InlineData(true)]
84 | [InlineData(false)]
85 | public void IsFalse(bool value)
86 | {
87 | if (value)
88 | {
89 | Assert.Throws(() => Guard.IsFalse(value, nameof(value), "Boo!"));
90 | }
91 | else
92 | {
93 | Guard.IsFalse(value, nameof(value), "Boo.");
94 | }
95 | }
96 |
97 | public static readonly TheoryData SizeCheckData = new TheoryData
98 | {
99 | { 0, 0, false },
100 | { 1, 1, false },
101 | { 1, 0, false },
102 | { 13, 13, false },
103 | { 20, 13, false },
104 | { 12, 13, true },
105 | { 0, 1, true },
106 | };
107 |
108 | [Theory]
109 | [MemberData(nameof(SizeCheckData))]
110 | public void MustBeSizedAtLeast(int length, int minLength, bool shouldThrow)
111 | {
112 | int[] data = new int[length];
113 |
114 | if (shouldThrow)
115 | {
116 | Assert.Throws(() => Guard.MustBeSizedAtLeast((Span)data, minLength, nameof(data)));
117 | Assert.Throws(() => Guard.MustBeSizedAtLeast((ReadOnlySpan)data, minLength, nameof(data)));
118 | }
119 | else
120 | {
121 | Guard.MustBeSizedAtLeast((Span)data, minLength, nameof(data));
122 | Guard.MustBeSizedAtLeast((ReadOnlySpan)data, minLength, nameof(data));
123 | }
124 | }
125 |
126 | [Theory]
127 | [MemberData(nameof(SizeCheckData))]
128 | public void DestinationShouldNotBeTooShort(int destLength, int sourceLength, bool shouldThrow)
129 | {
130 | int[] dest = new int[destLength];
131 | int[] source = new int[sourceLength];
132 |
133 | if (shouldThrow)
134 | {
135 | Assert.Throws(() => Guard.DestinationShouldNotBeTooShort((Span)source, (Span)dest, nameof(dest)));
136 | Assert.Throws(() => Guard.DestinationShouldNotBeTooShort((ReadOnlySpan)source, (Span)dest, nameof(dest)));
137 | }
138 | else
139 | {
140 | Guard.DestinationShouldNotBeTooShort((Span)source, (Span)dest, nameof(dest));
141 | Guard.DestinationShouldNotBeTooShort((ReadOnlySpan)source, (Span)dest, nameof(dest));
142 | }
143 | }
144 |
145 | [Fact]
146 | public void MustBeLessThan_IsLess_ThrowsNoException()
147 | {
148 | DebugGuard.MustBeLessThan(0, 1, "myParamName");
149 | }
150 |
151 | [Theory]
152 | [InlineData(2, 1)]
153 | [InlineData(1, 1)]
154 | public void MustBeLessThan_IsGreaterOrEqual_ThrowsNoException(int value, int max)
155 | {
156 | ArgumentOutOfRangeException exception = Assert.Throws(
157 | () => DebugGuard.MustBeLessThan(value, max, "myParamName"));
158 |
159 | Assert.Equal("myParamName", exception.ParamName);
160 | Assert.Contains($"Value {value} must be less than {max}.", exception.Message);
161 | }
162 |
163 | [Theory]
164 | [InlineData(0, 1)]
165 | [InlineData(1, 1)]
166 | public void MustBeLessThanOrEqualTo_IsLessOrEqual_ThrowsNoException(int value, int max)
167 | {
168 | DebugGuard.MustBeLessThanOrEqualTo(value, max, "myParamName");
169 | }
170 |
171 | [Fact]
172 | public void MustBeLessThanOrEqualTo_IsGreater_ThrowsNoException()
173 | {
174 | ArgumentOutOfRangeException exception = Assert.Throws(() => DebugGuard.MustBeLessThanOrEqualTo(2, 1, "myParamName"));
175 |
176 | Assert.Equal("myParamName", exception.ParamName);
177 | Assert.Contains($"Value 2 must be less than or equal to 1.", exception.Message);
178 | }
179 |
180 | [Fact]
181 | public void MustBeGreaterThan_IsGreater_ThrowsNoException()
182 | {
183 | DebugGuard.MustBeGreaterThan(2, 1, "myParamName");
184 | }
185 |
186 | [Theory]
187 | [InlineData(1, 2)]
188 | [InlineData(1, 1)]
189 | public void MustBeGreaterThan_IsLessOrEqual_ThrowsNoException(int value, int min)
190 | {
191 | ArgumentOutOfRangeException exception = Assert.Throws(
192 | () => DebugGuard.MustBeGreaterThan(value, min, "myParamName"));
193 |
194 | Assert.Equal("myParamName", exception.ParamName);
195 | Assert.Contains($"Value {value} must be greater than {min}.", exception.Message);
196 | }
197 |
198 | [Theory]
199 | [InlineData(2, 1)]
200 | [InlineData(1, 1)]
201 | public void MustBeGreaterThanOrEqualTo_IsGreaterOrEqual_ThrowsNoException(int value, int min)
202 | {
203 | DebugGuard.MustBeGreaterThanOrEqualTo(value, min, "myParamName");
204 | }
205 |
206 | [Fact]
207 | public void MustBeGreaterThanOrEqualTo_IsLess_ThrowsNoException()
208 | {
209 | ArgumentOutOfRangeException exception = Assert.Throws(
210 | () => DebugGuard.MustBeGreaterThanOrEqualTo(1, 2, "myParamName"));
211 |
212 | Assert.Equal("myParamName", exception.ParamName);
213 | Assert.Contains($"Value 1 must be greater than or equal to 2.", exception.Message);
214 | }
215 |
216 | [Theory]
217 | [InlineData(new int[] { 1, 2 }, 1)]
218 | [InlineData(new int[] { 1, 2 }, 2)]
219 | public void MustBeSizedAtLeast_Array_LengthIsGreaterOrEqual_ThrowsNoException(int[] value, int minLength)
220 | {
221 | DebugGuard.MustBeSizedAtLeast(value, minLength, "myParamName");
222 | }
223 |
224 | [Fact]
225 | public void MustBeSizedAtLeast_Array_LengthIsLess_ThrowsException()
226 | {
227 | ArgumentException exception = Assert.Throws(
228 | () => DebugGuard.MustBeSizedAtLeast(new int[] { 1, 2 }, 3, "myParamName"));
229 |
230 | Assert.Equal("myParamName", exception.ParamName);
231 | Assert.Contains($"The size must be at least 3.", exception.Message);
232 | }
233 | }
234 | }
235 |
--------------------------------------------------------------------------------
/tests/SixLabors.Core.Tests/Helpers/FloatRoundingComparer.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Numerics;
7 |
8 | namespace SixLabors.Tests.Helpers
9 | {
10 | ///
11 | /// Allows the comparison of single-precision floating point values by precision.
12 | ///
13 | public struct FloatRoundingComparer : IEqualityComparer, IEqualityComparer
14 | {
15 | ///
16 | /// Initializes a new instance of the struct.
17 | ///
18 | /// The number of decimal places (valid values: 0-7).
19 | public FloatRoundingComparer(int precision)
20 | {
21 | Guard.MustBeBetweenOrEqualTo(precision, 0, 7, nameof(precision));
22 | this.Precision = precision;
23 | }
24 |
25 | ///
26 | /// Gets the number of decimal places (valid values: 0-7).
27 | ///
28 | public int Precision { get; }
29 |
30 | ///
31 | public bool Equals(float x, float y)
32 | {
33 | float xp = (float)Math.Round(x, this.Precision, MidpointRounding.AwayFromZero);
34 | float yp = (float)Math.Round(y, this.Precision, MidpointRounding.AwayFromZero);
35 |
36 | return Comparer.Default.Compare(xp, yp) == 0;
37 | }
38 |
39 | ///
40 | public bool Equals(Vector4 x, Vector4 y)
41 | {
42 | return this.Equals(x.X, y.X) && this.Equals(x.Y, y.Y) && this.Equals(x.Z, y.Z) && this.Equals(x.W, y.W);
43 | }
44 |
45 | ///
46 | public int GetHashCode(float obj)
47 | {
48 | unchecked
49 | {
50 | int hashCode = obj.GetHashCode();
51 | hashCode = (hashCode * 397) ^ this.Precision.GetHashCode();
52 | return hashCode;
53 | }
54 | }
55 |
56 | ///
57 | public int GetHashCode(Vector4 obj) => HashCode.Combine(obj, this.Precision);
58 | }
59 | }
--------------------------------------------------------------------------------
/tests/SixLabors.Core.Tests/Helpers/GeometryUtilitiesTests.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using Xunit;
6 |
7 | namespace SixLabors.Tests.Helpers
8 | {
9 | public class GeometryUtilitiesTests
10 | {
11 | [Fact]
12 | public void Convert_Degree_To_Radian()
13 | => Assert.Equal((float)(Math.PI / 2D), GeometryUtilities.DegreeToRadian(90F), new FloatRoundingComparer(6));
14 |
15 | [Fact]
16 | public void Convert_Radian_To_Degree()
17 | => Assert.Equal(60F, GeometryUtilities.RadianToDegree((float)(Math.PI / 3D)), new FloatRoundingComparer(5));
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/tests/SixLabors.Core.Tests/Helpers/GuardTests.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using Xunit;
6 |
7 | namespace SixLabors.Helpers.Tests
8 | {
9 | public class GuardTests
10 | {
11 | private class Foo
12 | {
13 | }
14 |
15 | [Fact]
16 | public void NotNull_WhenNull_Throws()
17 | {
18 | Foo foo = null;
19 | Assert.Throws(() => Guard.NotNull(foo, nameof(foo)));
20 | }
21 |
22 | [Fact]
23 | public void NotNull_WhenNotNull()
24 | {
25 | Foo foo = new Foo();
26 | Guard.NotNull(foo, nameof(foo));
27 | }
28 |
29 | [Theory]
30 | [InlineData(null, true)]
31 | [InlineData("", true)]
32 | [InlineData(" ", true)]
33 | [InlineData("$", false)]
34 | [InlineData("lol", false)]
35 | public void NotNullOrWhiteSpace(string str, bool shouldThrow)
36 | {
37 | if (shouldThrow)
38 | {
39 | Assert.ThrowsAny(() => Guard.NotNullOrWhiteSpace(str, nameof(str)));
40 | }
41 | else
42 | {
43 | Guard.NotNullOrWhiteSpace(str, nameof(str));
44 | }
45 | }
46 |
47 | [Theory]
48 | [InlineData(true)]
49 | [InlineData(false)]
50 | public void IsTrue(bool value)
51 | {
52 | if (!value)
53 | {
54 | Assert.Throws(() => Guard.IsTrue(value, nameof(value), "Boo!"));
55 | }
56 | else
57 | {
58 | Guard.IsTrue(value, nameof(value), "Boo.");
59 | }
60 | }
61 |
62 | [Theory]
63 | [InlineData(true)]
64 | [InlineData(false)]
65 | public void IsFalse(bool value)
66 | {
67 | if (value)
68 | {
69 | Assert.Throws(() => Guard.IsFalse(value, nameof(value), "Boo!"));
70 | }
71 | else
72 | {
73 | Guard.IsFalse(value, nameof(value), "Boo.");
74 | }
75 | }
76 |
77 | public static readonly TheoryData SizeCheckData = new TheoryData
78 | {
79 | { 0, 0, false },
80 | { 1, 1, false },
81 | { 1, 0, false },
82 | { 13, 13, false },
83 | { 20, 13, false },
84 | { 12, 13, true },
85 | { 0, 1, true },
86 | };
87 |
88 | [Theory]
89 | [MemberData(nameof(SizeCheckData))]
90 | public void MustBeSizedAtLeast(int length, int minLength, bool shouldThrow)
91 | {
92 | int[] data = new int[length];
93 |
94 | if (shouldThrow)
95 | {
96 | Assert.Throws(() => Guard.MustBeSizedAtLeast((Span)data, minLength, nameof(data)));
97 | Assert.Throws(() => Guard.MustBeSizedAtLeast((ReadOnlySpan)data, minLength, nameof(data)));
98 | }
99 | else
100 | {
101 | Guard.MustBeSizedAtLeast((Span)data, minLength, nameof(data));
102 | Guard.MustBeSizedAtLeast((ReadOnlySpan)data, minLength, nameof(data));
103 | }
104 | }
105 |
106 | [Theory]
107 | [MemberData(nameof(SizeCheckData))]
108 | public void DestinationShouldNotBeTooShort(int destLength, int sourceLength, bool shouldThrow)
109 | {
110 | int[] dest = new int[destLength];
111 | int[] source = new int[sourceLength];
112 |
113 | if (shouldThrow)
114 | {
115 | Assert.Throws(() => Guard.DestinationShouldNotBeTooShort((Span)source, (Span)dest, nameof(dest)));
116 | Assert.Throws(() => Guard.DestinationShouldNotBeTooShort((ReadOnlySpan)source, (Span)dest, nameof(dest)));
117 | }
118 | else
119 | {
120 | Guard.DestinationShouldNotBeTooShort((Span)source, (Span)dest, nameof(dest));
121 | Guard.DestinationShouldNotBeTooShort((ReadOnlySpan)source, (Span)dest, nameof(dest));
122 | }
123 | }
124 |
125 | [Fact]
126 | public void MustBeLessThan_IsLess_ThrowsNoException()
127 | {
128 | Guard.MustBeLessThan(0, 1, "myParamName");
129 | }
130 |
131 | [Theory]
132 | [InlineData(2, 1)]
133 | [InlineData(1, 1)]
134 | public void MustBeLessThan_IsGreaterOrEqual_ThrowsNoException(int value, int max)
135 | {
136 | ArgumentOutOfRangeException exception = Assert.Throws(() =>
137 | {
138 | Guard.MustBeLessThan(value, max, "myParamName");
139 | });
140 |
141 | Assert.Equal("myParamName", exception.ParamName);
142 | Assert.Contains($"Value {value} must be less than {max}.", exception.Message);
143 | }
144 |
145 | [Theory]
146 | [InlineData(0, 1)]
147 | [InlineData(1, 1)]
148 | public void MustBeLessThanOrEqualTo_IsLessOrEqual_ThrowsNoException(int value, int max)
149 | {
150 | Guard.MustBeLessThanOrEqualTo(value, max, "myParamName");
151 | }
152 |
153 | [Fact]
154 | public void MustBeLessThanOrEqualTo_IsGreater_ThrowsNoException()
155 | {
156 | ArgumentOutOfRangeException exception = Assert.Throws(() =>
157 | {
158 | Guard.MustBeLessThanOrEqualTo(2, 1, "myParamName");
159 | });
160 |
161 | Assert.Equal("myParamName", exception.ParamName);
162 | Assert.Contains($"Value 2 must be less than or equal to 1.", exception.Message);
163 | }
164 |
165 | [Fact]
166 | public void MustBeGreaterThan_IsGreater_ThrowsNoException()
167 | {
168 | Guard.MustBeGreaterThan(2, 1, "myParamName");
169 | }
170 |
171 | [Theory]
172 | [InlineData(1, 2)]
173 | [InlineData(1, 1)]
174 | public void MustBeGreaterThan_IsLessOrEqual_ThrowsNoException(int value, int min)
175 | {
176 | ArgumentOutOfRangeException exception = Assert.Throws(() =>
177 | {
178 | Guard.MustBeGreaterThan(value, min, "myParamName");
179 | });
180 |
181 | Assert.Equal("myParamName", exception.ParamName);
182 | Assert.Contains($"Value {value} must be greater than {min}.", exception.Message);
183 | }
184 |
185 | [Theory]
186 | [InlineData(2, 1)]
187 | [InlineData(1, 1)]
188 | public void MustBeGreaterThanOrEqualTo_IsGreaterOrEqual_ThrowsNoException(int value, int min)
189 | {
190 | Guard.MustBeGreaterThanOrEqualTo(value, min, "myParamName");
191 | }
192 |
193 | [Fact]
194 | public void MustBeGreaterThanOrEqualTo_IsLess_ThrowsNoException()
195 | {
196 | ArgumentOutOfRangeException exception = Assert.Throws(() =>
197 | {
198 | Guard.MustBeGreaterThanOrEqualTo(1, 2, "myParamName");
199 | });
200 |
201 | Assert.Equal("myParamName", exception.ParamName);
202 | Assert.Contains($"Value 1 must be greater than or equal to 2.", exception.Message);
203 | }
204 |
205 | [Theory]
206 | [InlineData(1, 1, 3)]
207 | [InlineData(2, 1, 3)]
208 | [InlineData(3, 1, 3)]
209 | public void MustBeBetweenOrEqualTo_IsBetweenOrEqual_ThrowsNoException(int value, int min, int max)
210 | {
211 | Guard.MustBeBetweenOrEqualTo(value, min, max, "myParamName");
212 | }
213 |
214 | [Theory]
215 | [InlineData(0, 1, 3)]
216 | [InlineData(4, 1, 3)]
217 | public void MustBeBetweenOrEqualTo_IsLessOrGreater_ThrowsNoException(int value, int min, int max)
218 | {
219 | ArgumentOutOfRangeException exception = Assert.Throws(() =>
220 | {
221 | Guard.MustBeBetweenOrEqualTo(value, min, max, "myParamName");
222 | });
223 |
224 | Assert.Equal("myParamName", exception.ParamName);
225 | Assert.Contains($"Value {value} must be greater than or equal to {min} and less than or equal to {max}.", exception.Message);
226 | }
227 |
228 | [Theory]
229 | [InlineData(2, 1)]
230 | [InlineData(2, 2)]
231 | public void MustBeSizedAtLeast_Array_LengthIsGreaterOrEqual_ThrowsNoException(int valueLength, int minLength)
232 | {
233 | Guard.MustBeSizedAtLeast(new int[valueLength], minLength, "myParamName");
234 | }
235 |
236 | [Fact]
237 | public void MustBeSizedAtLeast_Array_LengthIsLess_ThrowsException()
238 | {
239 | ArgumentException exception = Assert.Throws(() =>
240 | {
241 | Guard.MustBeSizedAtLeast(new int[] { 1, 2 }, 3, "myParamName");
242 | });
243 |
244 | Assert.Equal("myParamName", exception.ParamName);
245 | Assert.Contains("The size must be at least 3", exception.Message);
246 | }
247 | }
248 | }
249 |
--------------------------------------------------------------------------------
/tests/SixLabors.Core.Tests/Helpers/MathFTests.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using Xunit;
6 |
7 | namespace SixLabors.Tests.Helpers
8 | {
9 | public class MathFTests
10 | {
11 | [Fact]
12 | public void MathF_PI_Is_Equal()
13 | {
14 | Assert.Equal(MathF.PI, (float)Math.PI);
15 | }
16 |
17 | [Fact]
18 | public void MathF_Ceililng_Is_Equal()
19 | {
20 | Assert.Equal(MathF.Ceiling(0.3333F), (float)Math.Ceiling(0.3333F));
21 | }
22 |
23 | [Fact]
24 | public void MathF_Cos_Is_Equal()
25 | {
26 | Assert.Equal(MathF.Cos(0.3333F), (float)Math.Cos(0.3333F));
27 | }
28 |
29 | [Fact]
30 | public void MathF_Abs_Is_Equal()
31 | {
32 | Assert.Equal(MathF.Abs(-0.3333F), (float)Math.Abs(-0.3333F));
33 | }
34 |
35 | [Fact]
36 | public void MathF_Atan2_Is_Equal()
37 | {
38 | Assert.Equal(MathF.Atan2(1.2345F, 1.2345F), (float)Math.Atan2(1.2345F, 1.2345F));
39 | }
40 |
41 | [Fact]
42 | public void MathF_Exp_Is_Equal()
43 | {
44 | Assert.Equal(MathF.Exp(1.2345F), (float)Math.Exp(1.2345F));
45 | }
46 |
47 | [Fact]
48 | public void MathF_Floor_Is_Equal()
49 | {
50 | Assert.Equal(MathF.Floor(1.2345F), (float)Math.Floor(1.2345F));
51 | }
52 |
53 | [Fact]
54 | public void MathF_Min_Is_Equal()
55 | {
56 | Assert.Equal(MathF.Min(1.2345F, 5.4321F), (float)Math.Min(1.2345F, 5.4321F));
57 | }
58 |
59 | [Fact]
60 | public void MathF_Max_Is_Equal()
61 | {
62 | Assert.Equal(MathF.Max(1.2345F, 5.4321F), (float)Math.Max(1.2345F, 5.4321F));
63 | }
64 |
65 | [Fact]
66 | public void MathF_Pow_Is_Equal()
67 | {
68 | Assert.Equal(MathF.Pow(1.2345F, 5.4321F), (float)Math.Pow(1.2345F, 5.4321F));
69 | }
70 |
71 | [Fact]
72 | public void MathF_Round_Is_Equal()
73 | {
74 | Assert.Equal(MathF.Round(1.2345F), (float)Math.Round(1.2345F));
75 | }
76 |
77 | [Fact]
78 | public void MathF_Round_With_Midpoint_Is_Equal()
79 | {
80 | Assert.Equal(MathF.Round(1.2345F, MidpointRounding.AwayFromZero), (float)Math.Round(1.2345F, MidpointRounding.AwayFromZero));
81 | }
82 |
83 | [Fact]
84 | public void MathF_Sin_Is_Equal()
85 | {
86 | Assert.Equal(MathF.Sin(1.2345F), (float)Math.Sin(1.2345F));
87 | }
88 |
89 | [Fact]
90 | public void MathF_Sqrt_Is_Equal()
91 | {
92 | Assert.Equal(MathF.Sqrt(2F), (float)Math.Sqrt(2F));
93 | }
94 | }
95 | }
--------------------------------------------------------------------------------
/tests/SixLabors.Core.Tests/Memory/ArrayPoolMemoryAllocatorTests.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | // ReSharper disable InconsistentNaming
5 | using System;
6 | using System.Buffers;
7 | using System.Runtime.CompilerServices;
8 | using System.Runtime.InteropServices;
9 | using SixLabors.Tests;
10 | using Xunit;
11 |
12 | namespace SixLabors.Memory.Tests
13 | {
14 | public class ArrayPoolMemoryAllocatorTests
15 | {
16 | private const int MaxPooledBufferSizeInBytes = 2048;
17 |
18 | private const int PoolSelectorThresholdInBytes = MaxPooledBufferSizeInBytes / 2;
19 |
20 | private MemoryAllocator MemoryAllocator { get; set; } =
21 | new ArrayPoolMemoryAllocator(MaxPooledBufferSizeInBytes, PoolSelectorThresholdInBytes);
22 |
23 | ///
24 | /// Rent a buffer -> return it -> re-rent -> verify if it's span points to the previous location.
25 | ///
26 | private bool CheckIsRentingPooledBuffer(int length)
27 | where T : struct
28 | {
29 | IMemoryOwner buffer = this.MemoryAllocator.Allocate(length);
30 | ref T ptrToPrevPosition0 = ref buffer.GetReference();
31 | buffer.Dispose();
32 |
33 | buffer = this.MemoryAllocator.Allocate(length);
34 | bool sameBuffers = Unsafe.AreSame(ref ptrToPrevPosition0, ref buffer.GetReference());
35 | buffer.Dispose();
36 |
37 | return sameBuffers;
38 | }
39 |
40 | public class BufferTests : BufferTestSuite
41 | {
42 | public BufferTests()
43 | : base(new ArrayPoolMemoryAllocator(MaxPooledBufferSizeInBytes, PoolSelectorThresholdInBytes))
44 | {
45 | }
46 | }
47 |
48 | public class Constructor
49 | {
50 | [Fact]
51 | public void WhenBothParametersPassedByUser()
52 | {
53 | var mgr = new ArrayPoolMemoryAllocator(1111, 666);
54 | Assert.Equal(1111, mgr.MaxPoolSizeInBytes);
55 | Assert.Equal(666, mgr.PoolSelectorThresholdInBytes);
56 | }
57 |
58 | [Fact]
59 | public void WhenPassedOnly_MaxPooledBufferSizeInBytes_SmallerThresholdValueIsAutoCalculated()
60 | {
61 | var mgr = new ArrayPoolMemoryAllocator(5000);
62 | Assert.Equal(5000, mgr.MaxPoolSizeInBytes);
63 | Assert.True(mgr.PoolSelectorThresholdInBytes < mgr.MaxPoolSizeInBytes);
64 | }
65 |
66 | [Fact]
67 | public void When_PoolSelectorThresholdInBytes_IsGreaterThan_MaxPooledBufferSizeInBytes_ExceptionIsThrown()
68 | {
69 | Assert.ThrowsAny(() => new ArrayPoolMemoryAllocator(100, 200));
70 | }
71 | }
72 |
73 | [Theory]
74 | [InlineData(32)]
75 | [InlineData(512)]
76 | [InlineData(MaxPooledBufferSizeInBytes - 1)]
77 | public void SmallBuffersArePooled_OfByte(int size)
78 | {
79 | Assert.True(this.CheckIsRentingPooledBuffer(size));
80 | }
81 |
82 | [Theory]
83 | [InlineData(128 * 1024 * 1024)]
84 | [InlineData(MaxPooledBufferSizeInBytes + 1)]
85 | public void LargeBuffersAreNotPooled_OfByte(int size)
86 | {
87 | if (!TestEnvironment.Is64BitProcess)
88 | {
89 | // can lead to OutOfMemoryException
90 | return;
91 | }
92 |
93 | Assert.False(this.CheckIsRentingPooledBuffer(size));
94 | }
95 |
96 | [Fact]
97 | public unsafe void SmallBuffersArePooled_OfBigValueType()
98 | {
99 | int count = (MaxPooledBufferSizeInBytes / sizeof(LargeStruct)) - 1;
100 |
101 | Assert.True(this.CheckIsRentingPooledBuffer(count));
102 | }
103 |
104 | [Fact]
105 | public unsafe void LaregeBuffersAreNotPooled_OfBigValueType()
106 | {
107 | if (!TestEnvironment.Is64BitProcess)
108 | {
109 | // can lead to OutOfMemoryException
110 | return;
111 | }
112 |
113 | int count = (MaxPooledBufferSizeInBytes / sizeof(LargeStruct)) + 1;
114 |
115 | Assert.False(this.CheckIsRentingPooledBuffer(count));
116 | }
117 |
118 | [Theory]
119 | [InlineData(AllocationOptions.None)]
120 | [InlineData(AllocationOptions.Clean)]
121 | public void CleaningRequests_AreControlledByAllocationParameter_Clean(AllocationOptions options)
122 | {
123 | using (IMemoryOwner firstAlloc = this.MemoryAllocator.Allocate(42))
124 | {
125 | firstAlloc.GetSpan().Fill(666);
126 | }
127 |
128 | using (IMemoryOwner secondAlloc = this.MemoryAllocator.Allocate(42, options))
129 | {
130 | int expected = options == AllocationOptions.Clean ? 0 : 666;
131 | Assert.Equal(expected, secondAlloc.GetSpan()[0]);
132 | }
133 | }
134 |
135 | [Theory]
136 | [InlineData(false)]
137 | [InlineData(true)]
138 | public void ReleaseRetainedResources_ReplacesInnerArrayPool(bool keepBufferAlive)
139 | {
140 | IMemoryOwner buffer = this.MemoryAllocator.Allocate(32);
141 | ref int ptrToPrev0 = ref MemoryMarshal.GetReference(buffer.GetSpan());
142 |
143 | if (!keepBufferAlive)
144 | {
145 | buffer.Dispose();
146 | }
147 |
148 | this.MemoryAllocator.ReleaseRetainedResources();
149 |
150 | buffer = this.MemoryAllocator.Allocate(32);
151 |
152 | Assert.False(Unsafe.AreSame(ref ptrToPrev0, ref buffer.GetReference()));
153 | }
154 |
155 | [Fact]
156 | public void ReleaseRetainedResources_DisposingPreviouslyAllocatedBuffer_IsAllowed()
157 | {
158 | IMemoryOwner buffer = this.MemoryAllocator.Allocate(32);
159 | this.MemoryAllocator.ReleaseRetainedResources();
160 | buffer.Dispose();
161 | }
162 |
163 | [Fact]
164 | public void AllocationOverLargeArrayThreshold_UsesDifferentPool()
165 | {
166 | if (!TestEnvironment.Is64BitProcess)
167 | {
168 | // can lead to OutOfMemoryException
169 | return;
170 | }
171 |
172 | const int ArrayLengthThreshold = PoolSelectorThresholdInBytes / sizeof(int);
173 |
174 | IMemoryOwner small = this.MemoryAllocator.Allocate(ArrayLengthThreshold - 1);
175 | ref int ptr2Small = ref small.GetReference();
176 | small.Dispose();
177 |
178 | IMemoryOwner large = this.MemoryAllocator.Allocate(ArrayLengthThreshold + 1);
179 |
180 | Assert.False(Unsafe.AreSame(ref ptr2Small, ref large.GetReference()));
181 | }
182 |
183 | [Fact]
184 | public void CreateWithAggressivePooling()
185 | {
186 | if (!TestEnvironment.Is64BitProcess)
187 | {
188 | // can lead to OutOfMemoryException
189 | return;
190 | }
191 |
192 | this.MemoryAllocator = ArrayPoolMemoryAllocator.CreateWithAggressivePooling();
193 |
194 | Assert.True(this.CheckIsRentingPooledBuffer(4096 * 4096));
195 | }
196 |
197 | [Fact]
198 | public void CreateDefault()
199 | {
200 | if (!TestEnvironment.Is64BitProcess)
201 | {
202 | // can lead to OutOfMemoryException
203 | return;
204 | }
205 |
206 | this.MemoryAllocator = ArrayPoolMemoryAllocator.CreateDefault();
207 |
208 | Assert.False(this.CheckIsRentingPooledBuffer(2 * 4096 * 4096));
209 | Assert.True(this.CheckIsRentingPooledBuffer(2048 * 2048));
210 | }
211 |
212 | [Fact]
213 | public void CreateWithModeratePooling()
214 | {
215 | if (!TestEnvironment.Is64BitProcess)
216 | {
217 | // can lead to OutOfMemoryException
218 | return;
219 | }
220 |
221 | this.MemoryAllocator = ArrayPoolMemoryAllocator.CreateWithModeratePooling();
222 |
223 | Assert.False(this.CheckIsRentingPooledBuffer(2048 * 2048));
224 | Assert.True(this.CheckIsRentingPooledBuffer(1024 * 16));
225 | }
226 |
227 | [StructLayout(LayoutKind.Sequential)]
228 | private struct Rgba32
229 | {
230 | private readonly uint dummy;
231 | }
232 |
233 | private const int SizeOfLargeStruct = MaxPooledBufferSizeInBytes / 5;
234 |
235 | [StructLayout(LayoutKind.Explicit, Size = SizeOfLargeStruct)]
236 | private struct LargeStruct
237 | {
238 | }
239 |
240 | [Theory]
241 | [InlineData(-1)]
242 | [InlineData((int.MaxValue / SizeOfLargeStruct) + 1)]
243 | public void AllocateIncorrectAmount_ThrowsCorrect_ArgumentOutOfRangeException(int length)
244 | {
245 | ArgumentOutOfRangeException ex = Assert.Throws(() => this.MemoryAllocator.Allocate(length));
246 | Assert.Equal("length", ex.ParamName);
247 | }
248 |
249 | [Theory]
250 | [InlineData(-1)]
251 | public void AllocateManagedByteBuffer_IncorrectAmount_ThrowsCorrect_ArgumentOutOfRangeException(int length)
252 | {
253 | ArgumentOutOfRangeException ex = Assert.Throws(() => this.MemoryAllocator.AllocateManagedByteBuffer(length));
254 | Assert.Equal("length", ex.ParamName);
255 | }
256 | }
257 | }
258 |
--------------------------------------------------------------------------------
/tests/SixLabors.Core.Tests/Memory/BufferExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Buffers;
6 | using System.Runtime.CompilerServices;
7 | using System.Runtime.InteropServices;
8 |
9 | namespace SixLabors.Memory.Tests
10 | {
11 | internal static class BufferExtensions
12 | {
13 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
14 | public static Span GetSpan(this IMemoryOwner buffer)
15 | => buffer.Memory.Span;
16 |
17 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
18 | public static int Length(this IMemoryOwner buffer)
19 | => buffer.GetSpan().Length;
20 |
21 | public static ref T GetReference(this IMemoryOwner buffer)
22 | where T : struct =>
23 | ref MemoryMarshal.GetReference(buffer.GetSpan());
24 | }
25 | }
--------------------------------------------------------------------------------
/tests/SixLabors.Core.Tests/Memory/BufferTestSuite.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Buffers;
6 | using System.Runtime.CompilerServices;
7 | using System.Runtime.InteropServices;
8 | using Xunit;
9 |
10 | // ReSharper disable InconsistentNaming
11 | namespace SixLabors.Memory.Tests
12 | {
13 | ///
14 | /// Inherit this class to test an implementation (provided by ).
15 | ///
16 | public abstract class BufferTestSuite
17 | {
18 | protected BufferTestSuite(MemoryAllocator memoryAllocator)
19 | {
20 | this.MemoryAllocator = memoryAllocator;
21 | }
22 |
23 | protected MemoryAllocator MemoryAllocator { get; }
24 |
25 | public struct CustomStruct : IEquatable
26 | {
27 | public long A;
28 |
29 | public byte B;
30 |
31 | public float C;
32 |
33 | public CustomStruct(long a, byte b, float c)
34 | {
35 | this.A = a;
36 | this.B = b;
37 | this.C = c;
38 | }
39 |
40 | public bool Equals(CustomStruct other)
41 | {
42 | return this.A == other.A && this.B == other.B && this.C.Equals(other.C);
43 | }
44 |
45 | public override bool Equals(object obj)
46 | {
47 | return obj is CustomStruct other && this.Equals(other);
48 | }
49 |
50 | public override int GetHashCode()
51 | {
52 | unchecked
53 | {
54 | int hashCode = this.A.GetHashCode();
55 | hashCode = (hashCode * 397) ^ this.B.GetHashCode();
56 | hashCode = (hashCode * 397) ^ this.C.GetHashCode();
57 | return hashCode;
58 | }
59 | }
60 | }
61 |
62 | public static readonly TheoryData LenthValues = new TheoryData { 0, 1, 7, 1023, 1024 };
63 |
64 | [Theory]
65 | [MemberData(nameof(LenthValues))]
66 | public void HasCorrectLength_byte(int desiredLength)
67 | {
68 | this.TestHasCorrectLength(desiredLength);
69 | }
70 |
71 | [Theory]
72 | [MemberData(nameof(LenthValues))]
73 | public void HasCorrectLength_float(int desiredLength)
74 | {
75 | this.TestHasCorrectLength(desiredLength);
76 | }
77 |
78 | [Theory]
79 | [MemberData(nameof(LenthValues))]
80 | public void HasCorrectLength_CustomStruct(int desiredLength)
81 | {
82 | this.TestHasCorrectLength(desiredLength);
83 | }
84 |
85 | private void TestHasCorrectLength(int desiredLength)
86 | where T : struct
87 | {
88 | using (IMemoryOwner buffer = this.MemoryAllocator.Allocate(desiredLength))
89 | {
90 | Assert.Equal(desiredLength, buffer.GetSpan().Length);
91 | }
92 | }
93 |
94 | [Theory]
95 | [MemberData(nameof(LenthValues))]
96 | public void CanAllocateCleanBuffer_byte(int desiredLength)
97 | {
98 | this.TestCanAllocateCleanBuffer(desiredLength, false);
99 | this.TestCanAllocateCleanBuffer(desiredLength, true);
100 | }
101 |
102 | [Theory]
103 | [MemberData(nameof(LenthValues))]
104 | public void CanAllocateCleanBuffer_double(int desiredLength)
105 | {
106 | this.TestCanAllocateCleanBuffer(desiredLength);
107 | }
108 |
109 | [Theory]
110 | [MemberData(nameof(LenthValues))]
111 | public void CanAllocateCleanBuffer_CustomStruct(int desiredLength)
112 | {
113 | this.TestCanAllocateCleanBuffer(desiredLength);
114 | }
115 |
116 | private IMemoryOwner Allocate(int desiredLength, AllocationOptions options, bool managedByteBuffer)
117 | where T : struct
118 | {
119 | if (managedByteBuffer)
120 | {
121 | if (!(this.MemoryAllocator.AllocateManagedByteBuffer(desiredLength, options) is IMemoryOwner buffer))
122 | {
123 | throw new InvalidOperationException("typeof(T) != typeof(byte)");
124 | }
125 |
126 | return buffer;
127 | }
128 |
129 | return this.MemoryAllocator.Allocate(desiredLength, options);
130 | }
131 |
132 | private void TestCanAllocateCleanBuffer(int desiredLength, bool testManagedByteBuffer = false)
133 | where T : struct, IEquatable
134 | {
135 | ReadOnlySpan expected = new T[desiredLength];
136 |
137 | for (int i = 0; i < 10; i++)
138 | {
139 | using (IMemoryOwner buffer = this.Allocate(desiredLength, AllocationOptions.Clean, testManagedByteBuffer))
140 | {
141 | Assert.True(buffer.GetSpan().SequenceEqual(expected));
142 | }
143 | }
144 | }
145 |
146 | [Theory]
147 | [MemberData(nameof(LenthValues))]
148 | public void SpanPropertyIsAlwaysTheSame_int(int desiredLength)
149 | {
150 | this.TestSpanPropertyIsAlwaysTheSame(desiredLength);
151 | }
152 |
153 | [Theory]
154 | [MemberData(nameof(LenthValues))]
155 | public void SpanPropertyIsAlwaysTheSame_byte(int desiredLength)
156 | {
157 | this.TestSpanPropertyIsAlwaysTheSame(desiredLength, false);
158 | this.TestSpanPropertyIsAlwaysTheSame(desiredLength, true);
159 | }
160 |
161 | private void TestSpanPropertyIsAlwaysTheSame(int desiredLength, bool testManagedByteBuffer = false)
162 | where T : struct
163 | {
164 | using (IMemoryOwner buffer = this.Allocate(desiredLength, AllocationOptions.None, testManagedByteBuffer))
165 | {
166 | ref T a = ref MemoryMarshal.GetReference(buffer.GetSpan());
167 | ref T b = ref MemoryMarshal.GetReference(buffer.GetSpan());
168 | ref T c = ref MemoryMarshal.GetReference(buffer.GetSpan());
169 |
170 | Assert.True(Unsafe.AreSame(ref a, ref b));
171 | Assert.True(Unsafe.AreSame(ref b, ref c));
172 | }
173 | }
174 |
175 | [Theory]
176 | [MemberData(nameof(LenthValues))]
177 | public void WriteAndReadElements_float(int desiredLength)
178 | {
179 | this.TestWriteAndReadElements(desiredLength, x => x * 1.2f);
180 | }
181 |
182 | [Theory]
183 | [MemberData(nameof(LenthValues))]
184 | public void WriteAndReadElements_byte(int desiredLength)
185 | {
186 | this.TestWriteAndReadElements(desiredLength, x => (byte)(x + 1), false);
187 | this.TestWriteAndReadElements(desiredLength, x => (byte)(x + 1), true);
188 | }
189 |
190 | private void TestWriteAndReadElements(int desiredLength, Func getExpectedValue, bool testManagedByteBuffer = false)
191 | where T : struct
192 | {
193 | using (IMemoryOwner buffer = this.Allocate(desiredLength, AllocationOptions.None, testManagedByteBuffer))
194 | {
195 | T[] expectedVals = new T[buffer.Length()];
196 |
197 | for (int i = 0; i < buffer.Length(); i++)
198 | {
199 | Span span = buffer.GetSpan();
200 | expectedVals[i] = getExpectedValue(i);
201 | span[i] = expectedVals[i];
202 | }
203 |
204 | for (int i = 0; i < buffer.Length(); i++)
205 | {
206 | Span span = buffer.GetSpan();
207 | Assert.Equal(expectedVals[i], span[i]);
208 | }
209 | }
210 | }
211 |
212 | [Theory]
213 | [MemberData(nameof(LenthValues))]
214 | public void IndexingSpan_WhenOutOfRange_Throws_byte(int desiredLength)
215 | {
216 | this.TestIndexOutOfRangeShouldThrow(desiredLength, false);
217 | this.TestIndexOutOfRangeShouldThrow(desiredLength, true);
218 | }
219 |
220 | [Theory]
221 | [MemberData(nameof(LenthValues))]
222 | public void IndexingSpan_WhenOutOfRange_Throws_long(int desiredLength)
223 | {
224 | this.TestIndexOutOfRangeShouldThrow(desiredLength);
225 | }
226 |
227 | [Theory]
228 | [MemberData(nameof(LenthValues))]
229 | public void IndexingSpan_WhenOutOfRange_Throws_CustomStruct(int desiredLength)
230 | {
231 | this.TestIndexOutOfRangeShouldThrow(desiredLength);
232 | }
233 |
234 | private T TestIndexOutOfRangeShouldThrow(int desiredLength, bool testManagedByteBuffer = false)
235 | where T : struct, IEquatable
236 | {
237 | var dummy = default(T);
238 |
239 | using (IMemoryOwner buffer = this.Allocate(desiredLength, AllocationOptions.None, testManagedByteBuffer))
240 | {
241 | Assert.ThrowsAny(
242 | () =>
243 | {
244 | Span span = buffer.GetSpan();
245 | dummy = span[desiredLength];
246 | });
247 |
248 | Assert.ThrowsAny(
249 | () =>
250 | {
251 | Span span = buffer.GetSpan();
252 | dummy = span[desiredLength + 1];
253 | });
254 |
255 | Assert.ThrowsAny(
256 | () =>
257 | {
258 | Span span = buffer.GetSpan();
259 | dummy = span[desiredLength + 42];
260 | });
261 | }
262 |
263 | return dummy;
264 | }
265 |
266 | [Theory]
267 | [InlineData(1)]
268 | [InlineData(7)]
269 | [InlineData(1024)]
270 | [InlineData(6666)]
271 | public void ManagedByteBuffer_ArrayIsCorrect(int desiredLength)
272 | {
273 | using (IManagedByteBuffer buffer = this.MemoryAllocator.AllocateManagedByteBuffer(desiredLength))
274 | {
275 | ref byte array0 = ref buffer.Array[0];
276 | ref byte span0 = ref buffer.GetReference();
277 |
278 | Assert.True(Unsafe.AreSame(ref span0, ref array0));
279 | Assert.True(buffer.Array.Length >= buffer.GetSpan().Length);
280 | }
281 | }
282 |
283 | [Fact]
284 | public void GetMemory_ReturnsValidMemory()
285 | {
286 | using (IMemoryOwner buffer = this.MemoryAllocator.Allocate(42))
287 | {
288 | Span span0 = buffer.GetSpan();
289 | span0[10].A = 30;
290 | Memory memory = buffer.Memory;
291 |
292 | Assert.Equal(42, memory.Length);
293 | Span span1 = memory.Span;
294 |
295 | Assert.Equal(42, span1.Length);
296 | Assert.Equal(30, span1[10].A);
297 | }
298 | }
299 |
300 | [Fact]
301 | public unsafe void GetMemory_ResultIsPinnable()
302 | {
303 | using (IMemoryOwner buffer = this.MemoryAllocator.Allocate(42))
304 | {
305 | Span span0 = buffer.GetSpan();
306 | span0[10] = 30;
307 |
308 | Memory memory = buffer.Memory;
309 |
310 | using (MemoryHandle h = memory.Pin())
311 | {
312 | int* ptr = (int*)h.Pointer;
313 | Assert.Equal(30, ptr[10]);
314 | }
315 | }
316 | }
317 | }
318 | }
--------------------------------------------------------------------------------
/tests/SixLabors.Core.Tests/Memory/SimpleGcMemoryAllocatorTests.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Runtime.InteropServices;
6 | using Xunit;
7 |
8 | namespace SixLabors.Memory.Tests
9 | {
10 | public class SimpleGcMemoryAllocatorTests
11 | {
12 | public class BufferTests : BufferTestSuite
13 | {
14 | public BufferTests()
15 | : base(new SimpleGcMemoryAllocator())
16 | {
17 | }
18 | }
19 |
20 | protected SimpleGcMemoryAllocator MemoryAllocator { get; } = new SimpleGcMemoryAllocator();
21 |
22 | [Theory]
23 | [InlineData(-1)]
24 | public void Allocate_IncorrectAmount_ThrowsCorrect_ArgumentOutOfRangeException(int length)
25 | {
26 | ArgumentOutOfRangeException ex = Assert.Throws(() => this.MemoryAllocator.Allocate(length));
27 | Assert.Equal("length", ex.ParamName);
28 | }
29 |
30 | [Theory]
31 | [InlineData(-1)]
32 | public void AllocateManagedByteBuffer_IncorrectAmount_ThrowsCorrect_ArgumentOutOfRangeException(int length)
33 | {
34 | ArgumentOutOfRangeException ex = Assert.Throws(() => this.MemoryAllocator.AllocateManagedByteBuffer(length));
35 | Assert.Equal("length", ex.ParamName);
36 | }
37 |
38 | [StructLayout(LayoutKind.Explicit, Size = 512)]
39 | private struct BigStruct
40 | {
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/tests/SixLabors.Core.Tests/Primitives/PointFTests.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Globalization;
6 | using System.Numerics;
7 | using System.Reflection;
8 | using System.Runtime.CompilerServices;
9 | using Xunit;
10 |
11 | namespace SixLabors.Primitives.Tests
12 | {
13 | public class PointFTests
14 | {
15 | [Fact]
16 | public void CanReinterpretCastFromVector2()
17 | {
18 | var vector = new Vector2(1, 2);
19 |
20 | PointF point = Unsafe.As(ref vector);
21 |
22 | Assert.Equal(vector.X, point.X);
23 | Assert.Equal(vector.Y, point.Y);
24 | }
25 |
26 | [Fact]
27 | public void DefaultConstructorTest()
28 | {
29 | Assert.Equal(default, PointF.Empty);
30 | }
31 |
32 | [Theory]
33 | [InlineData(float.MaxValue, float.MinValue)]
34 | [InlineData(float.MinValue, float.MinValue)]
35 | [InlineData(float.MaxValue, float.MaxValue)]
36 | [InlineData(float.MinValue, float.MaxValue)]
37 | [InlineData(0.0, 0.0)]
38 | public void NonDefaultConstructorTest(float x, float y)
39 | {
40 | var p1 = new PointF(x, y);
41 |
42 | Assert.Equal(x, p1.X);
43 | Assert.Equal(y, p1.Y);
44 | }
45 |
46 | [Fact]
47 | public void IsEmptyDefaultsTest()
48 | {
49 | Assert.True(PointF.Empty.IsEmpty);
50 | Assert.True(default(PointF).IsEmpty);
51 | Assert.True(new PointF(0, 0).IsEmpty);
52 | }
53 |
54 | [Theory]
55 | [InlineData(float.MaxValue, float.MinValue)]
56 | [InlineData(float.MinValue, float.MinValue)]
57 | [InlineData(float.MaxValue, float.MaxValue)]
58 | public void IsEmptyRandomTest(float x, float y)
59 | {
60 | Assert.False(new PointF(x, y).IsEmpty);
61 | }
62 |
63 | [Theory]
64 | [InlineData(float.MaxValue, float.MinValue)]
65 | [InlineData(float.MinValue, float.MinValue)]
66 | [InlineData(float.MaxValue, float.MaxValue)]
67 | [InlineData(0, 0)]
68 | public void CoordinatesTest(float x, float y)
69 | {
70 | var p = new PointF(x, y);
71 | Assert.Equal(x, p.X);
72 | Assert.Equal(y, p.Y);
73 |
74 | p.X = 10;
75 | Assert.Equal(10, p.X);
76 |
77 | p.Y = -10.123f;
78 | Assert.Equal(-10.123, p.Y, 3);
79 | }
80 |
81 | [Theory]
82 | [InlineData(float.MaxValue, float.MinValue, int.MaxValue, int.MinValue)]
83 | [InlineData(float.MinValue, float.MaxValue, int.MinValue, int.MaxValue)]
84 | [InlineData(0, 0, 0, 0)]
85 | public void ArithmeticTestWithSize(float x, float y, int x1, int y1)
86 | {
87 | var p = new PointF(x, y);
88 | var s = new Size(x1, y1);
89 |
90 | var addExpected = new PointF(x + x1, y + y1);
91 | var subExpected = new PointF(x - x1, y - y1);
92 | Assert.Equal(addExpected, p + s);
93 | Assert.Equal(subExpected, p - s);
94 | Assert.Equal(addExpected, PointF.Add(p, s));
95 | Assert.Equal(subExpected, PointF.Subtract(p, s));
96 | }
97 |
98 | [Theory]
99 | [InlineData(float.MaxValue, float.MinValue)]
100 | [InlineData(float.MinValue, float.MaxValue)]
101 | [InlineData(0, 0)]
102 | public void ArithmeticTestWithSizeF(float x, float y)
103 | {
104 | var p = new PointF(x, y);
105 | var s = new SizeF(y, x);
106 |
107 | var addExpected = new PointF(x + y, y + x);
108 | var subExpected = new PointF(x - y, y - x);
109 | Assert.Equal(addExpected, p + s);
110 | Assert.Equal(subExpected, p - s);
111 | Assert.Equal(addExpected, PointF.Add(p, s));
112 | Assert.Equal(subExpected, PointF.Subtract(p, s));
113 | }
114 |
115 | [Fact]
116 | public void RotateTest()
117 | {
118 | var p = new PointF(13, 17);
119 | Matrix3x2 matrix = Matrix3x2Extensions.CreateRotationDegrees(45, PointF.Empty);
120 |
121 | var pout = PointF.Transform(p, matrix);
122 |
123 | Assert.Equal(new PointF(-2.82842732F, 21.2132034F), pout);
124 | }
125 |
126 | [Fact]
127 | public void SkewTest()
128 | {
129 | var p = new PointF(13, 17);
130 | Matrix3x2 matrix = Matrix3x2Extensions.CreateSkewDegrees(45, 45, PointF.Empty);
131 |
132 | var pout = PointF.Transform(p, matrix);
133 | Assert.Equal(new PointF(30, 30), pout);
134 | }
135 |
136 | [Theory]
137 | [InlineData(float.MaxValue, float.MinValue)]
138 | [InlineData(float.MinValue, float.MaxValue)]
139 | [InlineData(float.MinValue, float.MinValue)]
140 | [InlineData(float.MaxValue, float.MaxValue)]
141 | [InlineData(0, 0)]
142 | public void EqualityTest(float x, float y)
143 | {
144 | var pLeft = new PointF(x, y);
145 | var pRight = new PointF(y, x);
146 |
147 | if (x == y)
148 | {
149 | Assert.True(pLeft == pRight);
150 | Assert.False(pLeft != pRight);
151 | Assert.True(pLeft.Equals(pRight));
152 | Assert.True(pLeft.Equals((object)pRight));
153 | Assert.Equal(pLeft.GetHashCode(), pRight.GetHashCode());
154 | return;
155 | }
156 |
157 | Assert.True(pLeft != pRight);
158 | Assert.False(pLeft == pRight);
159 | Assert.False(pLeft.Equals(pRight));
160 | Assert.False(pLeft.Equals((object)pRight));
161 | }
162 |
163 | [Fact]
164 | public void EqualityTest_NotPointF()
165 | {
166 | var point = new PointF(0, 0);
167 | Assert.False(point.Equals(null));
168 | Assert.False(point.Equals(0));
169 |
170 | // If PointF implements IEquatable (e.g. in .NET Core), then structs that are implicitly
171 | // convertible to var can potentially be equal.
172 | // See https://github.com/dotnet/corefx/issues/5255.
173 | bool expectsImplicitCastToPointF = typeof(IEquatable).IsAssignableFrom(point.GetType());
174 | Assert.Equal(expectsImplicitCastToPointF, point.Equals(new Point(0, 0)));
175 |
176 | Assert.False(point.Equals((object)new Point(0, 0))); // No implicit cast
177 | }
178 |
179 | [Fact]
180 | public void GetHashCodeTest()
181 | {
182 | var point = new PointF(10, 10);
183 | Assert.Equal(point.GetHashCode(), new PointF(10, 10).GetHashCode());
184 | Assert.NotEqual(point.GetHashCode(), new PointF(20, 10).GetHashCode());
185 | Assert.NotEqual(point.GetHashCode(), new PointF(10, 20).GetHashCode());
186 | }
187 |
188 | [Fact]
189 | public void ToStringTest()
190 | {
191 | var p = new PointF(5.1F, -5.123F);
192 | Assert.Equal(string.Format(CultureInfo.CurrentCulture, "PointF [ X={0}, Y={1} ]", p.X, p.Y), p.ToString());
193 | }
194 |
195 | [Theory]
196 | [InlineData(float.MaxValue, float.MinValue)]
197 | [InlineData(float.MinValue, float.MinValue)]
198 | [InlineData(float.MaxValue, float.MaxValue)]
199 | [InlineData(0, 0)]
200 | public void DeconstructTest(float x, float y)
201 | {
202 | PointF p = new PointF(x, y);
203 |
204 | (float deconstructedX, float deconstructedY) = p;
205 |
206 | Assert.Equal(x, deconstructedX);
207 | Assert.Equal(y, deconstructedY);
208 | }
209 | }
210 | }
--------------------------------------------------------------------------------
/tests/SixLabors.Core.Tests/Primitives/PointTests.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Globalization;
6 | using System.Numerics;
7 | using Xunit;
8 |
9 | namespace SixLabors.Primitives.Tests
10 | {
11 | public class PointTests
12 | {
13 | [Fact]
14 | public void DefaultConstructorTest()
15 | {
16 | Assert.Equal(default, Point.Empty);
17 | }
18 |
19 | [Theory]
20 | [InlineData(int.MaxValue, int.MinValue)]
21 | [InlineData(int.MinValue, int.MinValue)]
22 | [InlineData(int.MaxValue, int.MaxValue)]
23 | [InlineData(0, 0)]
24 | public void NonDefaultConstructorTest(int x, int y)
25 | {
26 | var p1 = new Point(x, y);
27 | var p2 = new Point(new Size(x, y));
28 |
29 | Assert.Equal(p1, p2);
30 | }
31 |
32 | [Theory]
33 | [InlineData(int.MaxValue)]
34 | [InlineData(int.MinValue)]
35 | [InlineData(0)]
36 | public void SingleIntConstructorTest(int x)
37 | {
38 | var p1 = new Point(x);
39 | var p2 = new Point(unchecked((short)(x & 0xFFFF)), unchecked((short)((x >> 16) & 0xFFFF)));
40 |
41 | Assert.Equal(p1, p2);
42 | }
43 |
44 | [Fact]
45 | public void IsEmptyDefaultsTest()
46 | {
47 | Assert.True(Point.Empty.IsEmpty);
48 | Assert.True(default(Point).IsEmpty);
49 | Assert.True(new Point(0, 0).IsEmpty);
50 | }
51 |
52 | [Theory]
53 | [InlineData(int.MaxValue, int.MinValue)]
54 | [InlineData(int.MinValue, int.MinValue)]
55 | [InlineData(int.MaxValue, int.MaxValue)]
56 | public void IsEmptyRandomTest(int x, int y)
57 | {
58 | Assert.False(new Point(x, y).IsEmpty);
59 | }
60 |
61 | [Theory]
62 | [InlineData(int.MaxValue, int.MinValue)]
63 | [InlineData(int.MinValue, int.MinValue)]
64 | [InlineData(int.MaxValue, int.MaxValue)]
65 | [InlineData(0, 0)]
66 | public void CoordinatesTest(int x, int y)
67 | {
68 | var p = new Point(x, y);
69 | Assert.Equal(x, p.X);
70 | Assert.Equal(y, p.Y);
71 | }
72 |
73 | [Theory]
74 | [InlineData(int.MaxValue, int.MinValue)]
75 | [InlineData(int.MinValue, int.MinValue)]
76 | [InlineData(int.MaxValue, int.MaxValue)]
77 | [InlineData(0, 0)]
78 | public void PointFConversionTest(int x, int y)
79 | {
80 | PointF p = new Point(x, y);
81 | Assert.Equal(new PointF(x, y), p);
82 | }
83 |
84 | [Theory]
85 | [InlineData(int.MaxValue, int.MinValue)]
86 | [InlineData(int.MinValue, int.MinValue)]
87 | [InlineData(int.MaxValue, int.MaxValue)]
88 | [InlineData(0, 0)]
89 | public void SizeConversionTest(int x, int y)
90 | {
91 | var sz = (Size)new Point(x, y);
92 | Assert.Equal(new Size(x, y), sz);
93 | }
94 |
95 | [Theory]
96 | [InlineData(int.MaxValue, int.MinValue)]
97 | [InlineData(int.MinValue, int.MinValue)]
98 | [InlineData(int.MaxValue, int.MaxValue)]
99 | [InlineData(0, 0)]
100 | public void ArithmeticTest(int x, int y)
101 | {
102 | Point addExpected, subExpected, p = new Point(x, y);
103 | var s = new Size(y, x);
104 |
105 | unchecked
106 | {
107 | addExpected = new Point(x + y, y + x);
108 | subExpected = new Point(x - y, y - x);
109 | }
110 |
111 | Assert.Equal(addExpected, p + s);
112 | Assert.Equal(subExpected, p - s);
113 | Assert.Equal(addExpected, Point.Add(p, s));
114 | Assert.Equal(subExpected, Point.Subtract(p, s));
115 | }
116 |
117 | [Theory]
118 | [InlineData(float.MaxValue, float.MinValue)]
119 | [InlineData(float.MinValue, float.MinValue)]
120 | [InlineData(float.MaxValue, float.MaxValue)]
121 | [InlineData(0, 0)]
122 | public void PointFMathematicalTest(float x, float y)
123 | {
124 | var pf = new PointF(x, y);
125 | Point pCeiling, pTruncate, pRound;
126 |
127 | unchecked
128 | {
129 | pCeiling = new Point((int)MathF.Ceiling(x), (int)MathF.Ceiling(y));
130 | pTruncate = new Point((int)x, (int)y);
131 | pRound = new Point((int)MathF.Round(x), (int)MathF.Round(y));
132 | }
133 |
134 | Assert.Equal(pCeiling, Point.Ceiling(pf));
135 | Assert.Equal(pRound, Point.Round(pf));
136 | Assert.Equal(pTruncate, (Point)pf);
137 | }
138 |
139 | [Theory]
140 | [InlineData(int.MaxValue, int.MinValue)]
141 | [InlineData(int.MinValue, int.MinValue)]
142 | [InlineData(int.MaxValue, int.MaxValue)]
143 | [InlineData(0, 0)]
144 | public void OffsetTest(int x, int y)
145 | {
146 | var p1 = new Point(x, y);
147 | var p2 = new Point(y, x);
148 |
149 | p1.Offset(p2);
150 |
151 | Assert.Equal(unchecked(p2.X + p2.Y), p1.X);
152 | Assert.Equal(p1.X, p1.Y);
153 |
154 | p2.Offset(x, y);
155 | Assert.Equal(p1, p2);
156 | }
157 |
158 | [Fact]
159 | public void RotateTest()
160 | {
161 | var p = new Point(13, 17);
162 | Matrix3x2 matrix = Matrix3x2Extensions.CreateRotationDegrees(45, Point.Empty);
163 |
164 | var pout = Point.Transform(p, matrix);
165 |
166 | Assert.Equal(new Point(-3, 21), pout);
167 | }
168 |
169 | [Fact]
170 | public void SkewTest()
171 | {
172 | var p = new Point(13, 17);
173 | Matrix3x2 matrix = Matrix3x2Extensions.CreateSkewDegrees(45, 45, Point.Empty);
174 |
175 | var pout = Point.Transform(p, matrix);
176 | Assert.Equal(new Point(30, 30), pout);
177 | }
178 |
179 | [Theory]
180 | [InlineData(int.MaxValue, int.MinValue)]
181 | [InlineData(int.MinValue, int.MinValue)]
182 | [InlineData(int.MaxValue, int.MaxValue)]
183 | [InlineData(0, 0)]
184 | public void EqualityTest(int x, int y)
185 | {
186 | var p1 = new Point(x, y);
187 | var p2 = new Point((x / 2) - 1, (y / 2) - 1);
188 | var p3 = new Point(x, y);
189 |
190 | Assert.True(p1 == p3);
191 | Assert.True(p1 != p2);
192 | Assert.True(p2 != p3);
193 |
194 | Assert.True(p1.Equals(p3));
195 | Assert.False(p1.Equals(p2));
196 | Assert.False(p2.Equals(p3));
197 |
198 | Assert.True(p1.Equals((object)p3));
199 | Assert.False(p1.Equals((object)p2));
200 | Assert.False(p2.Equals((object)p3));
201 |
202 | Assert.Equal(p1.GetHashCode(), p3.GetHashCode());
203 | }
204 |
205 | [Fact]
206 | public void EqualityTest_NotPoint()
207 | {
208 | var point = new Point(0, 0);
209 | Assert.False(point.Equals(null));
210 | Assert.False(point.Equals(0));
211 | Assert.False(point.Equals(new PointF(0, 0)));
212 | }
213 |
214 | [Fact]
215 | public void GetHashCodeTest()
216 | {
217 | var point = new Point(10, 10);
218 | Assert.Equal(point.GetHashCode(), new Point(10, 10).GetHashCode());
219 | Assert.NotEqual(point.GetHashCode(), new Point(20, 10).GetHashCode());
220 | Assert.NotEqual(point.GetHashCode(), new Point(10, 20).GetHashCode());
221 | }
222 |
223 | [Theory]
224 | [InlineData(0, 0, 0, 0)]
225 | [InlineData(1, -2, 3, -4)]
226 | public void ConversionTest(int x, int y, int width, int height)
227 | {
228 | var rect = new Rectangle(x, y, width, height);
229 | RectangleF rectF = rect;
230 | Assert.Equal(x, rectF.X);
231 | Assert.Equal(y, rectF.Y);
232 | Assert.Equal(width, rectF.Width);
233 | Assert.Equal(height, rectF.Height);
234 | }
235 |
236 | [Fact]
237 | public void ToStringTest()
238 | {
239 | var p = new Point(5, -5);
240 | Assert.Equal(string.Format(CultureInfo.CurrentCulture, "Point [ X={0}, Y={1} ]", p.X, p.Y), p.ToString());
241 | }
242 |
243 | [Theory]
244 | [InlineData(int.MaxValue, int.MinValue)]
245 | [InlineData(int.MinValue, int.MinValue)]
246 | [InlineData(int.MaxValue, int.MaxValue)]
247 | [InlineData(0, 0)]
248 | public void DeconstructTest(int x, int y)
249 | {
250 | Point p = new Point(x, y);
251 |
252 | (int deconstructedX, int deconstructedY) = p;
253 |
254 | Assert.Equal(x, deconstructedX);
255 | Assert.Equal(y, deconstructedY);
256 | }
257 | }
258 | }
--------------------------------------------------------------------------------
/tests/SixLabors.Core.Tests/Primitives/RectangleFTests.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Globalization;
6 | using System.Reflection;
7 | using Xunit;
8 |
9 | namespace SixLabors.Primitives.Tests
10 | {
11 | ///
12 | /// Tests the struct.
13 | ///
14 | public class RectangleFTests
15 | {
16 | [Fact]
17 | public void DefaultConstructorTest()
18 | {
19 | Assert.Equal(default, RectangleF.Empty);
20 | }
21 |
22 | [Theory]
23 | [InlineData(0, 0, 0, 0)]
24 | [InlineData(float.MaxValue, float.MinValue, float.MinValue, float.MaxValue)]
25 | [InlineData(float.MaxValue, 0, 0, float.MaxValue)]
26 | [InlineData(0, float.MinValue, float.MaxValue, 0)]
27 | public void NonDefaultConstructorTest(float x, float y, float width, float height)
28 | {
29 | var rect1 = new RectangleF(x, y, width, height);
30 | var p = new PointF(x, y);
31 | var s = new SizeF(width, height);
32 | var rect2 = new RectangleF(p, s);
33 |
34 | Assert.Equal(rect1, rect2);
35 | }
36 |
37 | [Theory]
38 | [InlineData(0, 0, 0, 0)]
39 | [InlineData(float.MaxValue, float.MinValue, float.MinValue, float.MaxValue)]
40 | [InlineData(float.MaxValue, 0, 0, float.MaxValue)]
41 | [InlineData(0, float.MinValue, float.MaxValue, 0)]
42 | public void FromLTRBTest(float left, float top, float right, float bottom)
43 | {
44 | var expected = new RectangleF(left, top, right - left, bottom - top);
45 | var actual = RectangleF.FromLTRB(left, top, right, bottom);
46 |
47 | Assert.Equal(expected, actual);
48 | }
49 |
50 | [Theory]
51 | [InlineData(0, 0, 0, 0)]
52 | [InlineData(float.MaxValue, float.MinValue, float.MinValue, float.MaxValue)]
53 | [InlineData(float.MaxValue, 0, 0, float.MaxValue)]
54 | [InlineData(0, float.MinValue, float.MaxValue, 0)]
55 | public void DimensionsTest(float x, float y, float width, float height)
56 | {
57 | var rect = new RectangleF(x, y, width, height);
58 | var p = new PointF(x, y);
59 | var s = new SizeF(width, height);
60 |
61 | Assert.Equal(p, rect.Location);
62 | Assert.Equal(s, rect.Size);
63 | Assert.Equal(x, rect.X);
64 | Assert.Equal(y, rect.Y);
65 | Assert.Equal(width, rect.Width);
66 | Assert.Equal(height, rect.Height);
67 | Assert.Equal(x, rect.Left);
68 | Assert.Equal(y, rect.Top);
69 | Assert.Equal(x + width, rect.Right);
70 | Assert.Equal(y + height, rect.Bottom);
71 | }
72 |
73 | [Fact]
74 | public void IsEmptyTest()
75 | {
76 | Assert.True(RectangleF.Empty.IsEmpty);
77 | Assert.True(default(RectangleF).IsEmpty);
78 | Assert.True(new RectangleF(1, -2, -10, 10).IsEmpty);
79 | Assert.True(new RectangleF(1, -2, 10, -10).IsEmpty);
80 | Assert.True(new RectangleF(1, -2, 0, 0).IsEmpty);
81 |
82 | Assert.False(new RectangleF(0, 0, 10, 10).IsEmpty);
83 | }
84 |
85 | [Theory]
86 | [InlineData(0, 0)]
87 | [InlineData(float.MaxValue, float.MinValue)]
88 | public void LocationSetTest(float x, float y)
89 | {
90 | var point = new PointF(x, y);
91 | var rect = new RectangleF(10, 10, 10, 10) { Location = point };
92 | Assert.Equal(point, rect.Location);
93 | Assert.Equal(point.X, rect.X);
94 | Assert.Equal(point.Y, rect.Y);
95 | }
96 |
97 | [Theory]
98 | [InlineData(0, 0)]
99 | [InlineData(float.MaxValue, float.MinValue)]
100 | public void SizeSetTest(float x, float y)
101 | {
102 | var size = new SizeF(x, y);
103 | var rect = new RectangleF(10, 10, 10, 10) { Size = size };
104 | Assert.Equal(size, rect.Size);
105 | Assert.Equal(size.Width, rect.Width);
106 | Assert.Equal(size.Height, rect.Height);
107 | }
108 |
109 | [Theory]
110 | [InlineData(float.MaxValue, float.MinValue, float.MinValue, float.MaxValue)]
111 | [InlineData(float.MaxValue, 0, 0, float.MaxValue)]
112 | [InlineData(0, float.MinValue, float.MaxValue, 0)]
113 | public void EqualityTest(float x, float y, float width, float height)
114 | {
115 | var rect1 = new RectangleF(x, y, width, height);
116 | var rect2 = new RectangleF(width, height, x, y);
117 |
118 | Assert.True(rect1 != rect2);
119 | Assert.False(rect1 == rect2);
120 | Assert.False(rect1.Equals(rect2));
121 | Assert.False(rect1.Equals((object)rect2));
122 | }
123 |
124 | [Fact]
125 | public void EqualityTestNotRectangleF()
126 | {
127 | var rectangle = new RectangleF(0, 0, 0, 0);
128 | Assert.False(rectangle.Equals(null));
129 | Assert.False(rectangle.Equals(0));
130 |
131 | // If RectangleF implements IEquatable (e.g. in .NET Core), then classes that are implicitly
132 | // convertible to RectangleF can potentially be equal.
133 | // See https://github.com/dotnet/corefx/issues/5255.
134 | bool expectsImplicitCastToRectangleF = typeof(IEquatable).IsAssignableFrom(rectangle.GetType());
135 | Assert.Equal(expectsImplicitCastToRectangleF, rectangle.Equals(new Rectangle(0, 0, 0, 0)));
136 |
137 | Assert.False(rectangle.Equals((object)new Rectangle(0, 0, 0, 0))); // No implicit cast
138 | }
139 |
140 | [Fact]
141 | public void GetHashCodeTest()
142 | {
143 | var rect1 = new RectangleF(10, 10, 10, 10);
144 | var rect2 = new RectangleF(10, 10, 10, 10);
145 | Assert.Equal(rect1.GetHashCode(), rect2.GetHashCode());
146 | Assert.NotEqual(rect1.GetHashCode(), new RectangleF(20, 10, 10, 10).GetHashCode());
147 | Assert.NotEqual(rect1.GetHashCode(), new RectangleF(10, 20, 10, 10).GetHashCode());
148 | Assert.NotEqual(rect1.GetHashCode(), new RectangleF(10, 10, 20, 10).GetHashCode());
149 | Assert.NotEqual(rect1.GetHashCode(), new RectangleF(10, 10, 10, 20).GetHashCode());
150 | }
151 |
152 | [Theory]
153 | [InlineData(float.MaxValue, float.MinValue, float.MinValue, float.MaxValue)]
154 | [InlineData(0, float.MinValue, float.MaxValue, 0)]
155 | public void ContainsTest(float x, float y, float width, float height)
156 | {
157 | var rect = new RectangleF(x, y, width, height);
158 | float x1 = (x + width) / 2;
159 | float y1 = (y + height) / 2;
160 | var p = new PointF(x1, y1);
161 | var r = new RectangleF(x1, y1, width / 2, height / 2);
162 |
163 | Assert.False(rect.Contains(x1, y1));
164 | Assert.False(rect.Contains(p));
165 | Assert.False(rect.Contains(r));
166 | }
167 |
168 | [Theory]
169 | [InlineData(0, 0, 0, 0)]
170 | [InlineData(float.MaxValue / 2, float.MinValue / 2, float.MinValue / 2, float.MaxValue / 2)]
171 | [InlineData(0, float.MinValue, float.MaxValue, 0)]
172 | public void InflateTest(float x, float y, float width, float height)
173 | {
174 | var rect = new RectangleF(x, y, width, height);
175 | var inflatedRect = new RectangleF(x - width, y - height, width + (2 * width), height + (2 * height));
176 |
177 | rect.Inflate(width, height);
178 | Assert.Equal(inflatedRect, rect);
179 |
180 | var s = new SizeF(x, y);
181 | inflatedRect = RectangleF.Inflate(rect, x, y);
182 |
183 | rect.Inflate(s);
184 | Assert.Equal(inflatedRect, rect);
185 | }
186 |
187 | [Theory]
188 | [InlineData(float.MaxValue, float.MinValue, float.MaxValue / 2, float.MinValue / 2)]
189 | [InlineData(0, float.MinValue, float.MaxValue, 0)]
190 | public void IntersectTest(float x, float y, float width, float height)
191 | {
192 | var rect1 = new RectangleF(x, y, width, height);
193 | var rect2 = new RectangleF(y, x, width, height);
194 | var expectedRect = RectangleF.Intersect(rect1, rect2);
195 | rect1.Intersect(rect2);
196 | Assert.Equal(expectedRect, rect1);
197 | Assert.False(rect1.IntersectsWith(expectedRect));
198 | }
199 |
200 | [Fact]
201 | public void IntersectIntersectingRectsTest()
202 | {
203 | var rect1 = new RectangleF(0, 0, 5, 5);
204 | var rect2 = new RectangleF(1, 1, 3, 3);
205 | var expected = new RectangleF(1, 1, 3, 3);
206 |
207 | Assert.Equal(expected, RectangleF.Intersect(rect1, rect2));
208 | }
209 |
210 | [Theory]
211 | [InlineData(0, 0, 0, 0)]
212 | [InlineData(float.MaxValue, float.MinValue, float.MinValue, float.MaxValue)]
213 | [InlineData(float.MaxValue, 0, 0, float.MaxValue)]
214 | [InlineData(0, float.MinValue, float.MaxValue, 0)]
215 | public void UnionTest(float x, float y, float width, float height)
216 | {
217 | var a = new RectangleF(x, y, width, height);
218 | var b = new RectangleF(width, height, x, y);
219 |
220 | float x1 = Math.Min(a.X, b.X);
221 | float x2 = Math.Max(a.X + a.Width, b.X + b.Width);
222 | float y1 = Math.Min(a.Y, b.Y);
223 | float y2 = Math.Max(a.Y + a.Height, b.Y + b.Height);
224 |
225 | var expectedRectangle = new RectangleF(x1, y1, x2 - x1, y2 - y1);
226 |
227 | Assert.Equal(expectedRectangle, RectangleF.Union(a, b));
228 | }
229 |
230 | [Theory]
231 | [InlineData(0, 0, 0, 0)]
232 | [InlineData(float.MaxValue, float.MinValue, float.MinValue, float.MaxValue)]
233 | [InlineData(float.MaxValue, 0, 0, float.MaxValue)]
234 | [InlineData(0, float.MinValue, float.MaxValue, 0)]
235 | public void OffsetTest(float x, float y, float width, float height)
236 | {
237 | var r1 = new RectangleF(x, y, width, height);
238 | var expectedRect = new RectangleF(x + width, y + height, width, height);
239 | var p = new PointF(width, height);
240 |
241 | r1.Offset(p);
242 | Assert.Equal(expectedRect, r1);
243 |
244 | expectedRect.Offset(p);
245 | r1.Offset(width, height);
246 | Assert.Equal(expectedRect, r1);
247 | }
248 |
249 | [Fact]
250 | public void ToStringTest()
251 | {
252 | var r = new RectangleF(5, 5.1F, 1.3F, 1);
253 | Assert.Equal(string.Format(CultureInfo.CurrentCulture, "RectangleF [ X={0}, Y={1}, Width={2}, Height={3} ]", r.X, r.Y, r.Width, r.Height), r.ToString());
254 | }
255 |
256 | [Theory]
257 | [InlineData(float.MinValue, float.MaxValue, float.MaxValue, float.MaxValue)]
258 | [InlineData(float.MinValue, float.MaxValue, float.MaxValue, float.MinValue)]
259 | [InlineData(float.MinValue, float.MaxValue, float.MinValue, float.MaxValue)]
260 | [InlineData(float.MinValue, float.MaxValue, float.MinValue, float.MinValue)]
261 | [InlineData(float.MinValue, float.MinValue, float.MaxValue, float.MaxValue)]
262 | [InlineData(float.MinValue, float.MinValue, float.MaxValue, float.MinValue)]
263 | [InlineData(float.MinValue, float.MinValue, float.MinValue, float.MaxValue)]
264 | [InlineData(float.MinValue, float.MinValue, float.MinValue, float.MinValue)]
265 | [InlineData(float.MaxValue, float.MaxValue, float.MaxValue, float.MaxValue)]
266 | [InlineData(float.MaxValue, float.MaxValue, float.MaxValue, float.MinValue)]
267 | [InlineData(float.MaxValue, float.MaxValue, float.MinValue, float.MaxValue)]
268 | [InlineData(float.MaxValue, float.MaxValue, float.MinValue, float.MinValue)]
269 | [InlineData(float.MaxValue, float.MinValue, float.MaxValue, float.MaxValue)]
270 | [InlineData(float.MaxValue, float.MinValue, float.MaxValue, float.MinValue)]
271 | [InlineData(float.MaxValue, float.MinValue, float.MinValue, float.MaxValue)]
272 | [InlineData(float.MaxValue, float.MinValue, float.MinValue, float.MinValue)]
273 | [InlineData(0, 0, 0, 0)]
274 | public void DeconstructTest(float x, float y, float width, float height)
275 | {
276 | RectangleF r = new RectangleF(x, y, width, height);
277 |
278 | (float dx, float dy, float dw, float dh) = r;
279 |
280 | Assert.Equal(x, dx);
281 | Assert.Equal(y, dy);
282 | Assert.Equal(width, dw);
283 | Assert.Equal(height, dh);
284 | }
285 | }
286 | }
--------------------------------------------------------------------------------
/tests/SixLabors.Core.Tests/Primitives/SizeFTests.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Globalization;
6 | using System.Reflection;
7 | using Xunit;
8 |
9 | namespace SixLabors.Primitives.Tests
10 | {
11 | public class SizeFTests
12 | {
13 | [Fact]
14 | public void DefaultConstructorTest()
15 | {
16 | Assert.Equal(default, SizeF.Empty);
17 | }
18 |
19 | [Theory]
20 | [InlineData(float.MaxValue, float.MinValue)]
21 | [InlineData(float.MinValue, float.MinValue)]
22 | [InlineData(float.MaxValue, float.MaxValue)]
23 | [InlineData(0, 0)]
24 | public void NonDefaultConstructorAndDimensionsTest(float width, float height)
25 | {
26 | var s1 = new SizeF(width, height);
27 | var p1 = new PointF(width, height);
28 | var s2 = new SizeF(s1);
29 |
30 | Assert.Equal(s1, s2);
31 | Assert.Equal(s1, new SizeF(p1));
32 | Assert.Equal(s2, new SizeF(p1));
33 |
34 | Assert.Equal(width, s1.Width);
35 | Assert.Equal(height, s1.Height);
36 |
37 | s1.Width = 10;
38 | Assert.Equal(10, s1.Width);
39 |
40 | s1.Height = -10.123f;
41 | Assert.Equal(-10.123, s1.Height, 3);
42 | }
43 |
44 | [Fact]
45 | public void IsEmptyDefaultsTest()
46 | {
47 | Assert.True(SizeF.Empty.IsEmpty);
48 | Assert.True(default(SizeF).IsEmpty);
49 | Assert.True(new SizeF(0, 0).IsEmpty);
50 | }
51 |
52 | [Theory]
53 | [InlineData(float.MaxValue, float.MinValue)]
54 | [InlineData(float.MinValue, float.MinValue)]
55 | [InlineData(float.MaxValue, float.MaxValue)]
56 | public void IsEmptyRandomTest(float width, float height)
57 | {
58 | Assert.False(new SizeF(width, height).IsEmpty);
59 | }
60 |
61 | [Theory]
62 | [InlineData(float.MaxValue, float.MinValue)]
63 | [InlineData(float.MinValue, float.MinValue)]
64 | [InlineData(float.MaxValue, float.MaxValue)]
65 | [InlineData(0, 0)]
66 | public void ArithmeticTest(float width, float height)
67 | {
68 | var s1 = new SizeF(width, height);
69 | var s2 = new SizeF(height, width);
70 | var addExpected = new SizeF(width + height, width + height);
71 | var subExpected = new SizeF(width - height, height - width);
72 |
73 | Assert.Equal(addExpected, s1 + s2);
74 | Assert.Equal(addExpected, SizeF.Add(s1, s2));
75 |
76 | Assert.Equal(subExpected, s1 - s2);
77 | Assert.Equal(subExpected, SizeF.Subtract(s1, s2));
78 | }
79 |
80 | [Theory]
81 | [InlineData(float.MaxValue, float.MinValue)]
82 | [InlineData(float.MinValue, float.MinValue)]
83 | [InlineData(float.MaxValue, float.MaxValue)]
84 | [InlineData(0, 0)]
85 | public void EqualityTest(float width, float height)
86 | {
87 | var sLeft = new SizeF(width, height);
88 | var sRight = new SizeF(height, width);
89 |
90 | if (width == height)
91 | {
92 | Assert.True(sLeft == sRight);
93 | Assert.False(sLeft != sRight);
94 | Assert.True(sLeft.Equals(sRight));
95 | Assert.True(sLeft.Equals((object)sRight));
96 | Assert.Equal(sLeft.GetHashCode(), sRight.GetHashCode());
97 | return;
98 | }
99 |
100 | Assert.True(sLeft != sRight);
101 | Assert.False(sLeft == sRight);
102 | Assert.False(sLeft.Equals(sRight));
103 | Assert.False(sLeft.Equals((object)sRight));
104 | }
105 |
106 | [Fact]
107 | public void EqualityTest_NotSizeF()
108 | {
109 | var size = new SizeF(0, 0);
110 | Assert.False(size.Equals(null));
111 | Assert.False(size.Equals(0));
112 |
113 | // If SizeF implements IEquatable (e.g in .NET Core), then classes that are implicitly
114 | // convertible to SizeF can potentially be equal.
115 | // See https://github.com/dotnet/corefx/issues/5255.
116 | bool expectsImplicitCastToSizeF = typeof(IEquatable).IsAssignableFrom(size.GetType());
117 | Assert.Equal(expectsImplicitCastToSizeF, size.Equals(new Size(0, 0)));
118 |
119 | Assert.False(size.Equals((object)new Size(0, 0))); // No implicit cast
120 | }
121 |
122 | [Fact]
123 | public void GetHashCodeTest()
124 | {
125 | var size = new SizeF(10, 10);
126 | Assert.Equal(size.GetHashCode(), new SizeF(10, 10).GetHashCode());
127 | Assert.NotEqual(size.GetHashCode(), new SizeF(20, 10).GetHashCode());
128 | Assert.NotEqual(size.GetHashCode(), new SizeF(10, 20).GetHashCode());
129 | }
130 |
131 | [Theory]
132 | [InlineData(float.MaxValue, float.MinValue)]
133 | [InlineData(float.MinValue, float.MinValue)]
134 | [InlineData(float.MaxValue, float.MaxValue)]
135 | [InlineData(0, 0)]
136 | public void ConversionTest(float width, float height)
137 | {
138 | var s1 = new SizeF(width, height);
139 | var p1 = (PointF)s1;
140 | var s2 = new Size(unchecked((int)width), unchecked((int)height));
141 |
142 | Assert.Equal(new PointF(width, height), p1);
143 | Assert.Equal(p1, (PointF)s1);
144 | Assert.Equal(s2, (Size)s1);
145 | }
146 |
147 | [Fact]
148 | public void ToStringTest()
149 | {
150 | var sz = new SizeF(10, 5);
151 | Assert.Equal(string.Format(CultureInfo.CurrentCulture, "SizeF [ Width={0}, Height={1} ]", sz.Width, sz.Height), sz.ToString());
152 | }
153 |
154 | [Theory]
155 | [InlineData(1000.234f, 0.0f)]
156 | [InlineData(1000.234f, 1.0f)]
157 | [InlineData(1000.234f, 2400.933f)]
158 | [InlineData(1000.234f, float.MaxValue)]
159 | [InlineData(1000.234f, -1.0f)]
160 | [InlineData(1000.234f, -2400.933f)]
161 | [InlineData(1000.234f, float.MinValue)]
162 | [InlineData(float.MaxValue, 0.0f)]
163 | [InlineData(float.MaxValue, 1.0f)]
164 | [InlineData(float.MaxValue, 2400.933f)]
165 | [InlineData(float.MaxValue, float.MaxValue)]
166 | [InlineData(float.MaxValue, -1.0f)]
167 | [InlineData(float.MaxValue, -2400.933f)]
168 | [InlineData(float.MaxValue, float.MinValue)]
169 | [InlineData(float.MinValue, 0.0f)]
170 | [InlineData(float.MinValue, 1.0f)]
171 | [InlineData(float.MinValue, 2400.933f)]
172 | [InlineData(float.MinValue, float.MaxValue)]
173 | [InlineData(float.MinValue, -1.0f)]
174 | [InlineData(float.MinValue, -2400.933f)]
175 | [InlineData(float.MinValue, float.MinValue)]
176 | public void MultiplicationTest(float dimension, float multiplier)
177 | {
178 | SizeF sz1 = new SizeF(dimension, dimension);
179 | SizeF mulExpected;
180 |
181 | mulExpected = new SizeF(dimension * multiplier, dimension * multiplier);
182 |
183 | Assert.Equal(mulExpected, sz1 * multiplier);
184 | Assert.Equal(mulExpected, multiplier * sz1);
185 | }
186 |
187 | [Theory]
188 | [InlineData(1111.1111f, 2222.2222f, 3333.3333f)]
189 | public void MultiplicationTestWidthHeightMultiplier(float width, float height, float multiplier)
190 | {
191 | SizeF sz1 = new SizeF(width, height);
192 | SizeF mulExpected;
193 |
194 | mulExpected = new SizeF(width * multiplier, height * multiplier);
195 |
196 | Assert.Equal(mulExpected, sz1 * multiplier);
197 | Assert.Equal(mulExpected, multiplier * sz1);
198 | }
199 |
200 | [Theory]
201 | [InlineData(0.0f, 1.0f)]
202 | [InlineData(1.0f, 1.0f)]
203 | [InlineData(-1.0f, 1.0f)]
204 | [InlineData(1.0f, -1.0f)]
205 | [InlineData(-1.0f, -1.0f)]
206 | [InlineData(float.MaxValue, float.MaxValue)]
207 | [InlineData(float.MaxValue, float.MinValue)]
208 | [InlineData(float.MinValue, float.MaxValue)]
209 | [InlineData(float.MinValue, float.MinValue)]
210 | [InlineData(float.MaxValue, 1.0f)]
211 | [InlineData(float.MinValue, 1.0f)]
212 | [InlineData(float.MaxValue, -1.0f)]
213 | [InlineData(float.MinValue, -1.0f)]
214 | [InlineData(float.MinValue, 0.0f)]
215 | [InlineData(1.0f, float.MinValue)]
216 | [InlineData(1.0f, float.MaxValue)]
217 | [InlineData(-1.0f, float.MinValue)]
218 | [InlineData(-1.0f, float.MaxValue)]
219 | public void DivideTestSizeFloat(float dimension, float divisor)
220 | {
221 | SizeF size = new SizeF(dimension, dimension);
222 | SizeF expected = new SizeF(dimension / divisor, dimension / divisor);
223 | Assert.Equal(expected, size / divisor);
224 | }
225 |
226 | [Theory]
227 | [InlineData(-111.111f, 222.222f, 333.333f)]
228 | public void DivideTestSizeFloatWidthHeightDivisor(float width, float height, float divisor)
229 | {
230 | SizeF size = new SizeF(width, height);
231 | SizeF expected = new SizeF(width / divisor, height / divisor);
232 | Assert.Equal(expected, size / divisor);
233 | }
234 |
235 | [Theory]
236 | [InlineData(float.MaxValue, float.MinValue)]
237 | [InlineData(float.MinValue, float.MinValue)]
238 | [InlineData(float.MaxValue, float.MaxValue)]
239 | [InlineData(0, 0)]
240 | public void DeconstructTest(float width, float height)
241 | {
242 | SizeF s = new SizeF(width, height);
243 |
244 | (float deconstructedWidth, float deconstructedHeight) = s;
245 |
246 | Assert.Equal(width, deconstructedWidth);
247 | Assert.Equal(height, deconstructedHeight);
248 | }
249 | }
250 | }
--------------------------------------------------------------------------------
/tests/SixLabors.Core.Tests/Primitives/SizeTests.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 | using System.Globalization;
6 | using Xunit;
7 |
8 | namespace SixLabors.Primitives.Tests
9 | {
10 | ///
11 | /// Tests the struct.
12 | ///
13 | public class SizeTests
14 | {
15 | [Fact]
16 | public void DefaultConstructorTest()
17 | {
18 | Assert.Equal(default, Size.Empty);
19 | }
20 |
21 | [Theory]
22 | [InlineData(int.MaxValue, int.MinValue)]
23 | [InlineData(int.MinValue, int.MinValue)]
24 | [InlineData(int.MaxValue, int.MaxValue)]
25 | [InlineData(0, 0)]
26 | public void NonDefaultConstructorTest(int width, int height)
27 | {
28 | var s1 = new Size(width, height);
29 | var s2 = new Size(new Point(width, height));
30 |
31 | Assert.Equal(s1, s2);
32 |
33 | s1.Width = 10;
34 | Assert.Equal(10, s1.Width);
35 |
36 | s1.Height = -10;
37 | Assert.Equal(-10, s1.Height);
38 | }
39 |
40 | [Fact]
41 | public void IsEmptyDefaultsTest()
42 | {
43 | Assert.True(Size.Empty.IsEmpty);
44 | Assert.True(default(Size).IsEmpty);
45 | Assert.True(new Size(0, 0).IsEmpty);
46 | }
47 |
48 | [Theory]
49 | [InlineData(int.MaxValue, int.MinValue)]
50 | [InlineData(int.MinValue, int.MinValue)]
51 | [InlineData(int.MaxValue, int.MaxValue)]
52 | public void IsEmptyRandomTest(int width, int height)
53 | {
54 | Assert.False(new Size(width, height).IsEmpty);
55 | }
56 |
57 | [Theory]
58 | [InlineData(int.MaxValue, int.MinValue)]
59 | [InlineData(int.MinValue, int.MinValue)]
60 | [InlineData(int.MaxValue, int.MaxValue)]
61 | [InlineData(0, 0)]
62 | public void DimensionsTest(int width, int height)
63 | {
64 | var p = new Size(width, height);
65 | Assert.Equal(width, p.Width);
66 | Assert.Equal(height, p.Height);
67 | }
68 |
69 | [Theory]
70 | [InlineData(int.MaxValue, int.MinValue)]
71 | [InlineData(int.MinValue, int.MinValue)]
72 | [InlineData(int.MaxValue, int.MaxValue)]
73 | [InlineData(0, 0)]
74 | public void PointFConversionTest(int width, int height)
75 | {
76 | SizeF sz = new Size(width, height);
77 | Assert.Equal(new SizeF(width, height), sz);
78 | }
79 |
80 | [Theory]
81 | [InlineData(int.MaxValue, int.MinValue)]
82 | [InlineData(int.MinValue, int.MinValue)]
83 | [InlineData(int.MaxValue, int.MaxValue)]
84 | [InlineData(0, 0)]
85 | public void SizeConversionTest(int width, int height)
86 | {
87 | var sz = (Point)new Size(width, height);
88 | Assert.Equal(new Point(width, height), sz);
89 | }
90 |
91 | [Theory]
92 | [InlineData(int.MaxValue, int.MinValue)]
93 | [InlineData(int.MinValue, int.MinValue)]
94 | [InlineData(int.MaxValue, int.MaxValue)]
95 | [InlineData(0, 0)]
96 | public void ArithmeticTest(int width, int height)
97 | {
98 | var sz1 = new Size(width, height);
99 | var sz2 = new Size(height, width);
100 | Size addExpected, subExpected;
101 |
102 | unchecked
103 | {
104 | addExpected = new Size(width + height, height + width);
105 | subExpected = new Size(width - height, height - width);
106 | }
107 |
108 | Assert.Equal(addExpected, sz1 + sz2);
109 | Assert.Equal(subExpected, sz1 - sz2);
110 | Assert.Equal(addExpected, Size.Add(sz1, sz2));
111 | Assert.Equal(subExpected, Size.Subtract(sz1, sz2));
112 | }
113 |
114 | [Theory]
115 | [InlineData(float.MaxValue, float.MinValue)]
116 | [InlineData(float.MinValue, float.MinValue)]
117 | [InlineData(float.MaxValue, float.MaxValue)]
118 | [InlineData(0, 0)]
119 | public void PointFMathematicalTest(float width, float height)
120 | {
121 | var szF = new SizeF(width, height);
122 | Size pCeiling, pTruncate, pRound;
123 |
124 | unchecked
125 | {
126 | pCeiling = new Size((int)MathF.Ceiling(width), (int)MathF.Ceiling(height));
127 | pTruncate = new Size((int)width, (int)height);
128 | pRound = new Size((int)MathF.Round(width), (int)MathF.Round(height));
129 | }
130 |
131 | Assert.Equal(pCeiling, Size.Ceiling(szF));
132 | Assert.Equal(pRound, Size.Round(szF));
133 | Assert.Equal(pTruncate, (Size)szF);
134 | }
135 |
136 | [Theory]
137 | [InlineData(int.MaxValue, int.MinValue)]
138 | [InlineData(int.MinValue, int.MinValue)]
139 | [InlineData(int.MaxValue, int.MaxValue)]
140 | [InlineData(0, 0)]
141 | public void EqualityTest(int width, int height)
142 | {
143 | var p1 = new Size(width, height);
144 | var p2 = new Size(unchecked(width - 1), unchecked(height - 1));
145 | var p3 = new Size(width, height);
146 |
147 | Assert.True(p1 == p3);
148 | Assert.True(p1 != p2);
149 | Assert.True(p2 != p3);
150 |
151 | Assert.True(p1.Equals(p3));
152 | Assert.False(p1.Equals(p2));
153 | Assert.False(p2.Equals(p3));
154 |
155 | Assert.True(p1.Equals((object)p3));
156 | Assert.False(p1.Equals((object)p2));
157 | Assert.False(p2.Equals((object)p3));
158 |
159 | Assert.Equal(p1.GetHashCode(), p3.GetHashCode());
160 | }
161 |
162 | [Fact]
163 | public void EqualityTest_NotSize()
164 | {
165 | var size = new Size(0, 0);
166 | Assert.False(size.Equals(null));
167 | Assert.False(size.Equals(0));
168 | Assert.False(size.Equals(new SizeF(0, 0)));
169 | }
170 |
171 | [Fact]
172 | public void GetHashCodeTest()
173 | {
174 | var size = new Size(10, 10);
175 | Assert.Equal(size.GetHashCode(), new Size(10, 10).GetHashCode());
176 | Assert.NotEqual(size.GetHashCode(), new Size(20, 10).GetHashCode());
177 | Assert.NotEqual(size.GetHashCode(), new Size(10, 20).GetHashCode());
178 | }
179 |
180 | [Fact]
181 | public void ToStringTest()
182 | {
183 | var sz = new Size(10, 5);
184 | Assert.Equal(string.Format(CultureInfo.CurrentCulture, "Size [ Width={0}, Height={1} ]", sz.Width, sz.Height), sz.ToString());
185 | }
186 |
187 | [Theory]
188 | [InlineData(1000, 0)]
189 | [InlineData(1000, 1)]
190 | [InlineData(1000, 2400)]
191 | [InlineData(1000, int.MaxValue)]
192 | [InlineData(1000, -1)]
193 | [InlineData(1000, -2400)]
194 | [InlineData(1000, int.MinValue)]
195 | [InlineData(int.MaxValue, 0)]
196 | [InlineData(int.MaxValue, 1)]
197 | [InlineData(int.MaxValue, 2400)]
198 | [InlineData(int.MaxValue, int.MaxValue)]
199 | [InlineData(int.MaxValue, -1)]
200 | [InlineData(int.MaxValue, -2400)]
201 | [InlineData(int.MaxValue, int.MinValue)]
202 | [InlineData(int.MinValue, 0)]
203 | [InlineData(int.MinValue, 1)]
204 | [InlineData(int.MinValue, 2400)]
205 | [InlineData(int.MinValue, int.MaxValue)]
206 | [InlineData(int.MinValue, -1)]
207 | [InlineData(int.MinValue, -2400)]
208 | [InlineData(int.MinValue, int.MinValue)]
209 | public void MultiplicationTestSizeInt(int dimension, int multiplier)
210 | {
211 | Size sz1 = new Size(dimension, dimension);
212 | Size mulExpected;
213 |
214 | unchecked
215 | {
216 | mulExpected = new Size(dimension * multiplier, dimension * multiplier);
217 | }
218 |
219 | Assert.Equal(mulExpected, sz1 * multiplier);
220 | Assert.Equal(mulExpected, multiplier * sz1);
221 | }
222 |
223 | [Theory]
224 | [InlineData(1000, 2000, 3000)]
225 | public void MultiplicationTestSizeIntWidthHeightMultiplier(int width, int height, int multiplier)
226 | {
227 | Size sz1 = new Size(width, height);
228 | Size mulExpected;
229 |
230 | unchecked
231 | {
232 | mulExpected = new Size(width * multiplier, height * multiplier);
233 | }
234 |
235 | Assert.Equal(mulExpected, sz1 * multiplier);
236 | Assert.Equal(mulExpected, multiplier * sz1);
237 | }
238 |
239 | [Theory]
240 | [InlineData(1000, 0.0f)]
241 | [InlineData(1000, 1.0f)]
242 | [InlineData(1000, 2400.933f)]
243 | [InlineData(1000, float.MaxValue)]
244 | [InlineData(1000, -1.0f)]
245 | [InlineData(1000, -2400.933f)]
246 | [InlineData(1000, float.MinValue)]
247 | [InlineData(int.MaxValue, 0.0f)]
248 | [InlineData(int.MaxValue, 1.0f)]
249 | [InlineData(int.MaxValue, 2400.933f)]
250 | [InlineData(int.MaxValue, float.MaxValue)]
251 | [InlineData(int.MaxValue, -1.0f)]
252 | [InlineData(int.MaxValue, -2400.933f)]
253 | [InlineData(int.MaxValue, float.MinValue)]
254 | [InlineData(int.MinValue, 0.0f)]
255 | [InlineData(int.MinValue, 1.0f)]
256 | [InlineData(int.MinValue, 2400.933f)]
257 | [InlineData(int.MinValue, float.MaxValue)]
258 | [InlineData(int.MinValue, -1.0f)]
259 | [InlineData(int.MinValue, -2400.933f)]
260 | [InlineData(int.MinValue, float.MinValue)]
261 | public void MultiplicationTestSizeFloat(int dimension, float multiplier)
262 | {
263 | Size sz1 = new Size(dimension, dimension);
264 | SizeF mulExpected;
265 |
266 | mulExpected = new SizeF(dimension * multiplier, dimension * multiplier);
267 |
268 | Assert.Equal(mulExpected, sz1 * multiplier);
269 | Assert.Equal(mulExpected, multiplier * sz1);
270 | }
271 |
272 | [Theory]
273 | [InlineData(1000, 2000, 30.33f)]
274 | public void MultiplicationTestSizeFloatWidthHeightMultiplier(int width, int height, float multiplier)
275 | {
276 | Size sz1 = new Size(width, height);
277 | SizeF mulExpected;
278 |
279 | mulExpected = new SizeF(width * multiplier, height * multiplier);
280 |
281 | Assert.Equal(mulExpected, sz1 * multiplier);
282 | Assert.Equal(mulExpected, multiplier * sz1);
283 | }
284 |
285 | [Fact]
286 | public void DivideByZeroChecks()
287 | {
288 | Size size = new Size(100, 100);
289 | Assert.Throws(() => size / 0);
290 |
291 | SizeF expectedSizeF = new SizeF(float.PositiveInfinity, float.PositiveInfinity);
292 | Assert.Equal(expectedSizeF, size / 0.0f);
293 | }
294 |
295 | [Theory]
296 | [InlineData(0, 1)]
297 | [InlineData(1, 1)]
298 | [InlineData(-1, 1)]
299 | [InlineData(1, -1)]
300 | [InlineData(-1, -1)]
301 | [InlineData(int.MaxValue, int.MaxValue)]
302 | [InlineData(int.MaxValue, int.MinValue)]
303 | [InlineData(int.MinValue, int.MaxValue)]
304 | [InlineData(int.MinValue, int.MinValue)]
305 | [InlineData(int.MaxValue, 1)]
306 | [InlineData(int.MinValue, 1)]
307 | [InlineData(int.MaxValue, -1)]
308 | public void DivideTestSizeInt(int dimension, int divisor)
309 | {
310 | Size size = new Size(dimension, dimension);
311 | Size expected;
312 |
313 | expected = new Size(dimension / divisor, dimension / divisor);
314 |
315 | Assert.Equal(expected, size / divisor);
316 | }
317 |
318 | [Theory]
319 | [InlineData(1111, 2222, 3333)]
320 | public void DivideTestSizeIntWidthHeightDivisor(int width, int height, int divisor)
321 | {
322 | Size size = new Size(width, height);
323 | Size expected;
324 |
325 | expected = new Size(width / divisor, height / divisor);
326 |
327 | Assert.Equal(expected, size / divisor);
328 | }
329 |
330 | [Theory]
331 | [InlineData(0, 1.0f)]
332 | [InlineData(1, 1.0f)]
333 | [InlineData(-1, 1.0f)]
334 | [InlineData(1, -1.0f)]
335 | [InlineData(-1, -1.0f)]
336 | [InlineData(int.MaxValue, float.MaxValue)]
337 | [InlineData(int.MaxValue, float.MinValue)]
338 | [InlineData(int.MinValue, float.MaxValue)]
339 | [InlineData(int.MinValue, float.MinValue)]
340 | [InlineData(int.MaxValue, 1.0f)]
341 | [InlineData(int.MinValue, 1.0f)]
342 | [InlineData(int.MaxValue, -1.0f)]
343 | [InlineData(int.MinValue, -1.0f)]
344 | public void DivideTestSizeFloat(int dimension, float divisor)
345 | {
346 | SizeF size = new SizeF(dimension, dimension);
347 | SizeF expected;
348 |
349 | expected = new SizeF(dimension / divisor, dimension / divisor);
350 | Assert.Equal(expected, size / divisor);
351 | }
352 |
353 | [Theory]
354 | [InlineData(1111, 2222, -333.33f)]
355 | public void DivideTestSizeFloatWidthHeightDivisor(int width, int height, float divisor)
356 | {
357 | SizeF size = new SizeF(width, height);
358 | SizeF expected;
359 |
360 | expected = new SizeF(width / divisor, height / divisor);
361 | Assert.Equal(expected, size / divisor);
362 | }
363 |
364 | [Theory]
365 | [InlineData(int.MaxValue, int.MinValue)]
366 | [InlineData(int.MinValue, int.MinValue)]
367 | [InlineData(int.MaxValue, int.MaxValue)]
368 | [InlineData(0, 0)]
369 | public void DeconstructTest(int width, int height)
370 | {
371 | Size s = new Size(width, height);
372 |
373 | (int deconstructedWidth, int deconstructedHeight) = s;
374 |
375 | Assert.Equal(width, deconstructedWidth);
376 | Assert.Equal(height, deconstructedHeight);
377 | }
378 | }
379 | }
--------------------------------------------------------------------------------
/tests/SixLabors.Core.Tests/SixLabors.Core.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 0.0.0
5 | netcoreapp1.1;netcoreapp2.1;
6 | SixLabors.Core.Tests
7 | SixLabors.Shapes.Tests
8 | true
9 | false
10 | false
11 | false
12 | false
13 | false
14 | false
15 | full
16 | SixLabors.Tests
17 | true
18 | 7.3
19 |
20 |
21 |
22 | ..\..\shared-infrastructure\SixLabors.Tests.ruleset
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | all
32 | runtime; build; native; contentfiles; analyzers; buildtransitive
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/tests/SixLabors.Core.Tests/TestEnvironment.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Six Labors and contributors.
2 | // Licensed under the Apache License, Version 2.0.
3 |
4 | using System;
5 |
6 | namespace SixLabors.Tests
7 | {
8 | internal class TestEnvironment
9 | {
10 | internal static bool Is64BitProcess => IntPtr.Size == 8;
11 | }
12 | }
--------------------------------------------------------------------------------
/tests/SixLabors.ruleset:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------