commit a6642911d7bbfaf4294eb36cce7238c63b2f267b Author: Edgaru089 Date: Thu Feb 29 09:48:29 2024 +0800 Initial commit diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9491a2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,363 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd \ No newline at end of file diff --git a/JacksEscape.sln b/JacksEscape.sln new file mode 100644 index 0000000..acea00e --- /dev/null +++ b/JacksEscape.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34622.214 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JacksEscape", "JacksEscape.vcxproj", "{C7225F7B-40C6-4C57-98A9-F7D751A53D28}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C7225F7B-40C6-4C57-98A9-F7D751A53D28}.Debug|x64.ActiveCfg = Debug|x64 + {C7225F7B-40C6-4C57-98A9-F7D751A53D28}.Debug|x64.Build.0 = Debug|x64 + {C7225F7B-40C6-4C57-98A9-F7D751A53D28}.Debug|x86.ActiveCfg = Debug|Win32 + {C7225F7B-40C6-4C57-98A9-F7D751A53D28}.Debug|x86.Build.0 = Debug|Win32 + {C7225F7B-40C6-4C57-98A9-F7D751A53D28}.Release|x64.ActiveCfg = Release|x64 + {C7225F7B-40C6-4C57-98A9-F7D751A53D28}.Release|x64.Build.0 = Release|x64 + {C7225F7B-40C6-4C57-98A9-F7D751A53D28}.Release|x86.ActiveCfg = Release|Win32 + {C7225F7B-40C6-4C57-98A9-F7D751A53D28}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {366A3442-CF71-45E8-9C4F-D2BCB7223B10} + EndGlobalSection +EndGlobal diff --git a/JacksEscape.vcxproj b/JacksEscape.vcxproj new file mode 100644 index 0000000..a9c53ef --- /dev/null +++ b/JacksEscape.vcxproj @@ -0,0 +1,144 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {c7225f7b-40c6-4c57-98a9-f7d751a53d28} + JacksEscape + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/JacksEscape.vcxproj.filters b/JacksEscape.vcxproj.filters new file mode 100644 index 0000000..3f5ce82 --- /dev/null +++ b/JacksEscape.vcxproj.filters @@ -0,0 +1,48 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {81dbe199-c614-445b-8e13-b76101c45c5e} + + + + + Util + + + Util + + + Util + + + Util + + + Util + + + + + Util + + + Util + + + Util + + + \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..8aa2645 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) [year] [fullname] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/_clang-format b/_clang-format new file mode 100644 index 0000000..6dbc1b9 --- /dev/null +++ b/_clang-format @@ -0,0 +1,64 @@ +--- +AccessModifierOffset: '-4' +AlignAfterOpenBracket: AlwaysBreak +AlignConsecutiveMacros: 'true' +AlignConsecutiveAssignments: 'true' +AlignConsecutiveDeclarations: 'true' +AlignEscapedNewlines: Left +AlignOperands: 'true' +AlignTrailingComments: 'true' +AllowAllArgumentsOnNextLine: 'true' +AllowAllConstructorInitializersOnNextLine: 'true' +AllowAllParametersOfDeclarationOnNextLine: 'true' +AllowShortBlocksOnASingleLine: 'true' +AllowShortCaseLabelsOnASingleLine: 'true' +AllowShortFunctionsOnASingleLine: 'true' +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: 'true' +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: 'false' +AlwaysBreakTemplateDeclarations: 'Yes' +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeTernaryOperators: 'false' +BreakStringLiterals: 'true' +ColumnLimit: '0' +CompactNamespaces: 'false' +ConstructorInitializerAllOnOneLineOrOnePerLine: 'true' +FixNamespaceComments: 'true' +IncludeBlocks: Preserve +IndentCaseLabels: 'true' +IndentGotoLabels: 'false' +IndentPPDirectives: None +IndentWidth: '4' +IndentWrappedFunctionNames: 'true' +KeepEmptyLinesAtTheStartOfBlocks: 'false' +Language: Cpp +MaxEmptyLinesToKeep: '2' +NamespaceIndentation: None +PenaltyReturnTypeOnItsOwnLine: '1000' +PointerAlignment: Right +ReflowComments: 'true' +SortIncludes: 'false' +SortUsingDeclarations: 'false' +SpaceAfterCStyleCast: 'false' +SpaceAfterLogicalNot: 'false' +SpaceAfterTemplateKeyword: 'false' +SpaceBeforeAssignmentOperators: 'true' +SpaceBeforeCpp11BracedList: 'false' +SpaceBeforeCtorInitializerColon: 'false' +SpaceBeforeInheritanceColon: 'false' +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: 'false' +SpaceInEmptyParentheses: 'false' +SpacesBeforeTrailingComments: '1' +SpacesInAngles: 'false' +SpacesInCStyleCastParentheses: 'false' +SpacesInContainerLiterals: 'false' +SpacesInParentheses: 'false' +SpacesInSquareBrackets: 'false' +Standard: Cpp11 +TabWidth: '4' +UseTab: ForContinuationAndIndentation +... diff --git a/util/minmax.h b/util/minmax.h new file mode 100644 index 0000000..1b52a8d --- /dev/null +++ b/util/minmax.h @@ -0,0 +1,43 @@ +#pragma once + + +static inline int intmin(int x, int y) { + return x < y ? x : y; +} + +static inline int intmax(int x, int y) { + return x > y ? x : y; +} + +static inline int intmin3(int x, int y, int z) { + if (x < y) + if (x < z) + return x; + else + return z; + else if (y < z) + return y; + else + return z; +} + +static inline int intmax3(int x, int y, int z) { + if (x > y) + if (x > z) + return x; + else + return z; + else if (y > z) + return y; + else + return z; +} + +static inline int intminmax(int x, int min, int max) { + if (x < min) + return min; + else if (x > max) + return max; + else + return x; +} diff --git a/util/queue.c b/util/queue.c new file mode 100644 index 0000000..94f9b6b --- /dev/null +++ b/util/queue.c @@ -0,0 +1,72 @@ + +#include "queue.h" + +#include + + +void queue_InitBuffered(queue *q, void *buffer, uintptr_t size) { + q->data = q->begin = q->end = buffer; + q->size = size; + q->count = 0; +} + +void queue_PushByte(queue *q, const uint8_t b) { + if (q->count == q->size) { // no more space + fprintf(stderr, "queue_PushByte: full[%llu bytes], discarding byte 0x%x\n", q->size, b); + return; + } + + q->count++; + *((uint8_t *)(q->end++)) = b; + if (q->end == q->data + q->size) + q->end = q->data; // out of the buffer: wrap around +} + +uint8_t queue_PopByte(queue *q) { + if (q->count == 0) { + fprintf(stderr, "queue_PopByte: poping an empty queue\n"); + return 0; + } + + q->count--; + uint8_t data = *((uint8_t *)(q->begin++)); + if (q->begin == q->data + q->size) + q->begin = q->data; // wrap around + return data; +} + +void queue_Push(queue *q, const void *buffer, uintptr_t size) { + // TODO Optimize queue_Push and queue_Pop + if (queue_Space(q) < size) + return; + for (const uint8_t *i = buffer; i < (const uint8_t *)buffer + size; i++) + queue_PushByte(q, *i); +} + +uintptr_t queue_Pop(queue *q, void *buffer, uintptr_t size) { + if (queue_Size(q) < size) + return 0; + for (uint8_t *i = buffer; i < (uint8_t *)buffer + size; i++) + *i = queue_PopByte(q); + return size; +} + +uint8_t queue_FrontByte(queue *q) { + if (q->count == 0) { + fprintf(stderr, "queue_TopByte: accessing an empty queue\n"); + return 0; + } + return *((uint8_t *)q->begin); +} + +bool queue_Empty(queue *q) { + return q->count == 0; +} + +uintptr_t queue_Size(queue *q) { + return q->count; +} + +uintptr_t queue_Space(queue *q) { + return q->size - q->count; +} diff --git a/util/queue.h b/util/queue.h new file mode 100644 index 0000000..7c9a7c2 --- /dev/null +++ b/util/queue.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct { + uint8_t *data; // the data buffer + uintptr_t size; // size of data buffer + uint8_t *begin, *end; // begin and past-the-end for in-queue data + uintptr_t count; // number of in-queue bytes +} queue; + +// initialize a queue with a existing buffer +void queue_InitBuffered(queue *q, void *buffer, uintptr_t size); + +// writes one byte to the queue, discarding if full +void queue_PushByte(queue *q, const uint8_t b); + +// pops one byte from the front of the queue, returning it +uint8_t queue_PopByte(queue *q); + +// write Size bytes to the queue, none written if there is not space for all the bytes +void queue_Push(queue *q, const void *buffer, uintptr_t size); + +// pops Size bytes from the queue, none popped if there are no enough data +// returns the number of bytes popped (either Size or 0) +uintptr_t queue_Pop(queue *q, void *buffer, uintptr_t size); + +// return the byte at the front of the queue +uint8_t queue_FrontByte(queue *q); + +// tells if the queue is empty +bool queue_Empty(queue *q); + +// returns the number of bytes in the queue +uintptr_t queue_Size(queue *q); + +// returns the empty space left at the end of the queue +uintptr_t queue_Space(queue *q); + + +#ifdef __cplusplus +} +#endif diff --git a/util/tree.c b/util/tree.c new file mode 100644 index 0000000..293ac45 --- /dev/null +++ b/util/tree.c @@ -0,0 +1,176 @@ + +#include "tree.h" +#include "tree_internal.h" + +#include +#include + + +// Create allocates and creates a new default Tree object. +tree_Tree *tree_Create(uintptr_t objectSize) { + tree_Tree *t = malloc(sizeof(tree_Tree)); + t->objectSize = objectSize; + t->size = 0; + t->root = 0; + return t; +} + + +static inline tree_Node *__tree_NewNode(tree_Tree *t, uintptr_t key, tree_Node *father, uintptr_t internal) { + t->size++; + + tree_Node *node = malloc(sizeof(tree_Node) - 1 + t->objectSize); + node->left = node->right = 0; + node->father = father; + node->key = key; + node->internal = internal; + return node; +} + +static void __tree_DestroyNodes(tree_Node *node) { + if (node->left) + __tree_DestroyNodes(node->left); + if (node->right) + __tree_DestroyNodes(node->right); + free(node); +} + +void tree_Destroy(tree_Tree *tree) { + if (tree->root) + __tree_DestroyNodes(tree->root); + free(tree); +} + + +// Will not return NULL +tree_Node *__tree_InsertNodes(tree_Tree *t, tree_Node *node, tree_Node *father, uintptr_t key, tree_Node **result, bool *added) { + if (!node) { + if (added) + *added = true; +#ifdef HELOS_UTIL_TREE_TYPE_TREAP + return *result = __tree_NewNode(t, key, father, random_Rand() ^ key); +#else + return *result = __tree_NewNode(t, key, father, 0); +#endif + } else if (key < node->key) { + node->left = __tree_InsertNodes(t, node->left, node, key, result, added); + return node; + } else if (key > node->key) { + node->right = __tree_InsertNodes(t, node->right, node, key, result, added); + return node; + } else { + if (added) + *added = false; + *result = node; + return node; + } +} + +tree_Node *tree_InsertNode(tree_Tree *t, uintptr_t key, bool *added) { + tree_Node *result; + t->root = __tree_InsertNodes(t, t->root, 0, key, &result, added); + +#ifdef HELOS_UTIL_TREE_TYPE_TREAP + if (*added) + __tree_treap_Adjust(result, &t->root); +#endif + + return result; +} + +void *tree_Insert(tree_Tree *t, uintptr_t key, bool *added) { + return tree_InsertNode(t, key, added)->data; +} + + +static tree_Node *__tree_FindNode(tree_Node *node, uintptr_t key) { + if (!node) + return NULL; + else if (key < node->key) + return __tree_FindNode(node->left, key); + else if (key > node->key) + return __tree_FindNode(node->right, key); + else + return node; +} + +tree_Node *tree_FindNode(tree_Tree *t, uintptr_t key) { + return __tree_FindNode(t->root, key); +} + +void *tree_Find(tree_Tree *t, uintptr_t key) { + tree_Node *node = tree_FindNode(t, key); + if (!node) + return NULL; + else + return node->data; +} + + +void tree_Delete(tree_Tree *t, tree_Node *node) { +#ifdef HELOS_UTIL_TREE_TYPE_TREAP + while (node->left && node->right) + if (node->left->internal < node->right->internal) + __tree_Rotate(node->left, &t->root); + else + __tree_Rotate(node->right, &t->root); +#else + while (node->left) + __tree_Rotate(node->left, &t->root); +#endif + + if (node == t->root) + t->root = (node->left ? node->left : node->right); + __tree_Connect(node->father, (node->left ? node->left : node->right), __tree_Tell(node)); + + free(node); +} + + +tree_Node *tree_FirstNode(tree_Tree *tree) { + tree_Node *result = tree->root; + if (!result) + return 0; + while (result->right) + result = result->left; + return result; +} + +tree_Node *tree_LastNode(tree_Tree *tree) { + tree_Node *result = tree->root; + if (!result) + return 0; + while (result->right) + result = result->right; + return result; +} + + +tree_Node *tree_Node_Next(tree_Node *node) { + if (node->right) { + tree_Node *result = node->right; + while (result->left) + result = result->left; + return result; + } else { + tree_Node *result = node; + while (result->father && __tree_Tell(result) == __tree_Right) + result = result->father; + return result->father; + } +} + +// Node_Previous returns the previous node. Returns NULL if first. +tree_Node *tree_Node_Previous(tree_Node *node) { + if (node->left) { + tree_Node *result = node->left; + while (result->right) + result = result->right; + return result; + } else { + tree_Node *result = node; + while (result->father && __tree_Tell(result) == __tree_Left) + result = result->father; + return result->father; + } +} diff --git a/util/tree.h b/util/tree.h new file mode 100644 index 0000000..b8679f7 --- /dev/null +++ b/util/tree.h @@ -0,0 +1,75 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct __tree_Node { + uintptr_t key; // node key + struct __tree_Node *left, *right; // left and right sons + struct __tree_Node *father; // father node + uintptr_t internal; // internal data for balanced trees + char data[1]; // placeholder for object data +} tree_Node; + +// Tree is a basic tree-based associative container. +// +// Right now it's a Treap. +typedef struct { + uintptr_t objectSize; // size in bytes of the object + tree_Node *root; // root of the tree, NULL if empty + uintptr_t size; // number of objects in the tree +} tree_Tree; + +// Create allocates and creates a new default Tree object. +tree_Tree *tree_Create(uintptr_t objectSize); + +// Destroy properly frees all data related to the structure, and itself. +void tree_Destroy(tree_Tree *tree); + +// Insert inserts a new object (or locates an existing one). +// +// If *added is not NULL, it is set to true if the key does +// not exist and is actually added. +// +// Newly allocated data is not zeroed, nor initialized in any way. +// +// Returns the pointer to the newly allocated (or existing) data. +void *tree_Insert(tree_Tree *tree, uintptr_t key, bool *added); + +// InsertNode does the same as Insert, but returns Node* instead of data. +tree_Node *tree_InsertNode(tree_Tree *tree, uintptr_t key, bool *added); + +// Find locates an existing object by its key. +// +// Returns NULL if the object does not exist. +void *tree_Find(tree_Tree *tree, uintptr_t key); + +// FindNode returns an existing tree node by its key. +// +// Used for iterating the tree objects. +tree_Node *tree_FindNode(tree_Tree *tree, uintptr_t key); + +// FirstNode returns the first node in increasing order. +tree_Node *tree_FirstNode(tree_Tree *tree); + +// LastNode returns the last node in increasing order. +tree_Node *tree_LastNode(tree_Tree *tree); + +// Delete deletes an existing node from the tree. +void tree_Delete(tree_Tree *tree, tree_Node *node); + +// Node_Next returns the next node. Returns NULL if the node is the last. +tree_Node *tree_Node_Next(tree_Node *node); + +// Node_Previous returns the previous node. Returns NULL if first. +tree_Node *tree_Node_Previous(tree_Node *node); + + +#ifdef __cplusplus +} +#endif diff --git a/util/tree_internal.h b/util/tree_internal.h new file mode 100644 index 0000000..207cd35 --- /dev/null +++ b/util/tree_internal.h @@ -0,0 +1,60 @@ +#pragma once + +#include "tree.h" + + +typedef enum { + __tree_Left, + __tree_Right, +} __tree_ConnectType; + +static inline __tree_ConnectType __tree_ConnectType_Invert(__tree_ConnectType type) { + return (__tree_ConnectType)(!type); +} + +static inline __tree_ConnectType __tree_Tell(tree_Node *son) { + if (!son->father) + return __tree_Left; + if (son->father->left == son) + return __tree_Left; + else + return __tree_Right; +} + +static inline tree_Node *__tree_Get(tree_Node *father, __tree_ConnectType type) { + return (type == __tree_Left) ? father->left : father->right; +} + +static inline void __tree_Connect(tree_Node *father, tree_Node *son, __tree_ConnectType type) { + if (son) + son->father = father; + if (father) { + if (type == __tree_Left) + father->left = son; + else + father->right = son; + } +} + +// Rotates the node up. +static inline void __tree_Rotate(tree_Node *node, tree_Node **root) { + if (!node->father) + return; + + __tree_ConnectType type = __tree_Tell(node); + + tree_Node *f = node->father, + *b = __tree_Get(node, __tree_ConnectType_Invert(type)); + __tree_Connect(f->father, node, __tree_Tell(f)); + __tree_Connect(node, f, __tree_ConnectType_Invert(type)); + __tree_Connect(f, b, type); + + if (!node->father) + *root = node; +} + +// Adjust the tree as a Treap +static inline void __tree_treap_Adjust(tree_Node *node, tree_Node **root) { + while (node->father && node->father->internal > node->internal) + __tree_Rotate(node, root); +} diff --git a/util/vector.c b/util/vector.c new file mode 100644 index 0000000..5ae0b16 --- /dev/null +++ b/util/vector.c @@ -0,0 +1,91 @@ + +#include "vector.h" + +#include "string.h" +#include "stdlib.h" + + +vector_Vector *vector_Create(uintptr_t objectSize) { + vector_Vector *vec = malloc(sizeof(vector_Vector)); + vec->objectSize = objectSize; + vec->size = 0; + vec->data = 0; + + vec->data = malloc(objectSize); + vec->cap = objectSize; + + return vec; +} + +// Resizes the underlying buffer to a new capacity +static inline void __vector_Rebuffer(vector_Vector *vec, uintptr_t newcap) { + void *newbuf = malloc(newcap); + memcpy(newbuf, vec->data, vec->size); + free(vec->data); + vec->data = newbuf; + vec->cap = newcap; +} + +void vector_Destroy(vector_Vector *vec) { + free(vec->data); + free(vec); +} + +void *vector_Push(vector_Vector *vec, const void *data) { + vector_Append(vec, data, 1); + return vec->data + vec->size - vec->objectSize; +} + +void vector_Append(vector_Vector *vec, const void *data, uintptr_t n) { + uintptr_t oldsize = vec->size, addsize = vec->objectSize * n; + vector_Resize(vec, oldsize + addsize); + + if (data) + memcpy(vec->data + oldsize, data, addsize); + else + memset(vec->data + oldsize, 0, addsize); +} + +void vector_Resize(vector_Vector *vec, uintptr_t size) { + uintptr_t newsize = vec->size + size * vec->objectSize; + if (newsize > vec->cap) { + // grow the buffer exponentially + uint64_t newcap = vec->cap; + while (newcap < newsize) + newcap *= 2; + __vector_Rebuffer(vec, newcap); + } + vec->size = newsize; +} + +uintptr_t vector_Size(vector_Vector *vec) { + return vec->size / vec->objectSize; +} + +void vector_Clear(vector_Vector *vec) { + vec->size = 0; +} + +void vector_ShrinkBuffer(vector_Vector *vec) { + if (vec->size != vec->cap) + __vector_Rebuffer(vec, vec->size); +} + +uintptr_t vector_Capacity(vector_Vector *vec) { + return vec->cap / vec->objectSize; +} + +void vector_Reserve(vector_Vector *vec, uintptr_t cap) { + uintptr_t newcap = vec->objectSize * cap; + if (newcap > vec->cap) + __vector_Rebuffer(vec, newcap); +} + +void *vector_At(vector_Vector *vec, uintptr_t i) { + return vec->data + vec->objectSize * i; +} + +// Data returns the data buffer. +void *vector_Data(vector_Vector *vec) { + return vec->data; +} diff --git a/util/vector.h b/util/vector.h new file mode 100644 index 0000000..7a812ca --- /dev/null +++ b/util/vector.h @@ -0,0 +1,65 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +// Vector is an automatic-resizing array. +typedef struct { + uint8_t *data; // actual data buffer + uintptr_t size, cap; // size of the data and buffer, in bytes + uintptr_t objectSize; // size of the object +} vector_Vector; + +// Create allocates a new vector. +vector_Vector *vector_Create(uintptr_t objectSize); + +// Destroy properly frees all data related to the structure, and itself. +void vector_Destroy(vector_Vector *vec); + +// Push pushes an object at the back of the vector. +// +// If data is NULL, the data is zeroed. +// +// Returns a pointer to data. +void *vector_Push(vector_Vector *vec, const void *data); + +// Append pushes multiple objects at the back of the buffer. +// +// If data is NULL, the data is zeroed. +void vector_Append(vector_Vector *vec, const void *data, uintptr_t n); + +// Resize resizes the vector to a new number of elements. +void vector_Resize(vector_Vector *vec, uintptr_t size); + +// Size returns the number of objects in a vector. +uintptr_t vector_Size(vector_Vector *vec); + +// Clear clears a vector, without resizing the buffer. +void vector_Clear(vector_Vector *vec); + +// ShrinkBuffer shrinks the internal buffer to exactly the size of the elements. +void vector_ShrinkBuffer(vector_Vector *vec); + +// Capacity returns the size of the internal buffer. +uintptr_t vector_Capacity(vector_Vector *vec); + +// Reserve reallocates the size of the buffer to CAP objects, +// if the current buffer is smaller. +void vector_Reserve(vector_Vector *vec, uintptr_t cap); + +// At returns the i-th object of the vector. +// +// No boundary test is performed. +void *vector_At(vector_Vector *vec, uintptr_t i); + +// Data returns the data buffer. +void *vector_Data(vector_Vector *vec); + + +#ifdef __cplusplus +} +#endif