115 changed files with 5587 additions and 599 deletions
-
4.gitignore
-
2Makefile.am.coverage
-
69TODO
-
13assets/html/foo.html
-
14assets/html/main.html
-
0assets/html/robots.txt
-
1assets/js/jquery.js
-
0assets/other/.keep-me
-
184config/mime.types
-
9configure.ac
-
26docs/idea_for_asset_access.md
-
184docs/mime.types
-
245docs/rbdelete.txt
-
235docs/rbinsert.txt
-
53docs/socket_states.txt
-
61include/asset.h
-
1include/cbuf.h
-
23include/cbufpool.h
-
3include/hash/hash.h
-
11include/http/message.h
-
9include/http/response.h
-
4include/http/worker.h
-
52include/http/writer.h
-
1include/socket.h
-
138include/tree.h
-
11include/utils/memory.h
-
31include/utils/mime_type.h
-
4m4/gcov.m4
-
13src/Makefile.am
-
6src/asset/Makefile.am
-
140src/asset/asset.c
-
94src/asset/pool.c
-
2src/auth/Makefile.am
-
8src/auth/credential.c
-
25src/auth/ldap.c
-
303src/binarytree.c
-
4src/cbuf/Makefile.am
-
4src/cbuf/cbuf.c
-
17src/cbuf/read.c
-
10src/cbufpool.c
-
2src/class/Makefile.am
-
12src/class/interface/i_class.c
-
54src/hash.c
-
2src/hash/Makefile.am
-
21src/hash/add.c
-
22src/hash/delete.c
-
10src/hash/each.c
-
21src/hash/get.c
-
9src/hash/hash.c
-
18src/hash/interface/hashable.c
-
8src/hash/value.c
-
3src/http/Makefile.am
-
12src/http/cookie.c
-
8src/http/header.c
-
24src/http/message.c
-
2src/http/parser.c
-
4src/http/parser/p_header.c
-
4src/http/parser/p_request_vars.c
-
54src/http/parser/parse.c
-
10src/http/request.c
-
4src/http/response.c
-
1src/http/response/304.c
-
1src/http/response/403.c
-
3src/http/response/404.c
-
65src/http/response/500.c
-
57src/http/response/asset.c
-
4src/http/response/login_form.c
-
4src/http/response/randval.c
-
4src/http/response/session.c
-
39src/http/worker.c
-
40src/http/worker/get_asset.c
-
101src/http/worker/process.c
-
13src/http/writer.c
-
141src/http/writer/write.c
-
2src/logger/Makefile.am
-
31src/logger/interface/i_logger.c
-
55src/mmapfiletest.c
-
54src/mmapfiletest2.c
-
2src/queue/Makefile.am
-
797src/rbtree.c
-
176src/rbtree2.c
-
2src/server/Makefile.am
-
55src/server/handle_accept.c
-
28src/server/poll.c
-
41src/server/read.c
-
90src/server/run.c
-
61src/server/server.c
-
24src/server/write.c
-
2src/session/Makefile.am
-
4src/session/session.c
-
4src/socket/Makefile.am
-
12src/socket/accept.c
-
32src/socket/nonblock.c
-
2src/stream/Makefile.am
-
26src/stream/read.c
-
25src/stream/write.c
-
14src/taskrambler.c
-
9src/tree/Makefile.am
-
249src/tree/delete.c
-
85src/tree/destroy.c
@ -0,0 +1,13 @@ |
|||||
|
<?xml version="1.0" encoding="iso-8859-1"?> |
||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> |
||||
|
<head> |
||||
|
<title>This is just foo</title> |
||||
|
</head> |
||||
|
<body> |
||||
|
<h1>A BIG FAT FOO</h1> |
||||
|
</body> |
||||
|
</html> |
||||
|
|
||||
|
<!-- vim: set ts=4 sw=4: --> |
||||
@ -0,0 +1 @@ |
|||||
|
jquery-1.7.1.min.js |
||||
@ -0,0 +1,184 @@ |
|||||
|
evy application/envoy |
||||
|
fif application/fractals |
||||
|
spl application/futuresplash |
||||
|
hta application/hta |
||||
|
acx application/internet-property-stream |
||||
|
hqx application/mac-binhex40 |
||||
|
doc application/msword |
||||
|
dot application/msword |
||||
|
* application/octet-stream |
||||
|
oda application/oda |
||||
|
axs application/olescript |
||||
|
pdf application/pdf |
||||
|
prf application/pics-rules |
||||
|
p10 application/pkcs10 |
||||
|
crl application/pkix-crl |
||||
|
ai application/postscript |
||||
|
eps application/postscript |
||||
|
ps application/postscript |
||||
|
rtf application/rtf |
||||
|
setpay application/set-payment-initiation |
||||
|
setreg application/set-registration-initiation |
||||
|
xla application/vnd.ms-excel |
||||
|
xlc application/vnd.ms-excel |
||||
|
xlm application/vnd.ms-excel |
||||
|
xls application/vnd.ms-excel |
||||
|
xlt application/vnd.ms-excel |
||||
|
xlw application/vnd.ms-excel |
||||
|
msg application/vnd.ms-outlook |
||||
|
sst application/vnd.ms-pkicertstore |
||||
|
cat application/vnd.ms-pkiseccat |
||||
|
stl application/vnd.ms-pkistl |
||||
|
pot application/vnd.ms-powerpoint |
||||
|
pps application/vnd.ms-powerpoint |
||||
|
ppt application/vnd.ms-powerpoint |
||||
|
mpp application/vnd.ms-project |
||||
|
wcm application/vnd.ms-works |
||||
|
wdb application/vnd.ms-works |
||||
|
wks application/vnd.ms-works |
||||
|
wps application/vnd.ms-works |
||||
|
hlp application/winhlp |
||||
|
bcpio application/x-bcpio |
||||
|
cdf application/x-cdf |
||||
|
z application/x-compress |
||||
|
tgz application/x-compressed |
||||
|
cpio application/x-cpio |
||||
|
csh application/x-csh |
||||
|
dcr application/x-director |
||||
|
dir application/x-director |
||||
|
dxr application/x-director |
||||
|
dvi application/x-dvi |
||||
|
gtar application/x-gtar |
||||
|
gz application/x-gzip |
||||
|
hdf application/x-hdf |
||||
|
ins application/x-internet-signup |
||||
|
isp application/x-internet-signup |
||||
|
iii application/x-iphone |
||||
|
js application/x-javascript |
||||
|
latex application/x-latex |
||||
|
mdb application/x-msaccess |
||||
|
crd application/x-mscardfile |
||||
|
clp application/x-msclip |
||||
|
dll application/x-msdownload |
||||
|
m13 application/x-msmediaview |
||||
|
m14 application/x-msmediaview |
||||
|
mvb application/x-msmediaview |
||||
|
wmf application/x-msmetafile |
||||
|
mny application/x-msmoney |
||||
|
pub application/x-mspublisher |
||||
|
scd application/x-msschedule |
||||
|
trm application/x-msterminal |
||||
|
wri application/x-mswrite |
||||
|
nc application/x-netcdf |
||||
|
pma application/x-perfmon |
||||
|
pmc application/x-perfmon |
||||
|
pml application/x-perfmon |
||||
|
pmr application/x-perfmon |
||||
|
pmw application/x-perfmon |
||||
|
p12 application/x-pkcs12 |
||||
|
pfx application/x-pkcs12 |
||||
|
p7b application/x-pkcs7-certificates |
||||
|
spc application/x-pkcs7-certificates |
||||
|
p7r application/x-pkcs7-certreqresp |
||||
|
p7c application/x-pkcs7-mime |
||||
|
p7m application/x-pkcs7-mime |
||||
|
p7s application/x-pkcs7-signature |
||||
|
sh application/x-sh |
||||
|
shar application/x-shar |
||||
|
swf application/x-shockwave-flash |
||||
|
sit application/x-stuffit |
||||
|
sv4cpio application/x-sv4cpio |
||||
|
sv4crc application/x-sv4crc |
||||
|
tar application/x-tar |
||||
|
tcl application/x-tcl |
||||
|
tex application/x-tex |
||||
|
texi application/x-texinfo |
||||
|
texinfo application/x-texinfo |
||||
|
roff application/x-troff |
||||
|
t application/x-troff |
||||
|
tr application/x-troff |
||||
|
man application/x-troff-man |
||||
|
me application/x-troff-me |
||||
|
ms application/x-troff-ms |
||||
|
ustar application/x-ustar |
||||
|
src application/x-wais-source |
||||
|
cer application/x-x509-ca-cert |
||||
|
crt application/x-x509-ca-cert |
||||
|
der application/x-x509-ca-cert |
||||
|
pko application/ynd.ms-pkipko |
||||
|
zip application/zip |
||||
|
au audio/basic |
||||
|
snd audio/basic |
||||
|
mid audio/mid |
||||
|
rmi audio/mid |
||||
|
mp3 audio/mpeg |
||||
|
aif audio/x-aiff |
||||
|
aifc audio/x-aiff |
||||
|
aiff audio/x-aiff |
||||
|
m3u audio/x-mpegurl |
||||
|
ra audio/x-pn-realaudio |
||||
|
ram audio/x-pn-realaudio |
||||
|
wav audio/x-wav |
||||
|
bmp image/bmp |
||||
|
cod image/cis-cod |
||||
|
gif image/gif |
||||
|
ief image/ief |
||||
|
jpe image/jpeg |
||||
|
jpeg image/jpeg |
||||
|
jpg image/jpeg |
||||
|
jfif image/pipeg |
||||
|
svg image/svg+xml |
||||
|
tif image/tiff |
||||
|
tiff image/tiff |
||||
|
ras image/x-cmu-raster |
||||
|
cmx image/x-cmx |
||||
|
ico image/x-icon |
||||
|
pnm image/x-portable-anymap |
||||
|
pbm image/x-portable-bitmap |
||||
|
pgm image/x-portable-graymap |
||||
|
ppm image/x-portable-pixmap |
||||
|
rgb image/x-rgb |
||||
|
xbm image/x-xbitmap |
||||
|
xpm image/x-xpixmap |
||||
|
xwd image/x-xwindowdump |
||||
|
mht message/rfc822 |
||||
|
mhtml message/rfc822 |
||||
|
nws message/rfc822 |
||||
|
css text/css |
||||
|
323 text/h323 |
||||
|
htm text/html |
||||
|
html text/html |
||||
|
stm text/html |
||||
|
uls text/iuls |
||||
|
bas text/plain |
||||
|
c text/plain |
||||
|
h text/plain |
||||
|
txt text/plain |
||||
|
rtx text/richtext |
||||
|
sct text/scriptlet |
||||
|
tsv text/tab-separated-values |
||||
|
htt text/webviewhtml |
||||
|
htc text/x-component |
||||
|
etx text/x-setext |
||||
|
vcf text/x-vcard |
||||
|
mp2 video/mpeg |
||||
|
mpa video/mpeg |
||||
|
mpe video/mpeg |
||||
|
mpeg video/mpeg |
||||
|
mpg video/mpeg |
||||
|
mpv2 video/mpeg |
||||
|
mov video/quicktime |
||||
|
qt video/quicktime |
||||
|
lsf video/x-la-asf |
||||
|
lsx video/x-la-asf |
||||
|
asf video/x-ms-asf |
||||
|
asr video/x-ms-asf |
||||
|
asx video/x-ms-asf |
||||
|
avi video/x-msvideo |
||||
|
movie video/x-sgi-movie |
||||
|
flr x-world/x-vrml |
||||
|
vrml x-world/x-vrml |
||||
|
wrl x-world/x-vrml |
||||
|
wrz x-world/x-vrml |
||||
|
xaf x-world/x-vrml |
||||
|
xof x-world/x-vrml |
||||
@ -0,0 +1,26 @@ |
|||||
|
The Problem |
||||
|
=========== |
||||
|
|
||||
|
- One asset might be accessed on various positions by multiple workers. |
||||
|
- The asset might be large. |
||||
|
- The amount of usable file handles is limited. |
||||
|
|
||||
|
Idea |
||||
|
==== |
||||
|
|
||||
|
Create an asset class, wich holds the file handle as well as a memory |
||||
|
mapping to it, as well as a reference count of interested workers. |
||||
|
An asset object is created the first time the asset is requested. Then |
||||
|
the file is opened and memory mapped and the refcount is set to 1. |
||||
|
The asset is than stored into a hash indexed by the filename. |
||||
|
The next time the asset is requested it is found in the hash and the |
||||
|
refcount is increased. |
||||
|
The asset object might be an observer of each worker it uses, so the |
||||
|
worker can inform the asset object when they are done, so that the |
||||
|
reference count can be decreased. |
||||
|
If the reference count goes to zero, the asset object is removed from the |
||||
|
hash and freed. |
||||
|
Each worker in turn has to know how much of the asset is already processed, |
||||
|
so that it can ask for the position it wants the next data from. |
||||
|
As each request is assigned one worker and one request can only access one |
||||
|
asset the worker has to know only one position. |
||||
@ -0,0 +1,184 @@ |
|||||
|
evy application/envoy |
||||
|
fif application/fractals |
||||
|
spl application/futuresplash |
||||
|
hta application/hta |
||||
|
acx application/internet-property-stream |
||||
|
hqx application/mac-binhex40 |
||||
|
doc application/msword |
||||
|
dot application/msword |
||||
|
* application/octet-stream |
||||
|
oda application/oda |
||||
|
axs application/olescript |
||||
|
pdf application/pdf |
||||
|
prf application/pics-rules |
||||
|
p10 application/pkcs10 |
||||
|
crl application/pkix-crl |
||||
|
ai application/postscript |
||||
|
eps application/postscript |
||||
|
ps application/postscript |
||||
|
rtf application/rtf |
||||
|
setpay application/set-payment-initiation |
||||
|
setreg application/set-registration-initiation |
||||
|
xla application/vnd.ms-excel |
||||
|
xlc application/vnd.ms-excel |
||||
|
xlm application/vnd.ms-excel |
||||
|
xls application/vnd.ms-excel |
||||
|
xlt application/vnd.ms-excel |
||||
|
xlw application/vnd.ms-excel |
||||
|
msg application/vnd.ms-outlook |
||||
|
sst application/vnd.ms-pkicertstore |
||||
|
cat application/vnd.ms-pkiseccat |
||||
|
stl application/vnd.ms-pkistl |
||||
|
pot application/vnd.ms-powerpoint |
||||
|
pps application/vnd.ms-powerpoint |
||||
|
ppt application/vnd.ms-powerpoint |
||||
|
mpp application/vnd.ms-project |
||||
|
wcm application/vnd.ms-works |
||||
|
wdb application/vnd.ms-works |
||||
|
wks application/vnd.ms-works |
||||
|
wps application/vnd.ms-works |
||||
|
hlp application/winhlp |
||||
|
bcpio application/x-bcpio |
||||
|
cdf application/x-cdf |
||||
|
z application/x-compress |
||||
|
tgz application/x-compressed |
||||
|
cpio application/x-cpio |
||||
|
csh application/x-csh |
||||
|
dcr application/x-director |
||||
|
dir application/x-director |
||||
|
dxr application/x-director |
||||
|
dvi application/x-dvi |
||||
|
gtar application/x-gtar |
||||
|
gz application/x-gzip |
||||
|
hdf application/x-hdf |
||||
|
ins application/x-internet-signup |
||||
|
isp application/x-internet-signup |
||||
|
iii application/x-iphone |
||||
|
js application/x-javascript |
||||
|
latex application/x-latex |
||||
|
mdb application/x-msaccess |
||||
|
crd application/x-mscardfile |
||||
|
clp application/x-msclip |
||||
|
dll application/x-msdownload |
||||
|
m13 application/x-msmediaview |
||||
|
m14 application/x-msmediaview |
||||
|
mvb application/x-msmediaview |
||||
|
wmf application/x-msmetafile |
||||
|
mny application/x-msmoney |
||||
|
pub application/x-mspublisher |
||||
|
scd application/x-msschedule |
||||
|
trm application/x-msterminal |
||||
|
wri application/x-mswrite |
||||
|
nc application/x-netcdf |
||||
|
pma application/x-perfmon |
||||
|
pmc application/x-perfmon |
||||
|
pml application/x-perfmon |
||||
|
pmr application/x-perfmon |
||||
|
pmw application/x-perfmon |
||||
|
p12 application/x-pkcs12 |
||||
|
pfx application/x-pkcs12 |
||||
|
p7b application/x-pkcs7-certificates |
||||
|
spc application/x-pkcs7-certificates |
||||
|
p7r application/x-pkcs7-certreqresp |
||||
|
p7c application/x-pkcs7-mime |
||||
|
p7m application/x-pkcs7-mime |
||||
|
p7s application/x-pkcs7-signature |
||||
|
sh application/x-sh |
||||
|
shar application/x-shar |
||||
|
swf application/x-shockwave-flash |
||||
|
sit application/x-stuffit |
||||
|
sv4cpio application/x-sv4cpio |
||||
|
sv4crc application/x-sv4crc |
||||
|
tar application/x-tar |
||||
|
tcl application/x-tcl |
||||
|
tex application/x-tex |
||||
|
texi application/x-texinfo |
||||
|
texinfo application/x-texinfo |
||||
|
roff application/x-troff |
||||
|
t application/x-troff |
||||
|
tr application/x-troff |
||||
|
man application/x-troff-man |
||||
|
me application/x-troff-me |
||||
|
ms application/x-troff-ms |
||||
|
ustar application/x-ustar |
||||
|
src application/x-wais-source |
||||
|
cer application/x-x509-ca-cert |
||||
|
crt application/x-x509-ca-cert |
||||
|
der application/x-x509-ca-cert |
||||
|
pko application/ynd.ms-pkipko |
||||
|
zip application/zip |
||||
|
au audio/basic |
||||
|
snd audio/basic |
||||
|
mid audio/mid |
||||
|
rmi audio/mid |
||||
|
mp3 audio/mpeg |
||||
|
aif audio/x-aiff |
||||
|
aifc audio/x-aiff |
||||
|
aiff audio/x-aiff |
||||
|
m3u audio/x-mpegurl |
||||
|
ra audio/x-pn-realaudio |
||||
|
ram audio/x-pn-realaudio |
||||
|
wav audio/x-wav |
||||
|
bmp image/bmp |
||||
|
cod image/cis-cod |
||||
|
gif image/gif |
||||
|
ief image/ief |
||||
|
jpe image/jpeg |
||||
|
jpeg image/jpeg |
||||
|
jpg image/jpeg |
||||
|
jfif image/pipeg |
||||
|
svg image/svg+xml |
||||
|
tif image/tiff |
||||
|
tiff image/tiff |
||||
|
ras image/x-cmu-raster |
||||
|
cmx image/x-cmx |
||||
|
ico image/x-icon |
||||
|
pnm image/x-portable-anymap |
||||
|
pbm image/x-portable-bitmap |
||||
|
pgm image/x-portable-graymap |
||||
|
ppm image/x-portable-pixmap |
||||
|
rgb image/x-rgb |
||||
|
xbm image/x-xbitmap |
||||
|
xpm image/x-xpixmap |
||||
|
xwd image/x-xwindowdump |
||||
|
mht message/rfc822 |
||||
|
mhtml message/rfc822 |
||||
|
nws message/rfc822 |
||||
|
css text/css |
||||
|
323 text/h323 |
||||
|
htm text/html |
||||
|
html text/html |
||||
|
stm text/html |
||||
|
uls text/iuls |
||||
|
bas text/plain |
||||
|
c text/plain |
||||
|
h text/plain |
||||
|
txt text/plain |
||||
|
rtx text/richtext |
||||
|
sct text/scriptlet |
||||
|
tsv text/tab-separated-values |
||||
|
htt text/webviewhtml |
||||
|
htc text/x-component |
||||
|
etx text/x-setext |
||||
|
vcf text/x-vcard |
||||
|
mp2 video/mpeg |
||||
|
mpa video/mpeg |
||||
|
mpe video/mpeg |
||||
|
mpeg video/mpeg |
||||
|
mpg video/mpeg |
||||
|
mpv2 video/mpeg |
||||
|
mov video/quicktime |
||||
|
qt video/quicktime |
||||
|
lsf video/x-la-asf |
||||
|
lsx video/x-la-asf |
||||
|
asf video/x-ms-asf |
||||
|
asr video/x-ms-asf |
||||
|
asx video/x-ms-asf |
||||
|
avi video/x-msvideo |
||||
|
movie video/x-sgi-movie |
||||
|
flr x-world/x-vrml |
||||
|
vrml x-world/x-vrml |
||||
|
wrl x-world/x-vrml |
||||
|
wrz x-world/x-vrml |
||||
|
xaf x-world/x-vrml |
||||
|
xof x-world/x-vrml |
||||
@ -0,0 +1,245 @@ |
|||||
|
Properties of a rbtree |
||||
|
====================== |
||||
|
|
||||
|
1. A node is either red or black. |
||||
|
2. The root is black. (This rule is sometimes omitted. Since the root can |
||||
|
always be changed from red to black, but not necessarily vice-versa, |
||||
|
this rule has little effect on analysis.) |
||||
|
3. All leaves (NIL) are black. (All leaves are same color as the |
||||
|
root.) |
||||
|
4. Every red node must have two black child nodes. |
||||
|
5. Every simple path from a given node to any of its |
||||
|
descendant leaves contains the same number of black nodes. |
||||
|
|
||||
|
|
||||
|
Assumptions in addition to wikipedia |
||||
|
==================================== |
||||
|
|
||||
|
lets assume that NULL pointer are black B nodes. But we mark them with a (N) |
||||
|
|
||||
|
|
||||
|
Example |
||||
|
======= |
||||
|
|
||||
|
we start with the tree from the insert example |
||||
|
---------------------------------------------- |
||||
|
|
||||
|
B(11) |
||||
|
|
||||
|
R(8) R(13) |
||||
|
|
||||
|
B(3) B(9) B(12) B(16) |
||||
|
|
||||
|
B(N) B(N) B(N) R(10) B(N) B(N) B(N) B(N) |
||||
|
|
||||
|
B(N) B(N) |
||||
|
|
||||
|
we remove R(10) / remove a red node (replace with its child): |
||||
|
wikipedia explains why this can only happen with two leaf children (our B(N)) |
||||
|
|
||||
|
B(11) |
||||
|
|
||||
|
R(8) R(13) |
||||
|
|
||||
|
B(3) B(9) B(12) B(16) |
||||
|
|
||||
|
B(N) B(N) B(N) B(N) B(N) B(N) B(N) B(N) |
||||
|
|
||||
|
|
||||
|
again start with the insert example result |
||||
|
------------------------------------------ |
||||
|
|
||||
|
B(11) |
||||
|
|
||||
|
R(8) R(13) |
||||
|
|
||||
|
B(3) B(9) B(12) B(16) |
||||
|
|
||||
|
B(N) B(N) B(N) R(10) B(N) B(N) B(N) B(N) |
||||
|
|
||||
|
B(N) B(N) |
||||
|
|
||||
|
remove B(9) (which is the second simple case described on wikipedia) |
||||
|
M black, C red |
||||
|
After remove just repaint child black. As I do not replace the node, |
||||
|
but the value this is simplified in my case to simply do nothing after |
||||
|
normal delete... :D |
||||
|
|
||||
|
B(11) |
||||
|
|
||||
|
R(8) R(13) |
||||
|
|
||||
|
B(3) B(10) B(12) B(16) |
||||
|
|
||||
|
B(N) B(N) B(N) B(N) B(N) B(N) B(N) B(N) |
||||
|
|
||||
|
|
||||
|
again start with the insert example result |
||||
|
------------------------------------------ |
||||
|
|
||||
|
B(11) |
||||
|
|
||||
|
R(8) R(13) |
||||
|
|
||||
|
B(3) B(9) B(12) B(16) |
||||
|
|
||||
|
B(N) B(N) B(N) R(10) B(N) B(N) B(N) B(N) |
||||
|
|
||||
|
B(N) B(N) |
||||
|
|
||||
|
now lets delete B(3)... which is stated on wikipedia as the complicated case |
||||
|
where 6 subcases could be distinguished. |
||||
|
|
||||
|
Wikipedia says we begin with replacing B(3) which one if its childs, in my |
||||
|
case this means, setting r(8)->left to NULL.... |
||||
|
|
||||
|
B(11) |
||||
|
|
||||
|
R(8) R(13) |
||||
|
|
||||
|
B(N) B(9) B(12) B(16) |
||||
|
|
||||
|
B(N) R(10) B(N) B(N) B(N) B(N) |
||||
|
|
||||
|
B(N) B(N) |
||||
|
|
||||
|
So, what is called in on Wikipedia is simply a nullpointer for me...hopefully |
||||
|
I don't have to do anything with it. |
||||
|
|
||||
|
Get an overview over our variables now: |
||||
|
|
||||
|
N : Nullpointer set in R(8)->left (thus N will be black by definition, ever) |
||||
|
P : R(8) |
||||
|
S : B(9) |
||||
|
Sl: Nullpointer |
||||
|
Sr: R(10) |
||||
|
|
||||
|
cases: |
||||
|
- case 2: S is red => reverse color of P and S, then rotate left at P |
||||
|
- case 3: P, S and S's children are black => repaint S red |
||||
|
- case 4: S and S's children are black, P is red => exchange colors of S and |
||||
|
P |
||||
|
- case 5: S and Sr black, Sl is red N left of P => rotate right at S, exchange |
||||
|
colors of S and Sl |
||||
|
- case 6: S black, Sr is red N left of P => rotate left at P, exchange colors |
||||
|
of P and S and make Sr black |
||||
|
|
||||
|
looks like case 6: |
||||
|
|
||||
|
first rotate left at P |
||||
|
|
||||
|
B(11) |
||||
|
|
||||
|
B(9) R(13) |
||||
|
|
||||
|
R(8) R(10) B(12) B(16) |
||||
|
|
||||
|
B(N) B(N) B(N) B(N) B(N) B(N) B(N) B(N) |
||||
|
|
||||
|
exchange colors of P and S and make Sr black. |
||||
|
|
||||
|
B(11) |
||||
|
|
||||
|
R(9) R(13) |
||||
|
|
||||
|
B(8) B(10) B(12) B(16) |
||||
|
|
||||
|
B(N) B(N) B(N) B(N) B(N) B(N) B(N) B(N) |
||||
|
|
||||
|
|
||||
|
|
||||
|
now for case 2, we delete 16 from the following tree |
||||
|
|
||||
|
B(13) |
||||
|
|
||||
|
R(8) B(16) |
||||
|
|
||||
|
B(3) B(11) B(N) B(N) |
||||
|
|
||||
|
B(N) B(N) R(9) B(N) |
||||
|
|
||||
|
B(N) B(N) |
||||
|
|
||||
|
again first lets see what we have where... |
||||
|
|
||||
|
N : Nullpointer set in R(13)->right (thus N will be black by definition, ever) |
||||
|
P : B(13) |
||||
|
S : R(8) |
||||
|
Sl: B(3) |
||||
|
Sr: B(11) |
||||
|
|
||||
|
B(13)P |
||||
|
|
||||
|
R(8)S B(N)N |
||||
|
|
||||
|
B(3)Sl B(11)Sr |
||||
|
|
||||
|
B(N) B(N) R(9) B(N) |
||||
|
|
||||
|
B(N) B(N) |
||||
|
|
||||
|
revert colors of P and S |
||||
|
|
||||
|
R(13)P |
||||
|
|
||||
|
B(8)S B(N)N |
||||
|
|
||||
|
B(3)Sl B(11)Sr |
||||
|
|
||||
|
B(N) B(N) R(9) B(N) |
||||
|
|
||||
|
B(N) B(N) |
||||
|
|
||||
|
rotate right at P |
||||
|
|
||||
|
B(8)S |
||||
|
|
||||
|
B(3)Sl R(13)P |
||||
|
|
||||
|
B(N) B(N) B(11)Sr B(N)N |
||||
|
|
||||
|
R(9) B(N) |
||||
|
|
||||
|
B(N) B(N) |
||||
|
|
||||
|
relable ... done on wikipedia (don't know if I will need it.) |
||||
|
|
||||
|
B(8) |
||||
|
|
||||
|
B(3) R(13)P |
||||
|
|
||||
|
B(N) B(N) B(11)S B(N)N |
||||
|
|
||||
|
R(9)Sl B(N)Sr |
||||
|
|
||||
|
B(N) B(N) |
||||
|
|
||||
|
ok, not case 3... P is red |
||||
|
nor is it case 4 Sl is red. |
||||
|
kind of case 6 reversed ... lets try what they do in the code not in the description... |
||||
|
|
||||
|
Sl to black |
||||
|
|
||||
|
B(8) |
||||
|
|
||||
|
B(3) R(13)P |
||||
|
|
||||
|
B(N) B(N) B(11)S B(N)N |
||||
|
|
||||
|
B(9)Sl B(N)Sr |
||||
|
|
||||
|
B(N) B(N) |
||||
|
|
||||
|
rotate right on P |
||||
|
|
||||
|
B(8) |
||||
|
|
||||
|
B(3) B(11)S |
||||
|
|
||||
|
B(N) B(N) B(9)Sl R(13)P |
||||
|
|
||||
|
B(N) B(N) B(N)Sr B(N)N |
||||
|
|
||||
|
This result is wrong....the balance is ok, but the color of 9 is wrong. |
||||
|
|
||||
|
# vim: set et ts=4: |
||||
@ -0,0 +1,235 @@ |
|||||
|
Properties of a rbtree |
||||
|
====================== |
||||
|
|
||||
|
1. A node is either red or black. |
||||
|
2. The root is black. (This rule is sometimes omitted. Since the root can |
||||
|
always be changed from red to black, but not necessarily vice-versa, |
||||
|
this rule has little effect on analysis.) |
||||
|
3. All leaves (NIL) are black. (All leaves are same color as the |
||||
|
root.) |
||||
|
4. Every red node must have two black child nodes. |
||||
|
5. Every simple path from a given node to any of its |
||||
|
descendant leaves contains the same number of black nodes. |
||||
|
|
||||
|
|
||||
|
Assumptions in addition to wikipedia |
||||
|
==================================== |
||||
|
|
||||
|
lets assume that NULL pointer are black B nodes. But we mark them with a (N) |
||||
|
|
||||
|
|
||||
|
Example |
||||
|
======= |
||||
|
|
||||
|
we start with an empty tree.... |
||||
|
------------------------------- |
||||
|
|
||||
|
B(N) |
||||
|
|
||||
|
|
||||
|
case 1 (root): add first element... elements are red R wenn added, add key 13. |
||||
|
------------------------------------------------------------------------------ |
||||
|
|
||||
|
R(13) |
||||
|
|
||||
|
B(N) B(N) |
||||
|
|
||||
|
|
||||
|
but now we violate rule 2 and correct this simply by changing the root to |
||||
|
black. => first rule, if we insert into a root node (the root was null) insert |
||||
|
as black. |
||||
|
|
||||
|
B(13) |
||||
|
|
||||
|
B(N) B(N) |
||||
|
|
||||
|
|
||||
|
case 2 (black parent): add an element 8. |
||||
|
----------------------------------------- |
||||
|
|
||||
|
B(13) |
||||
|
|
||||
|
R(8) B(N) |
||||
|
|
||||
|
B(N) B(N) |
||||
|
|
||||
|
we violate none of the properties defined. Nothing to be done. |
||||
|
|
||||
|
|
||||
|
Now add 16 which is case 2 again |
||||
|
|
||||
|
B(13) |
||||
|
|
||||
|
R(8) R(16) |
||||
|
|
||||
|
B(N) B(N) B(N) B(N) |
||||
|
|
||||
|
|
||||
|
case 3 (red parent and uncle): add 11.... |
||||
|
---------------------------------------- |
||||
|
|
||||
|
B(13) |
||||
|
|
||||
|
R(8) R(16) |
||||
|
|
||||
|
B(N) R(11) B(N) B(N) |
||||
|
|
||||
|
B(N) B(N) |
||||
|
|
||||
|
This violates propert 4 (each red node must have 2 black childs). |
||||
|
=> repaint both to black and the gandparent to red. |
||||
|
|
||||
|
R(13) |
||||
|
|
||||
|
B(8) B(16) |
||||
|
|
||||
|
B(N) R(11) B(N) B(N) |
||||
|
|
||||
|
B(N) B(N) |
||||
|
|
||||
|
This violates now property 2 (The root is black) and it may have |
||||
|
violated property 4 for the gantparent...so we start all over again |
||||
|
with case 1 on the grantparent. |
||||
|
As we now might run into case 4 or 5 where also parent uncle and |
||||
|
grandparent might be needed we should always track |
||||
|
|
||||
|
- grandgrandparent |
||||
|
- granduncle |
||||
|
- grandparent |
||||
|
- parent |
||||
|
- uncle |
||||
|
|
||||
|
For now case 1 occurs again wich gives us the following: |
||||
|
|
||||
|
B(13) |
||||
|
|
||||
|
B(8) B(16) |
||||
|
|
||||
|
B(N) R(11) B(N) B(N) |
||||
|
|
||||
|
B(N) B(N) |
||||
|
|
||||
|
|
||||
|
Perfect, thats ok again. |
||||
|
|
||||
|
Now as preparation of case 4 we add a 3 |
||||
|
|
||||
|
B(13) |
||||
|
|
||||
|
B(8) B(16) |
||||
|
|
||||
|
R(3) R(11) B(N) B(N) |
||||
|
|
||||
|
B(N) B(N) B(N) B(N) |
||||
|
|
||||
|
|
||||
|
and now a 9. |
||||
|
|
||||
|
B(13) |
||||
|
|
||||
|
B(8) B(16) |
||||
|
|
||||
|
R(3) R(11) B(N) B(N) |
||||
|
|
||||
|
B(N) B(N) R(9) B(N) |
||||
|
|
||||
|
B(N) B(N) |
||||
|
|
||||
|
|
||||
|
which again leads to case 3. |
||||
|
|
||||
|
B(13) |
||||
|
|
||||
|
R(8) B(16) |
||||
|
|
||||
|
B(3) B(11) B(N) B(N) |
||||
|
|
||||
|
B(N) B(N) R(9) B(N) |
||||
|
|
||||
|
B(N) B(N) |
||||
|
|
||||
|
and we are fine again. |
||||
|
now add 12... |
||||
|
|
||||
|
B(13) |
||||
|
|
||||
|
R(8) B(16) |
||||
|
|
||||
|
B(3) B(11) B(N) B(N) |
||||
|
|
||||
|
B(N) B(N) R(9) R(12) |
||||
|
|
||||
|
B(N) B(N) B(N) B(N) |
||||
|
|
||||
|
and now add a 10... |
||||
|
|
||||
|
B(13) |
||||
|
|
||||
|
R(8) B(16) |
||||
|
|
||||
|
B(3) B(11) B(N) B(N) |
||||
|
|
||||
|
B(N) B(N) R(9) R(12) |
||||
|
|
||||
|
B(N) R(10) B(N) B(N) |
||||
|
N N |
||||
|
|
||||
|
case 3 again... |
||||
|
|
||||
|
B(13) |
||||
|
|
||||
|
R(8) B(16) |
||||
|
|
||||
|
B(3) R(11) B(N) B(N) |
||||
|
|
||||
|
B(N) B(N) B(9) B(12) |
||||
|
|
||||
|
B(N) R(10) B(N) B(N) |
||||
|
N N |
||||
|
|
||||
|
as case 3 starts again with grandparent as node, which has to be prepared |
||||
|
before starting over again, we have the following: |
||||
|
|
||||
|
node R(11) |
||||
|
parent R(8) |
||||
|
uncle B(16) |
||||
|
grandparent B(13) |
||||
|
|
||||
|
|
||||
|
now property 4 of our new parent is violated which brings us to case 4 as |
||||
|
it is not the root. (the cases are taken from wikipedia.) |
||||
|
|
||||
|
so lets do case 4 on our node (which is left rotate on our parent, |
||||
|
the parent of our grandparent). |
||||
|
|
||||
|
B(13) |
||||
|
|
||||
|
R(11) B(16) |
||||
|
|
||||
|
R(8) B(12) B(N) B(N) |
||||
|
|
||||
|
B(3) B(9) B(N) B(N) |
||||
|
|
||||
|
B(N) B(N) B(N) R(10) |
||||
|
N N |
||||
|
|
||||
|
but again we are left in violated state...again property 4 is violated. |
||||
|
This is always the case, so always do case 5 after case 4. |
||||
|
|
||||
|
We can see beside of some subtree changes our node and parent have changed |
||||
|
role. we need to address this by swaping them in our code. |
||||
|
|
||||
|
So, do case 5 (right rotate the grandparent and set grandparent color to red |
||||
|
and parent color to black. |
||||
|
|
||||
|
B(11) |
||||
|
|
||||
|
R(8) R(13) |
||||
|
|
||||
|
B(3) B(9) B(12) B(16) |
||||
|
|
||||
|
B(N) B(N) B(N) R(10) B(N) B(N) B(N) B(N) |
||||
|
|
||||
|
B(N) B(N) |
||||
|
|
||||
|
# vim: set et ts=4: |
||||
@ -0,0 +1,53 @@ |
|||||
|
each socket can have 4 states while reading or writing...well as far as i can |
||||
|
say....assuming is is nonblocking. |
||||
|
These can be checked via errno and return value. |
||||
|
|
||||
|
recv send errno |
||||
|
OK >0 >0 NOT SET |
||||
|
CLOSED REMOTELY 0 -1 (write)ECONNRESET |
||||
|
E_AGAIN -1 -1 EAGAIN|EWOULDBLOCK |
||||
|
ERROR OTHER -1 -1 AMYTHING ELSE |
||||
|
|
||||
|
This means we need a slightly different handling for reading and writing. |
||||
|
It might be neccessary to distinguish other streams from sockets albeit I |
||||
|
would like to prevent this... |
||||
|
This might be tested with small test programs. Well, the only special thing |
||||
|
is ECONNRESET in write mode...because this is something that would not |
||||
|
happen to files open for writing. |
||||
|
We need to be more selective when to close the socket. In fact there are |
||||
|
some errors, as EINTR which does not mean our socket is closed at all. |
||||
|
|
||||
|
Error which does not cause us to close the socket while writing: |
||||
|
|
||||
|
EAGAIN - go to poll |
||||
|
EINTR - try again |
||||
|
ENOBUFS - try again (maybe only a few times....) |
||||
|
ENOMEM - try again (maybe only a few times....) |
||||
|
|
||||
|
All other errors will cause us to close the socket while writing to it. |
||||
|
|
||||
|
Error which does not cause us to close the socket while reading: |
||||
|
|
||||
|
EAGAIN - go to poll |
||||
|
EINTR - try again |
||||
|
ENOMEM - try again (maybe only a few times....) |
||||
|
|
||||
|
All other errors will cause us to close the socket while reading from it. |
||||
|
|
||||
|
From a server view... |
||||
|
- read or write a socket as long as OK |
||||
|
- close if either indicated by read or write...maybe read or write themself |
||||
|
could do the close. |
||||
|
- poll if all socket get EAGAIN on read and write. |
||||
|
|
||||
|
So...read and write must be able to notify about 3 states at least. |
||||
|
|
||||
|
1. I am fine...continue operation on me |
||||
|
2. I could not continue right now...please poll me |
||||
|
3. Don't do any further operation on me...please close me. |
||||
|
|
||||
|
This could be simply done with return values... |
||||
|
|
||||
|
for 1. Return value >= 0 |
||||
|
for 2. Return -1 STREAM_DO_POLL |
||||
|
for 3. Return -2 STREAM_DO_CLOSE |
||||
@ -0,0 +1,61 @@ |
|||||
|
/** |
||||
|
* \file |
||||
|
* Represents an asset (a file on disk) |
||||
|
* |
||||
|
* \author Georg Hopp |
||||
|
* |
||||
|
* \copyright |
||||
|
* Copyright © 2012 Georg Hopp |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef __ASSET_H__ |
||||
|
#define __ASSET_H__ |
||||
|
|
||||
|
#include <sys/types.h> |
||||
|
|
||||
|
#include "class.h" |
||||
|
#include "commons.h" |
||||
|
#include "hash.h" |
||||
|
|
||||
|
|
||||
|
CLASS(Asset) { |
||||
|
unsigned long hash; |
||||
|
|
||||
|
char fname[2049]; |
||||
|
char etag[200]; |
||||
|
char mtime[200]; |
||||
|
|
||||
|
size_t nfname; |
||||
|
size_t netag; |
||||
|
size_t nmtime; |
||||
|
|
||||
|
char * mime_type; |
||||
|
size_t nmime_type; |
||||
|
|
||||
|
int handle; |
||||
|
char * data; |
||||
|
size_t size; |
||||
|
|
||||
|
size_t ref_count; |
||||
|
}; |
||||
|
|
||||
|
Asset assetPoolGet(const char *, size_t); |
||||
|
size_t assetPoolRelease(Asset); |
||||
|
void assetPoolCleanup(void); |
||||
|
|
||||
|
#endif // __ASSET_H__ |
||||
|
|
||||
|
// vim: set ts=4 sw=4: |
||||
@ -0,0 +1,23 @@ |
|||||
|
/** |
||||
|
* As the initializations of cbufs is complicated and time consuming |
||||
|
* with all this shared memory initialization stuff and each cbuf |
||||
|
* always is the same (at least for this application) we don't free |
||||
|
* them after they are not used anymore. |
||||
|
* Instead we store the in this pool and reuse then the next time |
||||
|
* they are needed. |
||||
|
* |
||||
|
* Well thats the idea of this. |
||||
|
* |
||||
|
* OK, after review the code...it has been some time since I wrote it, |
||||
|
* I realize that only one cbuf is used right now. |
||||
|
* Each connection holds their unprocessed data in another heap reagion |
||||
|
* and reinitializes the ringbuffer each time with this. |
||||
|
* |
||||
|
* This seems both inefficient and error prone. So I will change this. |
||||
|
* The only question is, how large should our circular buffer be and |
||||
|
* how many connections do we expect in paralell... |
||||
|
* |
||||
|
* We need to have some handling to not accept any more connection |
||||
|
* when we reached the maximum amount for cbuffers and none is left in |
||||
|
* the pool. |
||||
|
*/ |
||||
@ -0,0 +1,138 @@ |
|||||
|
/** |
||||
|
* \file |
||||
|
* |
||||
|
* \author Georg Hopp |
||||
|
* |
||||
|
* \copyright |
||||
|
* Copyright © 2012 Georg Hopp |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef __TREE_H__ |
||||
|
#define __TREE_H__ |
||||
|
|
||||
|
#include "class.h" |
||||
|
|
||||
|
#define TREE_RIGHT(node) (NULL!=(node)?(node)->right:NULL) |
||||
|
#define TREE_LEFT(node) (NULL!=(node)?(node)->left:NULL) |
||||
|
#define TREE_PARENT(node) (NULL!=(node)?(node)->parent:NULL) |
||||
|
|
||||
|
#define TREE_CHILD(node) \ |
||||
|
(NULL==TREE_RIGHT((node))?TREE_LEFT((node)):TREE_RIGHT((node))) |
||||
|
|
||||
|
#define TREE_RIGHT_LEFT(node) \ |
||||
|
(NULL!=TREE_RIGHT((node))?TREE_LEFT(TREE_RIGHT((node))):NULL) |
||||
|
|
||||
|
#define TREE_LEFT_RIGHT(node) \ |
||||
|
(NULL!=TREE_LEFT((node))?TREE_RIGHT(TREE_LEFT((node))):NULL) |
||||
|
|
||||
|
#define TREE_SIBLING(node) \ |
||||
|
(NULL!=TREE_PARENT((node))? \ |
||||
|
((node)==TREE_PARENT((node))->left? \ |
||||
|
TREE_PARENT((node))->right: \ |
||||
|
TREE_PARENT((node))->left): \ |
||||
|
NULL) |
||||
|
|
||||
|
#define TREE_GRANDPARENT(node) \ |
||||
|
(NULL!=TREE_PARENT((node))?TREE_PARENT((node))->parent:NULL) |
||||
|
|
||||
|
#define TREE_UNCLE(node) \ |
||||
|
(NULL!=TREE_GRANDPARENT((node))? \ |
||||
|
(TREE_PARENT((node))==TREE_GRANDPARENT((node))->left? \ |
||||
|
TREE_GRANDPARENT((node))->right: \ |
||||
|
TREE_GRANDPARENT((node))->left): \ |
||||
|
NULL) |
||||
|
|
||||
|
#define TREE_ROTATE_LEFT(root, node) \ |
||||
|
do { \ |
||||
|
if (NULL != TREE_RIGHT_LEFT((node))) { \ |
||||
|
TREE_RIGHT_LEFT((node))->parent = (node); \ |
||||
|
} \ |
||||
|
TREE_RIGHT((node))->left = (node); \ |
||||
|
if (NULL != TREE_PARENT((node))) { \ |
||||
|
if (TREE_PARENT((node))->left==(node)) { \ |
||||
|
TREE_PARENT((node))->left = (node)->right; \ |
||||
|
} else { \ |
||||
|
TREE_PARENT((node))->right = (node)->right; \ |
||||
|
} \ |
||||
|
} else { \ |
||||
|
*(root) = (node)->right; \ |
||||
|
} \ |
||||
|
(node)->right = TREE_RIGHT_LEFT((node)); \ |
||||
|
(node)->parent = (node)->right; \ |
||||
|
TREE_RIGHT((node))->parent = (node)->parent; \ |
||||
|
} while(0) |
||||
|
|
||||
|
#define TREE_ROTATE_RIGHT(root, node) \ |
||||
|
do { \ |
||||
|
if (NULL != TREE_LEFT_RIGHT((node))) { \ |
||||
|
TREE_LEFT_RIGHT((node))->parent = (node); \ |
||||
|
} \ |
||||
|
TREE_LEFT((node))->right = (node); \ |
||||
|
if (NULL != TREE_PARENT((node))) { \ |
||||
|
if (TREE_PARENT((node))->left==(node)) { \ |
||||
|
TREE_PARENT((node))->left = (node)->left; \ |
||||
|
} else { \ |
||||
|
TREE_PARENT((node))->right = (node)->left; \ |
||||
|
} \ |
||||
|
} else { \ |
||||
|
*(root) = (node)->left; \ |
||||
|
} \ |
||||
|
TREE_LEFT((node))->parent = (node)->parent; \ |
||||
|
(node)->left = TREE_LEFT_RIGHT((node)); \ |
||||
|
(node)->parent = (node)->right; \ |
||||
|
} while(0) |
||||
|
|
||||
|
#define TREE_REPLACE_NODE(root, node1, node2) \ |
||||
|
do { \ |
||||
|
if (NULL != TREE_PARENT((node1))) { \ |
||||
|
if ((node1) == TREE_PARENT((node1))->left) { \ |
||||
|
TREE_PARENT((node1))->left = (node2); \ |
||||
|
} else { \ |
||||
|
TREE_PARENT((node1))->right = (node2); \ |
||||
|
} \ |
||||
|
} else { \ |
||||
|
*(root) = (node2); \ |
||||
|
} \ |
||||
|
if (NULL != (node2)) { \ |
||||
|
(node2)->parent = (node1)->parent; \ |
||||
|
} \ |
||||
|
} while(0) |
||||
|
|
||||
|
|
||||
|
enum rbColor {rbBlack=1, rbRed=2}; |
||||
|
|
||||
|
CLASS(Tree) { |
||||
|
void * data; |
||||
|
|
||||
|
enum rbColor color; |
||||
|
|
||||
|
Tree parent; |
||||
|
Tree left; |
||||
|
Tree right; |
||||
|
}; |
||||
|
|
||||
|
typedef int (*TreeComp)(const void *, const void *); |
||||
|
typedef void (*TreeAction)(const void *, const int); |
||||
|
|
||||
|
void * treeFind(Tree, const void *, TreeComp); |
||||
|
void * treeInsert(Tree *, const void *, TreeComp); |
||||
|
void * treeDelete(Tree *, const void *, TreeComp); |
||||
|
void treeWalk(Tree, TreeAction); |
||||
|
void treeDestroy(Tree *, TreeAction); |
||||
|
|
||||
|
#endif // __TREE_H__ |
||||
|
|
||||
|
// vim: set ts=4 sw=4: |
||||
@ -0,0 +1,31 @@ |
|||||
|
/** |
||||
|
* \file |
||||
|
* |
||||
|
* \author Georg Hopp |
||||
|
* |
||||
|
* \copyright |
||||
|
* Copyright © 2012 Georg Hopp |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef __UTILS_MIME_TYPE_H__ |
||||
|
#define __UTILS_MIME_TYPE_H__ |
||||
|
|
||||
|
char * getMimeType(const char *, size_t); |
||||
|
void clearMimeTypes(void); |
||||
|
|
||||
|
#endif // __UTILS_MIME_TYPE_H__ |
||||
|
|
||||
|
// vim: set ts=4 sw=4: |
||||
@ -0,0 +1,6 @@ |
|||||
|
ACLOCAL_AMFLAGS = -I m4 |
||||
|
|
||||
|
noinst_LIBRARIES = libasset.a |
||||
|
|
||||
|
libasset_a_SOURCES = asset.c pool.c |
||||
|
libasset_a_CFLAGS = $(CFLAGS) -Wall -I ../../include/ |
||||
@ -0,0 +1,140 @@ |
|||||
|
/** |
||||
|
* \file |
||||
|
* |
||||
|
* \author Georg Hopp |
||||
|
* |
||||
|
* \copyright |
||||
|
* Copyright © 2012 Georg Hopp |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#include <stdarg.h> |
||||
|
|
||||
|
// for mmap |
||||
|
#include <sys/mman.h> |
||||
|
|
||||
|
// for open and fstat |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/stat.h> |
||||
|
#include <fcntl.h> |
||||
|
|
||||
|
// for access |
||||
|
#include <unistd.h> |
||||
|
|
||||
|
// for localtime |
||||
|
#include <time.h> |
||||
|
|
||||
|
|
||||
|
#include "class.h" |
||||
|
#include "asset.h" |
||||
|
#include "hash.h" |
||||
|
|
||||
|
#include "utils/mime_type.h" |
||||
|
#include "utils/hash.h" |
||||
|
|
||||
|
|
||||
|
static |
||||
|
int |
||||
|
assetCtor(void * _this, va_list * params) |
||||
|
{ |
||||
|
Asset this = _this; |
||||
|
|
||||
|
struct tm * tmp; |
||||
|
struct stat st; |
||||
|
char * fname = va_arg(*params, char*); |
||||
|
char * ext; |
||||
|
|
||||
|
this->nfname = va_arg(*params, size_t); |
||||
|
|
||||
|
strncpy(this->fname, fname, 2048); |
||||
|
this->fname[2048] = '\0'; |
||||
|
|
||||
|
this->hash = sdbm( |
||||
|
(unsigned char *)this->fname, |
||||
|
this->nfname); |
||||
|
|
||||
|
if (-1 == access(this->fname, O_RDONLY)) { |
||||
|
return -1; |
||||
|
} else { |
||||
|
this->handle = open(this->fname, O_RDONLY); |
||||
|
fstat(this->handle, &st); |
||||
|
} |
||||
|
|
||||
|
tmp = localtime(&(st.st_mtime)); |
||||
|
this->netag = strftime(this->etag, sizeof(this->etag), "%s", tmp); |
||||
|
this->nmtime = strftime( |
||||
|
this->mtime, sizeof(this->mtime), "%a, %d %b %Y %T %Z", tmp); |
||||
|
|
||||
|
this->size = st.st_size; |
||||
|
|
||||
|
ext = strrchr(this->fname, '.'); |
||||
|
if (NULL != ext) { |
||||
|
ext++; |
||||
|
this->mime_type = getMimeType(ext, strlen(ext)); |
||||
|
} else { |
||||
|
this->mime_type = "application/octet-stream"; |
||||
|
} |
||||
|
|
||||
|
if (NULL != this->mime_type) { |
||||
|
this->nmime_type = strlen(this->mime_type); |
||||
|
} else { |
||||
|
this->nmime_type = 0; |
||||
|
} |
||||
|
|
||||
|
this->data = mmap( |
||||
|
NULL, this->size, PROT_READ, MAP_PRIVATE, this->handle, 0); |
||||
|
|
||||
|
if (MAP_FAILED == this->data) { |
||||
|
close(this->handle); |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
this->ref_count = 1; |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
static void assetDtor(void * _this) { |
||||
|
Asset this = _this; |
||||
|
|
||||
|
if (MAP_FAILED != this->data && NULL != this->data) { |
||||
|
munmap(this->data, this->size); |
||||
|
} |
||||
|
|
||||
|
if (0 < this->handle) { |
||||
|
close(this->handle); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
unsigned long |
||||
|
assetGetHash(void * _this) |
||||
|
{ |
||||
|
Asset this = _this; |
||||
|
|
||||
|
return this->hash; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
void |
||||
|
assetHandleDouble(void * _this, void * _doub) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
INIT_IFACE(Class, assetCtor, assetDtor, NULL); |
||||
|
INIT_IFACE(Hashable, assetGetHash, assetHandleDouble); |
||||
|
CREATE_CLASS(Asset, NULL, IFACE(Class), IFACE(Hashable)); |
||||
|
|
||||
|
// vim: set ts=4 sw=4: |
||||
@ -0,0 +1,94 @@ |
|||||
|
/** |
||||
|
* \file |
||||
|
* |
||||
|
* \author Georg Hopp |
||||
|
* |
||||
|
* \copyright |
||||
|
* Copyright © 2012 Georg Hopp |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
// for size_t |
||||
|
#include <sys/types.h> |
||||
|
|
||||
|
// for strlen |
||||
|
|
||||
|
#include "class.h" |
||||
|
#include "asset.h" |
||||
|
#include "hash.h" |
||||
|
|
||||
|
Hash asset_pool = NULL; |
||||
|
|
||||
|
static |
||||
|
inline |
||||
|
void |
||||
|
freeAsset(const void * _node) |
||||
|
{ |
||||
|
delete(_node); |
||||
|
} |
||||
|
|
||||
|
Asset |
||||
|
assetPoolGet(const char * path, size_t npath) |
||||
|
{ |
||||
|
Asset asset = NULL; |
||||
|
|
||||
|
if (NULL == asset_pool) { |
||||
|
asset_pool = new(Hash); |
||||
|
} else { |
||||
|
asset = hashGet(asset_pool, path, npath); |
||||
|
} |
||||
|
|
||||
|
if (NULL == asset) { |
||||
|
asset = new(Asset, path, npath); |
||||
|
hashAdd(asset_pool, asset); |
||||
|
} else { |
||||
|
asset->ref_count++; |
||||
|
} |
||||
|
|
||||
|
return asset; |
||||
|
} |
||||
|
|
||||
|
size_t |
||||
|
assetPoolRelease(Asset asset) |
||||
|
{ |
||||
|
if (asset->ref_count > 1) { |
||||
|
asset->ref_count--; |
||||
|
return asset->ref_count; |
||||
|
} |
||||
|
|
||||
|
if (NULL != asset) { |
||||
|
Asset found = (Asset)hashDelete( |
||||
|
asset_pool, asset->fname, asset->nfname); |
||||
|
|
||||
|
if (found == asset) { |
||||
|
delete(found); |
||||
|
} else { |
||||
|
// this should never happen....error log... |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
assetPoolCleanup(void) |
||||
|
{ |
||||
|
if (NULL != asset_pool) { |
||||
|
hashEach(asset_pool, freeAsset); |
||||
|
delete(asset_pool); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// vim: set ts=4 sw=4: |
||||
@ -0,0 +1,303 @@ |
|||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
|
||||
|
|
||||
|
struct element |
||||
|
{ |
||||
|
int data; |
||||
|
|
||||
|
struct element * parent; |
||||
|
struct element * left; |
||||
|
struct element * right; |
||||
|
}; |
||||
|
|
||||
|
struct element * |
||||
|
newElement(int data) |
||||
|
{ |
||||
|
struct element * el = malloc(sizeof(struct element)); |
||||
|
el->data = data; |
||||
|
el->parent = NULL; |
||||
|
el->left = NULL; |
||||
|
el->right = NULL; |
||||
|
|
||||
|
return el; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* find element in tree |
||||
|
*/ |
||||
|
struct element * |
||||
|
findElement(struct element * tree, int data) |
||||
|
{ |
||||
|
while (NULL != tree) { |
||||
|
if (tree->data == data) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if (data < tree->data) { |
||||
|
tree = tree->left; |
||||
|
} else { |
||||
|
tree = tree->right; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return tree; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* insert element in tree |
||||
|
*/ |
||||
|
void |
||||
|
insertElement(struct element ** tree, int data) |
||||
|
{ |
||||
|
struct element * node = *tree; |
||||
|
|
||||
|
if (NULL == node) { |
||||
|
*tree = newElement(data); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
while (data != node->data) { |
||||
|
if (data < node->data) { |
||||
|
if (NULL == node->left) { |
||||
|
node->left = newElement(data); |
||||
|
node->left->parent = node; |
||||
|
return; |
||||
|
} else { |
||||
|
node = node->left; |
||||
|
} |
||||
|
} else { |
||||
|
if (NULL == node->right) { |
||||
|
node->right = newElement(data); |
||||
|
node->right->parent = node; |
||||
|
return; |
||||
|
} else { |
||||
|
node = node->right; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* delete element from tree |
||||
|
* here multiple functions are involved.... |
||||
|
* ======================================================================= |
||||
|
*/ |
||||
|
/** |
||||
|
* find minimum of the right subtree aka leftmost leaf of right subtree |
||||
|
* aka left in-order successor. |
||||
|
* We return the parent of the element in the out argument parent. |
||||
|
* This can be NULL wenn calling. |
||||
|
*/ |
||||
|
struct element * |
||||
|
findInOrderSuccessor(struct element * tree) |
||||
|
{ |
||||
|
struct element * node = tree->right; |
||||
|
|
||||
|
while (NULL != node->left) { |
||||
|
node = node->left; |
||||
|
} |
||||
|
|
||||
|
return node; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
deleteElement(struct element ** tree, int data) |
||||
|
{ |
||||
|
struct element * node = *tree; |
||||
|
|
||||
|
// find the relevant node and it's parent |
||||
|
while (NULL != node && node->data != data) { |
||||
|
if (data < node->data) { |
||||
|
node = node->left; |
||||
|
} else { |
||||
|
node = node->right; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// element not found |
||||
|
if (NULL == node) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// distinuish 3 cases, where the resolving of each case leads to the |
||||
|
// precondition of the other. |
||||
|
|
||||
|
// case 1: two children |
||||
|
if (NULL != node->left && NULL != node->right) { |
||||
|
struct element * successor = findInOrderSuccessor(node); |
||||
|
|
||||
|
node->data = successor->data; |
||||
|
node = successor; |
||||
|
} |
||||
|
|
||||
|
// case 2: one child wither left or right |
||||
|
if (NULL != node->left) { |
||||
|
//node->data = node->left->data; |
||||
|
//node = node->left; |
||||
|
if (NULL != node->parent) { |
||||
|
if (node == node->parent->left) { |
||||
|
node->parent->left = node->left; |
||||
|
} else { |
||||
|
node->parent->right = node->left; |
||||
|
} |
||||
|
} |
||||
|
node->left->parent = node->parent; |
||||
|
} |
||||
|
|
||||
|
if (NULL != node->right) { |
||||
|
//node->data = node->right->data; |
||||
|
//node = node->right; |
||||
|
if (NULL != node->parent) { |
||||
|
if (node == node->parent->left) { |
||||
|
node->parent->left = node->right; |
||||
|
} else { |
||||
|
node->parent->right = node->right; |
||||
|
} |
||||
|
} |
||||
|
node->right->parent = node->parent; |
||||
|
} |
||||
|
|
||||
|
// case 3: we are a leaf |
||||
|
if (NULL != node->parent) { |
||||
|
if (node == node->parent->left) { |
||||
|
node->parent->left = NULL; |
||||
|
} else { |
||||
|
node->parent->right = NULL; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (node == *tree) { |
||||
|
if (NULL != node->left) { |
||||
|
*tree = node->left; |
||||
|
} else if (NULL != node->right) { |
||||
|
*tree = node->right; |
||||
|
} else { |
||||
|
*tree = NULL; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
free(node); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void |
||||
|
traverse(struct element * tree, void (*cb)(int, int)) |
||||
|
{ |
||||
|
struct element * previous = tree; |
||||
|
struct element * node = tree; |
||||
|
int depth = 1; |
||||
|
|
||||
|
/* |
||||
|
* I think this has something like O(n+log(n)) on a ballanced |
||||
|
* tree because I have to traverse back the rightmost leaf to |
||||
|
* the root to get a break condition. |
||||
|
*/ |
||||
|
while (node) { |
||||
|
/* |
||||
|
* If we come from the right so nothing and go to our |
||||
|
* next parent. |
||||
|
*/ |
||||
|
if (previous == node->right) { |
||||
|
previous = node; |
||||
|
node = node->parent; |
||||
|
depth--; |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if ((NULL == node->left || previous == node->left)) { |
||||
|
/* |
||||
|
* If there are no more elements to the left or we |
||||
|
* came from the left, process data. |
||||
|
*/ |
||||
|
cb(node->data, depth); |
||||
|
previous = node; |
||||
|
|
||||
|
if (NULL != node->right) { |
||||
|
node = node->right; |
||||
|
depth++; |
||||
|
} else { |
||||
|
node = node->parent; |
||||
|
depth--; |
||||
|
} |
||||
|
} else { |
||||
|
/* |
||||
|
* if there are more elements to the left go there. |
||||
|
*/ |
||||
|
previous = node; |
||||
|
node = node->left; |
||||
|
depth++; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void printElement(int data, int depth) |
||||
|
{ |
||||
|
int i; |
||||
|
|
||||
|
printf("%02d(%02d)", data, depth); |
||||
|
for (i=0; i<depth; i++) printf("-"); |
||||
|
puts(""); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* ======================================================================= |
||||
|
*/ |
||||
|
int |
||||
|
main(int argc, char * argv[]) |
||||
|
{ |
||||
|
struct element * root = NULL; |
||||
|
|
||||
|
insertElement(&root, 13); |
||||
|
insertElement(&root, 8); |
||||
|
insertElement(&root, 16); |
||||
|
insertElement(&root, 11); |
||||
|
insertElement(&root, 3); |
||||
|
insertElement(&root, 9); |
||||
|
insertElement(&root, 12); |
||||
|
insertElement(&root, 10); |
||||
|
|
||||
|
/* |
||||
|
* delete does not work correctly here.. |
||||
|
* luckily I do not need the simple binary trees anymore |
||||
|
* as I have rbtrees. |
||||
|
*/ |
||||
|
puts("traverse"); |
||||
|
traverse(root, printElement); |
||||
|
|
||||
|
deleteElement(&root, 8); |
||||
|
puts("traverse"); |
||||
|
traverse(root, printElement); |
||||
|
|
||||
|
deleteElement(&root, 11); |
||||
|
puts("traverse"); |
||||
|
traverse(root, printElement); |
||||
|
|
||||
|
deleteElement(&root, 13); |
||||
|
puts("traverse"); |
||||
|
traverse(root, printElement); |
||||
|
|
||||
|
deleteElement(&root, 3); |
||||
|
puts("traverse"); |
||||
|
traverse(root, printElement); |
||||
|
|
||||
|
deleteElement(&root, 16); |
||||
|
puts("traverse"); |
||||
|
traverse(root, printElement); |
||||
|
|
||||
|
deleteElement(&root, 10); |
||||
|
puts("traverse"); |
||||
|
traverse(root, printElement); |
||||
|
|
||||
|
deleteElement(&root, 9); |
||||
|
puts("traverse"); |
||||
|
traverse(root, printElement); |
||||
|
|
||||
|
deleteElement(&root, 12); |
||||
|
puts("traverse"); |
||||
|
traverse(root, printElement); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
// vim: set et ts=4 sw=4: |
||||
@ -0,0 +1,10 @@ |
|||||
|
/** |
||||
|
* As the initializations of cbufs is complicated and time consuming |
||||
|
* with all this shared memory initialization stuff and each cbuf |
||||
|
* always is the same (at least for this application) we don't free |
||||
|
* them after they are not used anymore. |
||||
|
* Instead we store the in this pool and reuse then the next time |
||||
|
* they are needed. |
||||
|
* |
||||
|
* Well thats the idea of this. |
||||
|
*/ |
||||
@ -0,0 +1,54 @@ |
|||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
|
||||
|
#include "class.h" |
||||
|
#include "commons.h" |
||||
|
#include "utils/memory.h" |
||||
|
|
||||
|
#include "hash.h" |
||||
|
#include "utils/memory.h" |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* ======================================================================= |
||||
|
*/ |
||||
|
int |
||||
|
main(int argc, char * argv[]) |
||||
|
{ |
||||
|
Hash hash = new(Hash); |
||||
|
HashValue deleted; |
||||
|
|
||||
|
hashAdd(hash, new(HashValue, CSTRA("foo"), CSTRA("bar"))); |
||||
|
hashAdd(hash, new(HashValue, CSTRA("hjkfdd"), CSTRA("bar"))); |
||||
|
hashAdd(hash, new(HashValue, CSTRA("j8frheff"), CSTRA("bar"))); |
||||
|
hashAdd(hash, new(HashValue, CSTRA("f9e0g"), CSTRA("bar"))); |
||||
|
hashAdd(hash, new(HashValue, CSTRA("gfrk9e0"), CSTRA("bar"))); |
||||
|
hashAdd(hash, new(HashValue, CSTRA("fr09ie"), CSTRA("bar"))); |
||||
|
hashAdd(hash, new(HashValue, CSTRA("fu8de9"), CSTRA("bar"))); |
||||
|
hashAdd(hash, new(HashValue, CSTRA("rehw78"), CSTRA("bar"))); |
||||
|
hashAdd(hash, new(HashValue, CSTRA("fcrne9"), CSTRA("bar"))); |
||||
|
hashAdd(hash, new(HashValue, CSTRA("new8"), CSTRA("bar"))); |
||||
|
hashAdd(hash, new(HashValue, CSTRA("fdhe78"), CSTRA("bar"))); |
||||
|
hashAdd(hash, new(HashValue, CSTRA("dhew8"), CSTRA("bar"))); |
||||
|
hashAdd(hash, new(HashValue, CSTRA("jfde9w8"), CSTRA("bar"))); |
||||
|
hashAdd(hash, new(HashValue, CSTRA("dhe7w89"), CSTRA("bar"))); |
||||
|
hashAdd(hash, new(HashValue, CSTRA("fduew89"), CSTRA("bar"))); |
||||
|
|
||||
|
deleted = hashDelete(hash, CSTRA("f9e0g")); |
||||
|
delete(deleted); |
||||
|
deleted = hashDelete(hash, CSTRA("fcrne9")); |
||||
|
delete(deleted); |
||||
|
deleted = hashDelete(hash, CSTRA("fr09ie")); |
||||
|
delete(deleted); |
||||
|
deleted = hashDelete(hash, CSTRA("jfde9w8")); |
||||
|
delete(deleted); |
||||
|
deleted = hashDelete(hash, CSTRA("j8frheff")); |
||||
|
delete(deleted); |
||||
|
|
||||
|
delete(hash); |
||||
|
memCleanup(); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
// vim: set et ts=4 sw=4: |
||||
@ -0,0 +1,65 @@ |
|||||
|
/** |
||||
|
* \file |
||||
|
* |
||||
|
* \author Georg Hopp |
||||
|
* |
||||
|
* \copyright |
||||
|
* Copyright © 2012 Georg Hopp |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#include <stdlib.h> |
||||
|
#include <string.h> |
||||
|
#include <stdio.h> |
||||
|
#include <sys/types.h> |
||||
|
|
||||
|
#include "class.h" |
||||
|
|
||||
|
#include "http/response.h" |
||||
|
#include "http/message.h" |
||||
|
#include "http/header.h" |
||||
|
|
||||
|
#include "utils/memory.h" |
||||
|
#include "hash.h" |
||||
|
|
||||
|
#define RESP_DATA "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n" \ |
||||
|
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" \ |
||||
|
" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" \ |
||||
|
"<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n" \ |
||||
|
"<head><title>500 - Internal Server Error</title></head>" \ |
||||
|
"<body><h1>500 - Internal Server Error</h1></body>" \ |
||||
|
"</html>" |
||||
|
|
||||
|
|
||||
|
HttpResponse |
||||
|
httpResponse500() |
||||
|
{ |
||||
|
HttpResponse response; |
||||
|
HttpMessage message; |
||||
|
|
||||
|
response = new(HttpResponse, "HTTP/1.1", 500, "Internal Server Error"); |
||||
|
message = (HttpMessage)response; |
||||
|
|
||||
|
hashAdd(message->header, |
||||
|
new(HttpHeader, CSTRA("Content-Type"), CSTRA("text/html"))); |
||||
|
|
||||
|
message->nbody = sizeof(RESP_DATA) - 1; |
||||
|
message->body = memMalloc(sizeof(RESP_DATA)); |
||||
|
memcpy(message->body, RESP_DATA, sizeof(RESP_DATA)); |
||||
|
|
||||
|
return response; |
||||
|
} |
||||
|
|
||||
|
// vim: set ts=4 sw=4: |
||||
@ -0,0 +1,55 @@ |
|||||
|
// for mmap |
||||
|
#include <sys/mman.h> |
||||
|
|
||||
|
// for random |
||||
|
#include <stdlib.h> |
||||
|
|
||||
|
// for open and fstat |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/stat.h> |
||||
|
#include <fcntl.h> |
||||
|
|
||||
|
// for puts |
||||
|
#include <stdio.h> |
||||
|
|
||||
|
// for time |
||||
|
#include <time.h> |
||||
|
|
||||
|
int |
||||
|
main(int argc, char * argv[]) |
||||
|
{ |
||||
|
struct stat st; |
||||
|
char * map; |
||||
|
size_t position; |
||||
|
char print_buf[101]; |
||||
|
int i; |
||||
|
|
||||
|
print_buf[100] = '\0'; |
||||
|
|
||||
|
int fd = open("./mmapfiletest.c", O_RDONLY); |
||||
|
|
||||
|
fstat(fd, &st); |
||||
|
map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); |
||||
|
|
||||
|
srandom(time(NULL)); |
||||
|
position = random() % (st.st_size - 100); |
||||
|
|
||||
|
for (i=0; i<100; i+=10) { |
||||
|
print_buf[i+0] = map[position + i + 0]; |
||||
|
print_buf[i+1] = map[position + i + 1]; |
||||
|
print_buf[i+2] = map[position + i + 2]; |
||||
|
print_buf[i+3] = map[position + i + 3]; |
||||
|
print_buf[i+4] = map[position + i + 4]; |
||||
|
print_buf[i+5] = map[position + i + 5]; |
||||
|
print_buf[i+6] = map[position + i + 6]; |
||||
|
print_buf[i+7] = map[position + i + 7]; |
||||
|
print_buf[i+8] = map[position + i + 8]; |
||||
|
print_buf[i+9] = map[position + i + 9]; |
||||
|
} |
||||
|
|
||||
|
puts(print_buf); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
// vim: set et ts=4 sw=4: |
||||
@ -0,0 +1,54 @@ |
|||||
|
// for random |
||||
|
#include <stdlib.h> |
||||
|
|
||||
|
// for puts |
||||
|
#include <stdio.h> |
||||
|
|
||||
|
// for time |
||||
|
#include <time.h> |
||||
|
|
||||
|
#include "class.h" |
||||
|
#include "commons.h" |
||||
|
#include "utils/memory.h" |
||||
|
|
||||
|
#include "asset.h" |
||||
|
|
||||
|
int |
||||
|
main(int argc, char * argv[]) |
||||
|
{ |
||||
|
size_t i; |
||||
|
size_t position; |
||||
|
char print_buf[101]; |
||||
|
|
||||
|
Asset asset = new(Asset, CSTRA("./src/mmapfiletest.c")); |
||||
|
|
||||
|
print_buf[100] = '\0'; |
||||
|
|
||||
|
srandom(time(NULL)); |
||||
|
position = random() % (asset->size - 100); |
||||
|
|
||||
|
for (i=0; i<100; i+=10) { |
||||
|
print_buf[i+0] = asset->data[position+i+0]; |
||||
|
print_buf[i+1] = asset->data[position+i+1]; |
||||
|
print_buf[i+2] = asset->data[position+i+2]; |
||||
|
print_buf[i+3] = asset->data[position+i+3]; |
||||
|
print_buf[i+4] = asset->data[position+i+4]; |
||||
|
print_buf[i+5] = asset->data[position+i+5]; |
||||
|
print_buf[i+6] = asset->data[position+i+6]; |
||||
|
print_buf[i+7] = asset->data[position+i+7]; |
||||
|
print_buf[i+8] = asset->data[position+i+8]; |
||||
|
print_buf[i+9] = asset->data[position+i+9]; |
||||
|
} |
||||
|
|
||||
|
if (NULL != asset->mime_type) { |
||||
|
puts(asset->mime_type); |
||||
|
} |
||||
|
puts(print_buf); |
||||
|
|
||||
|
delete(asset); |
||||
|
memCleanup(); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
// vim: set et ts=4 sw=4: |
||||
@ -0,0 +1,797 @@ |
|||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
#define NVALUES 10 |
||||
|
|
||||
|
enum rbColor {rbBlack=1, rbRed=2}; |
||||
|
|
||||
|
|
||||
|
struct element |
||||
|
{ |
||||
|
size_t size; |
||||
|
void * ptr; |
||||
|
|
||||
|
enum rbColor color; |
||||
|
|
||||
|
struct element * next; |
||||
|
struct element * last; |
||||
|
|
||||
|
struct element * parent; |
||||
|
struct element * left; |
||||
|
struct element * right; |
||||
|
}; |
||||
|
|
||||
|
struct element * |
||||
|
newElement(size_t size) |
||||
|
{ |
||||
|
struct element * element = malloc(size + sizeof(struct element)); |
||||
|
|
||||
|
element->size = size; |
||||
|
element->ptr = element + sizeof(struct element); |
||||
|
|
||||
|
element->next = NULL; |
||||
|
element->last = NULL; |
||||
|
|
||||
|
element->color = rbRed; |
||||
|
element->parent = NULL; |
||||
|
element->left = NULL; |
||||
|
element->right = NULL; |
||||
|
|
||||
|
return element; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* find element in tree |
||||
|
*/ |
||||
|
struct element * |
||||
|
findElement(struct element * tree, size_t size) |
||||
|
{ |
||||
|
struct element * fitting = NULL; |
||||
|
|
||||
|
while (NULL != tree) { |
||||
|
if (tree->size == size) { |
||||
|
fitting = tree; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if (size > tree->size) { |
||||
|
tree = tree->right; |
||||
|
} else { |
||||
|
fitting = tree; |
||||
|
tree = tree->left; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return fitting; |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* function to get specific elements needed for |
||||
|
* rb handling, grandparent, uncle and sibbling |
||||
|
*/ |
||||
|
struct element * |
||||
|
grandparent(struct element * node) |
||||
|
{ |
||||
|
if (NULL != node && NULL != node->parent) { |
||||
|
return node->parent->parent; |
||||
|
} |
||||
|
|
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
struct element * |
||||
|
uncle(struct element * node) |
||||
|
{ |
||||
|
struct element * gp = grandparent(node); |
||||
|
|
||||
|
if (NULL == gp) { |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
if (node->parent == gp->left) { |
||||
|
return gp->right; |
||||
|
} |
||||
|
|
||||
|
return gp->left; |
||||
|
} |
||||
|
|
||||
|
struct element * |
||||
|
sibling(struct element * node) |
||||
|
{ |
||||
|
if (NULL == node) { |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
if (NULL == node->parent->left || node == node->parent->left) { |
||||
|
return node->parent->right; |
||||
|
} else { |
||||
|
return node->parent->left; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* tree modifications...needed for rb handling. |
||||
|
*/ |
||||
|
void |
||||
|
rotateLeft(struct element ** tree, struct element * node) |
||||
|
{ |
||||
|
struct element * rightChild = node->right; |
||||
|
struct element * rcLeftSub = node->right->left; |
||||
|
|
||||
|
rightChild->left = node; |
||||
|
rightChild->parent = node->parent; |
||||
|
node->right = rcLeftSub; |
||||
|
if (NULL != rcLeftSub) { |
||||
|
rcLeftSub->parent = node; |
||||
|
} |
||||
|
|
||||
|
if (node->parent) { |
||||
|
if (node->parent->left == node) { |
||||
|
node->parent->left = rightChild; |
||||
|
} else { |
||||
|
node->parent->right = rightChild; |
||||
|
} |
||||
|
} else { |
||||
|
*tree = rightChild; |
||||
|
} |
||||
|
|
||||
|
node->parent = rightChild; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
rotateRight(struct element ** tree, struct element * node) |
||||
|
{ |
||||
|
struct element * leftChild = node->left; |
||||
|
struct element * lcRightSub = node->left->right; |
||||
|
|
||||
|
leftChild->right = node; |
||||
|
leftChild->parent = node->parent; |
||||
|
node->left = lcRightSub; |
||||
|
if (NULL != lcRightSub) { |
||||
|
lcRightSub->parent = node; |
||||
|
} |
||||
|
|
||||
|
if (node->parent) { |
||||
|
if (node->parent->left == node) { |
||||
|
node->parent->left = leftChild; |
||||
|
} else { |
||||
|
node->parent->right = leftChild; |
||||
|
} |
||||
|
} else { |
||||
|
*tree = leftChild; |
||||
|
} |
||||
|
|
||||
|
node->parent = leftChild; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
replaceNode( |
||||
|
struct element ** tree, |
||||
|
struct element * node1, |
||||
|
struct element * node2) |
||||
|
{ |
||||
|
if (NULL != node1->parent) { |
||||
|
if (node1 == node1->parent->left) { |
||||
|
node1->parent->left = node2; |
||||
|
} else { |
||||
|
node1->parent->right = node2; |
||||
|
} |
||||
|
} else { |
||||
|
*tree = node2; |
||||
|
} |
||||
|
|
||||
|
if (NULL != node2) { |
||||
|
node2->parent = node1->parent; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* insert element in tree |
||||
|
*/ |
||||
|
struct element * |
||||
|
insertElement(struct element ** tree, struct element * element) |
||||
|
{ |
||||
|
struct element * node = *tree; |
||||
|
struct element * new_node = NULL; |
||||
|
struct element * u; |
||||
|
struct element * g; |
||||
|
|
||||
|
element->next = NULL; |
||||
|
element->last = NULL; |
||||
|
|
||||
|
element->color = rbRed; |
||||
|
element->parent = NULL; |
||||
|
element->left = NULL; |
||||
|
element->right = NULL; |
||||
|
|
||||
|
// if tree is empty it's simple... :) |
||||
|
if (NULL == node) { |
||||
|
*tree = node = new_node = element; |
||||
|
} else { |
||||
|
// normal binary tree add.... |
||||
|
while (NULL != node) { |
||||
|
if (element->size < node->size) { |
||||
|
if (NULL == node->left) { |
||||
|
node->left = element; |
||||
|
node->left->parent = node; |
||||
|
new_node = node = node->left; |
||||
|
break; |
||||
|
} else { |
||||
|
node = node->left; |
||||
|
} |
||||
|
} else if (element->size > node->size) { |
||||
|
if (NULL == node->right) { |
||||
|
node->right = element; |
||||
|
node->right->parent = node; |
||||
|
new_node = node = node->right; |
||||
|
break; |
||||
|
} else { |
||||
|
node = node->right; |
||||
|
} |
||||
|
} else { |
||||
|
if (NULL == node->next) { |
||||
|
node->next = element; |
||||
|
node->last = element; |
||||
|
} else { |
||||
|
node->last->next = element; |
||||
|
node->last = element; |
||||
|
} |
||||
|
return node; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (NULL != new_node) { |
||||
|
/* |
||||
|
* handle reballancing rb style |
||||
|
*/ |
||||
|
while (1) { |
||||
|
// case 1 |
||||
|
if (node->parent == NULL) { |
||||
|
node->color = rbBlack; |
||||
|
// we're done.... :) |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
// case 2 |
||||
|
if (node->parent->color == rbBlack) { |
||||
|
// Tree is still valid ... wow, again we're done... :) |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
// case 3 |
||||
|
u = uncle(node); |
||||
|
g = grandparent(node); |
||||
|
|
||||
|
if (u != NULL && u->color == rbRed) { |
||||
|
node->parent->color = rbBlack; |
||||
|
u->color = rbBlack; |
||||
|
g->color = rbRed; |
||||
|
|
||||
|
node = g; |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
// case 4 |
||||
|
if (node == node->parent->right && node->parent == g->left) { |
||||
|
rotateLeft(tree, node->parent); |
||||
|
node = node->left; |
||||
|
} else if (node == node->parent->left && node->parent == g->right) { |
||||
|
|
||||
|
rotateRight(tree, node->parent); |
||||
|
node = node->right; |
||||
|
} |
||||
|
|
||||
|
// case 5 |
||||
|
g = grandparent(node); |
||||
|
|
||||
|
node->parent->color = rbBlack; |
||||
|
g->color = rbRed; |
||||
|
|
||||
|
if (node == node->parent->left) { |
||||
|
rotateRight(tree, g); |
||||
|
} else { |
||||
|
rotateLeft(tree, g); |
||||
|
} |
||||
|
|
||||
|
// we're done.. |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return new_node; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* delete element from tree |
||||
|
* here multiple functions are involved.... |
||||
|
* ======================================================================= |
||||
|
*/ |
||||
|
/** |
||||
|
* find minimum of the right subtree aka leftmost leaf of right subtree |
||||
|
* aka left in-order successor. |
||||
|
* We return the parent of the element in the out argument parent. |
||||
|
* This can be NULL wenn calling. |
||||
|
* |
||||
|
* 2: *successor = {size = 80, ptr = 0x603ae0, color = rbRed, parent = 0x603160, |
||||
|
* left = 0x0, right = 0x0} |
||||
|
* 1: *node = {size = 70, ptr = 0x603a60, color = rbBlack, parent = 0x603070, |
||||
|
* left = 0x6030e0, right = 0x6031e0} |
||||
|
* |
||||
|
*/ |
||||
|
struct element * |
||||
|
findInOrderSuccessor(struct element * tree) |
||||
|
{ |
||||
|
struct element * node = tree->right; |
||||
|
|
||||
|
while (NULL != node->left) { |
||||
|
node = node->left; |
||||
|
} |
||||
|
|
||||
|
return node; |
||||
|
} |
||||
|
|
||||
|
struct element * deleteOneChild(struct element **, struct element *); |
||||
|
|
||||
|
struct element * |
||||
|
deleteElement(struct element ** tree, struct element * element) |
||||
|
{ |
||||
|
struct element * node = *tree; |
||||
|
struct element * del_node; |
||||
|
struct element * child; |
||||
|
struct element * s; |
||||
|
|
||||
|
// find the relevant node and it's parent |
||||
|
while (NULL != node) { |
||||
|
|
||||
|
if (element->size < node->size) { |
||||
|
node = node->left; |
||||
|
} else if (element->size > node->size) { |
||||
|
node = node->right; |
||||
|
} else { |
||||
|
if (NULL != node->next) { |
||||
|
if (NULL != node->parent) { |
||||
|
if (node == node->parent->left) { |
||||
|
node->parent->left = node->next; |
||||
|
} else { |
||||
|
node->parent->right = node->next; |
||||
|
} |
||||
|
} else { |
||||
|
*tree = node->next; |
||||
|
} |
||||
|
|
||||
|
if (NULL != node->left) { |
||||
|
node->left->parent = node->next; |
||||
|
} |
||||
|
|
||||
|
if (NULL != node->right) { |
||||
|
node->right->parent = node->next; |
||||
|
} |
||||
|
|
||||
|
node->next->last = node->last; |
||||
|
node->next->color = node->color; |
||||
|
node->next->parent = node->parent; |
||||
|
node->next->left = node->left; |
||||
|
node->next->right = node->right; |
||||
|
|
||||
|
return node; |
||||
|
} |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// element not found |
||||
|
if (NULL == node) { |
||||
|
return node; |
||||
|
} |
||||
|
|
||||
|
del_node = node; |
||||
|
|
||||
|
// now our cases follows...the first one is the same as with |
||||
|
// simple binary search trees. Two non null children. |
||||
|
|
||||
|
// case 1: two children |
||||
|
if (NULL != node->left && NULL != node->right) { |
||||
|
struct element * successor = findInOrderSuccessor(node); |
||||
|
|
||||
|
enum rbColor tmpcolor = successor->color; |
||||
|
struct element * tmpparent = successor->parent; |
||||
|
struct element * tmpleft = successor->left; |
||||
|
struct element * tmpright = successor->right; |
||||
|
|
||||
|
replaceNode(tree, node, successor); |
||||
|
|
||||
|
successor->color = node->color; |
||||
|
successor->left = node->left; |
||||
|
successor->left->parent = successor; |
||||
|
// the right one might be successor... |
||||
|
if (node->right == successor) { |
||||
|
successor->right = node; |
||||
|
node->parent = successor; |
||||
|
} else { |
||||
|
successor->right = node->right; |
||||
|
node->right->parent = successor; |
||||
|
node->parent = tmpparent; |
||||
|
tmpparent->left = node; |
||||
|
} |
||||
|
|
||||
|
node->color = tmpcolor; |
||||
|
node->left = tmpleft; |
||||
|
node->right = tmpright; |
||||
|
} |
||||
|
|
||||
|
// Precondition: n has at most one non-null child. |
||||
|
child = (NULL == node->right) ? node->left : node->right; |
||||
|
replaceNode(tree, node, child); |
||||
|
|
||||
|
// delete one child case |
||||
|
// TODO this is overly complex as simply derived from the function... |
||||
|
// maybe this can be simplified. Maybe not...check. |
||||
|
if (node->color == rbBlack) { |
||||
|
if (NULL != child && child->color == rbRed) { |
||||
|
child->color = rbBlack; |
||||
|
// done despite modifying tree itself if neccessary.. |
||||
|
return del_node; |
||||
|
} else { |
||||
|
if (NULL != child) { |
||||
|
node = child; |
||||
|
} else { |
||||
|
node->color = rbBlack; |
||||
|
node->left = NULL; |
||||
|
node->right = NULL; |
||||
|
} |
||||
|
} |
||||
|
} else { |
||||
|
return del_node; |
||||
|
} |
||||
|
|
||||
|
// delete and rb rebalance... |
||||
|
while(1) { |
||||
|
// case 1 |
||||
|
if (NULL == node->parent) { |
||||
|
// done again |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
// case 2 |
||||
|
s = sibling(node); |
||||
|
|
||||
|
if (NULL != s && s->color == rbRed) { |
||||
|
node->parent->color = rbRed; |
||||
|
s->color = rbBlack; |
||||
|
|
||||
|
/* |
||||
|
* detect which child we are...assumption |
||||
|
* if we are not parent->right and parent->right is not |
||||
|
* null we must be left, even if its set to NULL previously |
||||
|
*/ |
||||
|
if (NULL != node->parent->right && node != node->parent->right) { |
||||
|
rotateLeft(tree, node->parent); |
||||
|
} else { |
||||
|
rotateRight(tree, node->parent); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
s = sibling(node); |
||||
|
// case 3 / 4 |
||||
|
if (NULL == s || ((s->color == rbBlack) && |
||||
|
(NULL == s->left || s->left->color == rbBlack) && |
||||
|
(NULL == s->right || s->right->color == rbBlack))) { |
||||
|
|
||||
|
if (NULL != s) { |
||||
|
s->color = rbRed; |
||||
|
} |
||||
|
|
||||
|
if (node->parent->color == rbBlack) { |
||||
|
// case 3 |
||||
|
node = node->parent; |
||||
|
continue; |
||||
|
} else { |
||||
|
// case 4 |
||||
|
node->parent->color = rbBlack; |
||||
|
// and done again... |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// case 5 |
||||
|
if (NULL != s && s->color == rbBlack) { |
||||
|
// this if statement is trivial, |
||||
|
// due to case 2 (even though case 2 changed the sibling to a |
||||
|
// sibling's child, |
||||
|
// the sibling's child can't be red, since no red parent can |
||||
|
// have a red child). |
||||
|
// |
||||
|
// the following statements just force the red to be on the |
||||
|
// left of the left of the parent, |
||||
|
// or right of the right, so case 6 will rotate correctly. |
||||
|
if ((node == node->parent->left) && |
||||
|
(NULL == s->right || s->right->color == rbBlack) && |
||||
|
(NULL != s->left && s->left->color == rbRed)) { |
||||
|
|
||||
|
// this last test is trivial too due to cases 2-4. |
||||
|
s->color = rbRed; |
||||
|
s->left->color = rbBlack; |
||||
|
|
||||
|
rotateRight(tree, s); |
||||
|
} else if ((node == node->parent->right) && |
||||
|
(NULL == s->left || s->left->color == rbBlack) && |
||||
|
(NULL != s->right && s->right->color == rbRed)) { |
||||
|
// this last test is trivial too due to cases 2-4. |
||||
|
s->color = rbRed; |
||||
|
s->right->color = rbBlack; |
||||
|
|
||||
|
rotateLeft(tree, s); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
s = sibling(node); |
||||
|
// case 6 |
||||
|
if (NULL != s) { |
||||
|
s->color = node->parent->color; |
||||
|
} |
||||
|
|
||||
|
if (NULL != node && NULL != node->parent) { |
||||
|
node->parent->color = rbBlack; |
||||
|
|
||||
|
/* |
||||
|
* detect which child we are...assumption |
||||
|
* if we are not parent->right and parent->right is not |
||||
|
* null we must be left, even if its set to NULL previously |
||||
|
*/ |
||||
|
if (NULL != node->parent->right && node != node->parent->right) { |
||||
|
if (NULL != s->right) { |
||||
|
s->right->color = rbBlack; |
||||
|
} |
||||
|
rotateLeft(tree, node->parent); |
||||
|
} else { |
||||
|
if (NULL != s->left) { |
||||
|
s->left->color = rbBlack; |
||||
|
} |
||||
|
rotateRight(tree, node->parent); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// done... |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
//deleteOneChild(tree, node); |
||||
|
|
||||
|
return del_node; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void |
||||
|
traverse(struct element * tree, void (*cb)(struct element *, int)) |
||||
|
{ |
||||
|
struct element * previous = tree; |
||||
|
struct element * node = tree; |
||||
|
int depth = 1; |
||||
|
|
||||
|
/* |
||||
|
* I think this has something like O(n+log(n)) on a ballanced |
||||
|
* tree because I have to traverse back the rightmost leaf to |
||||
|
* the root to get a break condition. |
||||
|
*/ |
||||
|
while (node) { |
||||
|
/* |
||||
|
* If we come from the right so nothing and go to our |
||||
|
* next parent. |
||||
|
*/ |
||||
|
if (previous == node->right) { |
||||
|
previous = node; |
||||
|
node = node->parent; |
||||
|
depth--; |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if ((NULL == node->left || previous == node->left)) { |
||||
|
/* |
||||
|
* If there are no more elements to the left or we |
||||
|
* came from the left, process data. |
||||
|
*/ |
||||
|
cb(node, depth); |
||||
|
previous = node; |
||||
|
|
||||
|
if (NULL != node->right) { |
||||
|
node = node->right; |
||||
|
depth++; |
||||
|
} else { |
||||
|
node = node->parent; |
||||
|
depth--; |
||||
|
} |
||||
|
} else { |
||||
|
/* |
||||
|
* if there are more elements to the left go there. |
||||
|
*/ |
||||
|
previous = node; |
||||
|
node = node->left; |
||||
|
depth++; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
post(struct element * tree, void (*cb)(struct element *, int)) |
||||
|
{ |
||||
|
struct element * previous = tree; |
||||
|
struct element * node = tree; |
||||
|
int depth = 1; |
||||
|
|
||||
|
/* |
||||
|
* I think this has something like O(n+log(n)) on a ballanced |
||||
|
* tree because I have to traverse back the rightmost leaf to |
||||
|
* the root to get a break condition. |
||||
|
*/ |
||||
|
while (node) { |
||||
|
/* |
||||
|
* If we come from the right so nothing and go to our |
||||
|
* next parent. |
||||
|
*/ |
||||
|
if ((NULL == node->left && NULL == node->right) |
||||
|
|| previous == node->right) { |
||||
|
|
||||
|
struct element * parent = node->parent; |
||||
|
|
||||
|
cb(node, depth); |
||||
|
|
||||
|
previous = node; |
||||
|
node = parent; |
||||
|
depth--; |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if ((NULL == node->left || previous == node->left)) { |
||||
|
/* |
||||
|
* If there are no more elements to the left or we |
||||
|
* came from the left, process data. |
||||
|
*/ |
||||
|
previous = node; |
||||
|
|
||||
|
if (NULL != node->right) { |
||||
|
node = node->right; |
||||
|
depth++; |
||||
|
} else { |
||||
|
node = node->parent; |
||||
|
depth--; |
||||
|
} |
||||
|
} else { |
||||
|
/* |
||||
|
* if there are more elements to the left go there. |
||||
|
*/ |
||||
|
previous = node; |
||||
|
node = node->left; |
||||
|
depth++; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void printElement(struct element * node, int depth) |
||||
|
{ |
||||
|
int i; |
||||
|
|
||||
|
printf("%s %010zu:%p(%02d)", |
||||
|
(node->color==rbRed)?"R":"B", |
||||
|
node->size, |
||||
|
node->ptr, |
||||
|
depth); |
||||
|
for (i=0; i<depth; i++) printf("-"); |
||||
|
puts(""); |
||||
|
|
||||
|
node = node->next; |
||||
|
while (NULL != node) { |
||||
|
printf(" %s %010zu:%p(%02d)", |
||||
|
(node->color==rbRed)?"R":"B", |
||||
|
node->size, |
||||
|
node->ptr, |
||||
|
depth); |
||||
|
for (i=0; i<depth; i++) printf("-"); |
||||
|
puts(""); |
||||
|
node = node->next; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void cleanup(struct element * node, int depth) |
||||
|
{ |
||||
|
while (NULL != node) { |
||||
|
printf("free node: "); |
||||
|
printElement(node, 0); |
||||
|
struct element * next = node->next; |
||||
|
free(node); |
||||
|
node = next; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* ======================================================================= |
||||
|
*/ |
||||
|
int |
||||
|
main(int argc, char * argv[]) |
||||
|
{ |
||||
|
struct element * root = NULL; |
||||
|
struct element * found = NULL; |
||||
|
|
||||
|
insertElement(&root, newElement(40)); |
||||
|
insertElement(&root, newElement(50)); |
||||
|
insertElement(&root, newElement(60)); |
||||
|
insertElement(&root, newElement(70)); |
||||
|
insertElement(&root, newElement(80)); |
||||
|
insertElement(&root, newElement(45)); |
||||
|
insertElement(&root, newElement(75)); |
||||
|
insertElement(&root, newElement(85)); |
||||
|
puts("traverse"); |
||||
|
traverse(root, printElement); |
||||
|
puts(""); |
||||
|
|
||||
|
insertElement(&root, newElement(70)); |
||||
|
puts("traverse"); |
||||
|
traverse(root, printElement); |
||||
|
puts(""); |
||||
|
|
||||
|
found = findElement(root, 10); |
||||
|
if (NULL == found) { |
||||
|
printf("can't find segmenet of minimum size: %d\n", 10); |
||||
|
} else { |
||||
|
printElement(found, 0); |
||||
|
} |
||||
|
puts(""); |
||||
|
|
||||
|
found = findElement(root, 64); |
||||
|
if (NULL == found) { |
||||
|
printf("can't find segmenet of minimum size: %d\n", 64); |
||||
|
} else { |
||||
|
printElement(found, 0); |
||||
|
} |
||||
|
puts(""); |
||||
|
|
||||
|
found = findElement(root, 90); |
||||
|
if (NULL == found) { |
||||
|
printf("can't find segmenet of minimum size: %d\n", 90); |
||||
|
} else { |
||||
|
printElement(found, 0); |
||||
|
} |
||||
|
puts(""); |
||||
|
|
||||
|
free(deleteElement(&root, findElement(root, 70))); |
||||
|
puts("traverse"); |
||||
|
traverse(root, printElement); |
||||
|
puts(""); |
||||
|
|
||||
|
insertElement(&root, newElement(80)); |
||||
|
insertElement(&root, newElement(50)); |
||||
|
insertElement(&root, newElement(80)); |
||||
|
|
||||
|
puts("traverse"); |
||||
|
traverse(root, printElement); |
||||
|
puts(""); |
||||
|
|
||||
|
found = deleteElement(&root, findElement(root, 80)); |
||||
|
printf("up to free: %p\n", found); |
||||
|
free(found); |
||||
|
puts("traverse"); |
||||
|
traverse(root, printElement); |
||||
|
puts(""); |
||||
|
|
||||
|
found = deleteElement(&root, findElement(root, 50)); |
||||
|
printf("up to free: %p\n", found); |
||||
|
free(found); |
||||
|
puts("traverse"); |
||||
|
traverse(root, printElement); |
||||
|
puts(""); |
||||
|
|
||||
|
found = deleteElement(&root, findElement(root, 70)); |
||||
|
printf("up to free: %p\n", found); |
||||
|
free(found); |
||||
|
puts("traverse"); |
||||
|
traverse(root, printElement); |
||||
|
puts(""); |
||||
|
|
||||
|
// post(root, cleanup); |
||||
|
// |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
// vim: set et ts=4 sw=4: |
||||
@ -0,0 +1,176 @@ |
|||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
|
||||
|
#include "class.h" |
||||
|
#include "commons.h" |
||||
|
#include "utils/memory.h" |
||||
|
|
||||
|
#include "tree.h" |
||||
|
#include "utils/memory.h" |
||||
|
|
||||
|
#define NVALUES 10 |
||||
|
|
||||
|
int |
||||
|
insertCompare(const void * tval, const void * search) |
||||
|
{ |
||||
|
return *(const int *)tval - *(const int *)search; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
freeNode(const void * data, const int depth) |
||||
|
{ |
||||
|
printf("now free %d at %p\n", *(int*)data, data); |
||||
|
MEM_FREE(data); |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
printNode(const void * _node, const int depth) |
||||
|
{ |
||||
|
Tree node = (Tree)_node; |
||||
|
int value = *(int *)node->data; |
||||
|
int i; |
||||
|
|
||||
|
for (i=1; i<7; i++) i<=depth?printf("-"):printf(" "); |
||||
|
printf("%p:%d p:%p l:%p r:%p\n", |
||||
|
node, value, node->parent, node->left, node->right); |
||||
|
|
||||
|
// printf("%s %010d(%02d)", |
||||
|
// (node->color==rbRed)?"R":"B", |
||||
|
// value, |
||||
|
// depth); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void * |
||||
|
newEle(int value) |
||||
|
{ |
||||
|
void * val = memMalloc(sizeof(int)); |
||||
|
|
||||
|
*(int*)val = value; |
||||
|
return val; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* ======================================================================= |
||||
|
*/ |
||||
|
int |
||||
|
main(int argc, char * argv[]) |
||||
|
{ |
||||
|
Tree root = NULL; |
||||
|
int * found = NULL; |
||||
|
int * element = NULL; |
||||
|
|
||||
|
int search10 = 10; |
||||
|
int search64 = 64; |
||||
|
int search70 = 70; |
||||
|
int search80 = 80; |
||||
|
int search50 = 50; |
||||
|
|
||||
|
treeInsert(&root, newEle(40), insertCompare); |
||||
|
treeInsert(&root, newEle(50), insertCompare); |
||||
|
treeInsert(&root, newEle(60), insertCompare); |
||||
|
treeInsert(&root, newEle(70), insertCompare); |
||||
|
treeInsert(&root, newEle(80), insertCompare); |
||||
|
treeInsert(&root, newEle(45), insertCompare); |
||||
|
treeInsert(&root, newEle(75), insertCompare); |
||||
|
treeInsert(&root, newEle(85), insertCompare); |
||||
|
puts("traverse"); |
||||
|
treeWalk(root, printNode); |
||||
|
puts(""); |
||||
|
|
||||
|
element = newEle(70); |
||||
|
found = treeInsert(&root, element, insertCompare); |
||||
|
printf("insert %p(%d) got %p(%d)\n", element, *element, found, *found); |
||||
|
if (found != element) { |
||||
|
printf("remove duplicate"); |
||||
|
MEM_FREE(element); |
||||
|
} |
||||
|
puts("traverse"); |
||||
|
treeWalk(root, printNode); |
||||
|
puts(""); |
||||
|
|
||||
|
found = treeFind(root, &search10, insertCompare); |
||||
|
if (NULL == found) { |
||||
|
printf("can't find segmenet of minimum size: %d\n", 10); |
||||
|
} else { |
||||
|
printf("found %d\n", *found); |
||||
|
} |
||||
|
puts(""); |
||||
|
|
||||
|
found = treeFind(root, &search64, insertCompare); |
||||
|
if (NULL == found) { |
||||
|
printf("can't find segmenet of minimum size: %d\n", 64); |
||||
|
} else { |
||||
|
printf("found %d\n", *found); |
||||
|
} |
||||
|
puts(""); |
||||
|
|
||||
|
found = treeFind(root, &search70, insertCompare); |
||||
|
if (NULL == found) { |
||||
|
printf("can't find segmenet of minimum size: %d\n", 70); |
||||
|
} else { |
||||
|
printf("found %d\n", *found); |
||||
|
} |
||||
|
puts(""); |
||||
|
|
||||
|
found = treeDelete(&root, (void *)&search70, insertCompare); |
||||
|
printf("delete %p(%d) got %p(%d)\n", &search70, search70, found, *found); |
||||
|
MEM_FREE(found); |
||||
|
puts("traverse"); |
||||
|
treeWalk(root, printNode); |
||||
|
puts(""); |
||||
|
|
||||
|
found = treeInsert(&root, (void *)&search80, insertCompare); |
||||
|
printf("insert %p(%d) got %p(%d)\n", &search80, search80, found, *found); |
||||
|
found = treeInsert(&root, (void *)&search50, insertCompare); |
||||
|
printf("insert %p(%d) got %p(%d)\n", &search50, search50, found, *found); |
||||
|
found = treeInsert(&root, (void *)&search80, insertCompare); |
||||
|
printf("insert %p(%d) got %p(%d)\n", &search80, search80, found, *found); |
||||
|
|
||||
|
puts("traverse"); |
||||
|
treeWalk(root, printNode); |
||||
|
puts(""); |
||||
|
|
||||
|
found = treeDelete(&root, (void *)&search80, insertCompare); |
||||
|
printf("delete %p(%d) got %p(%d)\n", &search80, search80, found, *found); |
||||
|
MEM_FREE(found); |
||||
|
puts("traverse"); |
||||
|
treeWalk(root, printNode); |
||||
|
puts(""); |
||||
|
|
||||
|
found = treeDelete(&root, (void *)&search50, insertCompare); |
||||
|
printf("delete %p(%d) got %p(%d)\n", &search50, search50, found, *found); |
||||
|
MEM_FREE(found); |
||||
|
puts("traverse"); |
||||
|
treeWalk(root, printNode); |
||||
|
puts(""); |
||||
|
|
||||
|
found = treeDelete(&root, (void *)&search70, insertCompare); |
||||
|
printf("delete %p(%d) got %p(%d)\n", &search70, search70, found, found?*found:-1); |
||||
|
MEM_FREE(found); |
||||
|
puts("traverse"); |
||||
|
treeWalk(root, printNode); |
||||
|
puts(""); |
||||
|
|
||||
|
element = newEle(60); |
||||
|
found = treeDelete(&root, element, insertCompare); |
||||
|
printf("delete %p(%d) got %p(%d)\n", |
||||
|
element, |
||||
|
*element, |
||||
|
found, |
||||
|
found?*found:-1); |
||||
|
if (found != element) { |
||||
|
MEM_FREE(element); |
||||
|
} |
||||
|
MEM_FREE(found); |
||||
|
puts("traverse"); |
||||
|
treeWalk(root, printNode); |
||||
|
puts(""); |
||||
|
|
||||
|
treeDestroy(&root, freeNode); |
||||
|
memCleanup(); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
// vim: set et ts=4 sw=4: |
||||
@ -0,0 +1,9 @@ |
|||||
|
ACLOCAL_AMFLAGS = -I m4 |
||||
|
|
||||
|
TREE = tree.c find.c insert.c inOrderSuccessor.c delete.c walk.c \
|
||||
|
rotateLeft.c rotateRight.c destroy.c |
||||
|
|
||||
|
noinst_LIBRARIES = libtree.a |
||||
|
|
||||
|
libtree_a_SOURCES = $(TREE) |
||||
|
libtree_a_CFLAGS = $(CFLAGS) -Wall -I ../../include/ |
||||
@ -0,0 +1,249 @@ |
|||||
|
/** |
||||
|
* \file |
||||
|
* |
||||
|
* \author Georg Hopp |
||||
|
* |
||||
|
* \copyright |
||||
|
* Copyright © 2012 Georg Hopp |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#include "tree.h" |
||||
|
|
||||
|
Tree inOrderSuccessor(Tree); |
||||
|
void treeRotateLeft(Tree *, Tree); |
||||
|
void treeRotateRight(Tree *, Tree); |
||||
|
|
||||
|
|
||||
|
void * |
||||
|
treeDelete(Tree * this, const void * search, TreeComp comp) |
||||
|
{ |
||||
|
Tree node = *this; |
||||
|
Tree del_node; |
||||
|
|
||||
|
void * data; |
||||
|
|
||||
|
/* |
||||
|
* first search for it and if its found return the data |
||||
|
* and we are done... |
||||
|
*/ |
||||
|
while (NULL != node) { |
||||
|
int comparison = comp(node->data, search); |
||||
|
|
||||
|
if (0 < comparison) { |
||||
|
node = TREE_LEFT(node); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if (0 > comparison) { |
||||
|
node = TREE_RIGHT(node); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if (0 == comparison) { |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* nothing was found...return NULL to indicate this. |
||||
|
*/ |
||||
|
if (NULL == node) { |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* we found an element, store its data pointer as we are |
||||
|
* up to delete it. |
||||
|
*/ |
||||
|
data = node->data; |
||||
|
|
||||
|
/* |
||||
|
* now remove the element. |
||||
|
*/ |
||||
|
|
||||
|
/* |
||||
|
* if we have two children replace data with the one from |
||||
|
* out inOrderSuccessor and remove the inOrderSuccessor. |
||||
|
*/ |
||||
|
if (NULL != TREE_LEFT(node) && NULL != TREE_RIGHT(node)) { |
||||
|
Tree successor = inOrderSuccessor(node); |
||||
|
|
||||
|
node->data = successor->data; |
||||
|
node = successor; |
||||
|
} |
||||
|
|
||||
|
{ |
||||
|
Tree child = TREE_CHILD(node); |
||||
|
|
||||
|
/* |
||||
|
* if we still have one child replace ourself with it. |
||||
|
*/ |
||||
|
TREE_REPLACE_NODE(this, node, child); |
||||
|
|
||||
|
/* |
||||
|
* and finally delete the node...and prepare ourselfs |
||||
|
* for rebalancing. |
||||
|
*/ |
||||
|
if (rbBlack == node->color) { |
||||
|
if (NULL != child && rbRed == child->color) { |
||||
|
child->color = rbBlack; |
||||
|
delete(node); |
||||
|
return data; |
||||
|
} else { |
||||
|
del_node = node; |
||||
|
if (NULL != child) { |
||||
|
node = child; |
||||
|
} else { |
||||
|
node->color = rbBlack; |
||||
|
node->left = NULL; |
||||
|
node->right = NULL; |
||||
|
} |
||||
|
} |
||||
|
} else { |
||||
|
delete(node); |
||||
|
return data; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* now comes rebalancing...note that if we came to this point |
||||
|
* the node is still not deleted. |
||||
|
* This is because I am not sure if it is needed during the |
||||
|
* rebalancing process...(this does not make much sense, but |
||||
|
* to be honest I don't know now.) |
||||
|
*/ |
||||
|
while(1) { |
||||
|
// case 1 |
||||
|
if (NULL == TREE_PARENT(node)) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
// case 2 |
||||
|
if (NULL != TREE_SIBLING(node) |
||||
|
&& rbRed == TREE_SIBLING(node)->color) { |
||||
|
|
||||
|
TREE_PARENT(node)->color = rbRed; |
||||
|
TREE_SIBLING(node)->color = rbBlack; |
||||
|
|
||||
|
if (NULL != TREE_PARENT(node)->right && |
||||
|
node != TREE_PARENT(node)->right) { |
||||
|
|
||||
|
//TREE_ROTATE_LEFT(this, TREE_PARENT(node)); |
||||
|
treeRotateLeft(this, TREE_PARENT(node)); |
||||
|
|
||||
|
} else { |
||||
|
|
||||
|
//TREE_ROTATE_RIGHT(this, TREE_PARENT(node)); |
||||
|
treeRotateRight(this, TREE_PARENT(node)); |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// case 3 / 4 |
||||
|
if (NULL == TREE_SIBLING(node) |
||||
|
|| (rbBlack == TREE_SIBLING(node)->color |
||||
|
&& (NULL == TREE_SIBLING(node)->left |
||||
|
|| rbBlack == TREE_SIBLING(node)->left->color) |
||||
|
&& (NULL == TREE_SIBLING(node)->right |
||||
|
|| rbBlack == TREE_SIBLING(node)->right->color))) { |
||||
|
|
||||
|
if (NULL != TREE_SIBLING(node)) { |
||||
|
TREE_SIBLING(node)->color = rbRed; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/* |
||||
|
* this is the point where during the balancing our tree |
||||
|
* node can be finally deleted. |
||||
|
*/ |
||||
|
if (rbBlack == TREE_PARENT(node)->color) { |
||||
|
// case 3 |
||||
|
Tree parent = node->parent; |
||||
|
node = parent; |
||||
|
continue; |
||||
|
} else { |
||||
|
// case 4 |
||||
|
TREE_PARENT(node)->color = rbBlack; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// case 5 |
||||
|
if (NULL != TREE_SIBLING(node) |
||||
|
&& rbBlack == TREE_SIBLING(node)->color) { |
||||
|
|
||||
|
if (node == TREE_PARENT(node)->left |
||||
|
&& (NULL == TREE_SIBLING(node)->right |
||||
|
|| rbBlack == TREE_SIBLING(node)->right->color) |
||||
|
&& (NULL != TREE_SIBLING(node)->left |
||||
|
&& rbRed == TREE_SIBLING(node)->left->color)) { |
||||
|
|
||||
|
TREE_SIBLING(node)->color = rbRed; |
||||
|
TREE_SIBLING(node)->left->color = rbBlack; |
||||
|
|
||||
|
//TREE_ROTATE_RIGHT(this, TREE_SIBLING(node)); |
||||
|
treeRotateRight(this, TREE_SIBLING(node)); |
||||
|
|
||||
|
} else if (node == TREE_PARENT(node)->right |
||||
|
&& (NULL == TREE_SIBLING(node)->left |
||||
|
|| rbBlack == TREE_SIBLING(node)->left->color) |
||||
|
&& (NULL != TREE_SIBLING(node)->right |
||||
|
&& rbRed == TREE_SIBLING(node)->right->color)) { |
||||
|
|
||||
|
TREE_SIBLING(node)->color = rbRed; |
||||
|
TREE_SIBLING(node)->right->color = rbBlack; |
||||
|
|
||||
|
//TREE_ROTATE_LEFT(this, TREE_SIBLING(node)); |
||||
|
treeRotateLeft(this, TREE_SIBLING(node)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// case 6 |
||||
|
if (NULL != TREE_SIBLING(node)) { |
||||
|
TREE_SIBLING(node)->color = TREE_PARENT(node)->color; |
||||
|
} |
||||
|
|
||||
|
if (NULL != node && NULL != TREE_PARENT(node)) { |
||||
|
TREE_PARENT(node)->color = rbBlack; |
||||
|
|
||||
|
if (NULL != TREE_PARENT(node)->right |
||||
|
&& node != TREE_PARENT(node)->right) { |
||||
|
|
||||
|
if (NULL != TREE_SIBLING(node)->right) { |
||||
|
TREE_SIBLING(node)->right->color = rbBlack; |
||||
|
} |
||||
|
//TREE_ROTATE_LEFT(this, TREE_PARENT(node)); |
||||
|
treeRotateLeft(this, TREE_PARENT(node)); |
||||
|
} else { |
||||
|
if (NULL != TREE_SIBLING(node)->left) { |
||||
|
TREE_SIBLING(node)->left->color = rbBlack; |
||||
|
} |
||||
|
//TREE_ROTATE_RIGHT(this, TREE_PARENT(node)); |
||||
|
treeRotateRight(this, TREE_PARENT(node)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
delete(del_node); |
||||
|
/* |
||||
|
* not sure if deleting here is correct. |
||||
|
*/ |
||||
|
return data; |
||||
|
} |
||||
|
|
||||
|
// vim: set ts=4 sw=4: |
||||
@ -0,0 +1,85 @@ |
|||||
|
/** |
||||
|
* \file |
||||
|
* |
||||
|
* \author Georg Hopp |
||||
|
* |
||||
|
* \copyright |
||||
|
* Copyright © 2012 Georg Hopp |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify |
||||
|
* it under the terms of the GNU General Public License as published by |
||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||
|
* (at your option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, |
||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
* GNU General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License |
||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#include "tree.h" |
||||
|
|
||||
|
void |
||||
|
treeDestroy(Tree * this, TreeAction action) |
||||
|
{ |
||||
|
Tree previous = * this; |
||||
|
Tree node = * this; |
||||
|
int depth = 1; |
||||
|
|
||||
|
/* |
||||
|
* I think this has something like O(n+log(n)) on a ballanced |
||||
|
* tree because I have to traverse back the rightmost leaf to |
||||
|
* the root to get a break condition. |
||||
|
*/ |
||||
|
while (NULL != node) { |
||||
|
/* |
||||
|
* If we come from the right so nothing and go to our |
||||
|
* next parent. |
||||
|
*/ |
||||
|
if (((NULL == TREE_LEFT(node) || previous == TREE_LEFT(node)) |
||||
|
&& NULL == TREE_RIGHT(node)) |
||||
|
|| previous == TREE_RIGHT(node)) { |
||||
|
|
||||
|
Tree parent = TREE_PARENT(node); |
||||
|
|
||||
|
action(node->data, depth); |
||||
|
|
||||
|
previous = node; |
||||
|
delete(node); |
||||
|
node = parent; |
||||
|
depth--; |
||||
|
|
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if ((NULL == TREE_LEFT(node) || previous == TREE_LEFT(node))) { |
||||
|
/* |
||||
|
* If there are no more elements to the left or we |
||||
|
* came from the left, process data. |
||||
|
*/ |
||||
|
previous = node; |
||||
|
|
||||
|
if (NULL != TREE_RIGHT(node)) { |
||||
|
node = TREE_RIGHT(node); |
||||
|
depth++; |
||||
|
} else { |
||||
|
node = TREE_PARENT(node); |
||||
|
depth--; |
||||
|
} |
||||
|
} else { |
||||
|
/* |
||||
|
* if there are more elements to the left go there. |
||||
|
*/ |
||||
|
previous = node; |
||||
|
node = TREE_LEFT(node); |
||||
|
depth++; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
*this = NULL; |
||||
|
} |
||||
|
|
||||
|
// vim: set ts=4 sw=4: |
||||
Some files were not shown because too many files changed in this diff
Write
Preview
Loading…
Cancel
Save
Reference in new issue