l4re-base-25.08.0

This commit is contained in:
2025-09-12 15:55:45 +02:00
commit d959eaab98
37938 changed files with 9382688 additions and 0 deletions

View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@@ -0,0 +1,469 @@
## This file states the license of this package and possibly its subpackages
## in machine and human readable format. The PackageName refers to the package
## whose license is defined by PackageLicenseConcluded.
## For more information about this file format visit the SPDX website at
## https://spdx.org
SPDXVersion: SPDX-2.3
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentNamespace: spdx:kernkonzept/l4re-core-115109da-9bd9-4dcc-ba3d-45e8f8332c47
DocumentName: l4re-core
Creator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
Created: 2018-05-17T00:00:00Z
## Package Information
PackageName: l4re-core
SPDXID: SPDXRef-l4re-core
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: GPL-2.0-only
PackageLicenseConcluded: GPL-2.0-only
PackageLicenseComments: <text>Packages contained in l4re-core may have individual licenses. See the respective package for details.</text>
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: crtn
SPDXID: SPDXRef-crtn
PackageFileName: ./crtn
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: LGPL-2.1-only
PackageLicenseConcluded: LGPL-2.1-only
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: cxx
SPDXID: SPDXRef-cxx
PackageFileName: ./cxx
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: GPL-2.0-only
PackageLicenseConcluded: GPL-2.0-only WITH GCC-exception-2.0
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: cxx_libc_io
SPDXID: SPDXRef-cxx-libc-io
PackageFileName: ./cxx_libc_io
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: GPL-2.0-only
PackageLicenseConcluded: GPL-2.0-only WITH GCC-exception-2.0
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: l4re
SPDXID: SPDXRef-l4re
PackageFileName: ./l4re
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: GPL-2.0-only
PackageLicenseConcluded: GPL-2.0-only WITH GCC-exception-2.0
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: l4re-util
SPDXID: SPDXRef-l4re-util
PackageFileName: ./l4re/util
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: GPL-2.0-only
PackageLicenseConcluded: GPL-2.0-only WITH GCC-exception-2.0
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
Relationship: SPDXRef-l4re CONTAINS SPDXRef-l4re-util
PackageName: l4re_c
SPDXID: SPDXRef-l4re-c
PackageFileName: ./l4re_c
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: GPL-2.0-only
PackageLicenseConcluded: GPL-2.0-only WITH GCC-exception-2.0
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: l4re_c-util
SPDXID: SPDXRef-l4re-c-util
PackageFileName: ./l4re_c/util
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: GPL-2.0-only
PackageLicenseConcluded: GPL-2.0-only WITH GCC-exception-2.0
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
Relationship: SPDXRef-l4re-c CONTAINS SPDXRef-l4re-c-util
PackageName: l4re_kernel
SPDXID: SPDXRef-l4re-kernel
PackageFileName: ./l4re_kernel
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: GPL-2.0-only
PackageLicenseConcluded: GPL-2.0-only
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: l4re_vfs
SPDXID: SPDXRef-l4re-vfs
PackageFileName: ./l4re_vfs
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: GPL-2.0-only
PackageLicenseConcluded: GPL-2.0-only WITH GCC-exception-2.0
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: l4sys
SPDXID: SPDXRef-l4sys
PackageFileName: ./l4sys
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: GPL-2.0-only
PackageLicenseConcluded: GPL-2.0-only WITH GCC-exception-2.0
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: l4util
SPDXID: SPDXRef-l4util
PackageFileName: ./l4util
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: LGPL-2.1-only
PackageLicenseConcluded: LGPL-2.1-only
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: true
FileName: ./l4util/include/ARCH-mips/thread.h
SPDXID: SPDXRef-l4util-mips-thread.h
LicenseConcluded: GPL-2.0-only
LicenseInfoInFile: NOASSERTION
FileCopyrightText: NOASSERTION
FileName: ./l4util/include/l4mod.h
SPDXID: SPDXRef-l4util-l4mod.h
LicenseConcluded: GPL-2.0-only
LicenseInfoInFile: NOASSERTION
FileCopyrightText: NOASSERTION
FileName: ./l4util/include/llulc.h
SPDXID: SPDXRef-l4util-llulc.h
LicenseConcluded: GPL-2.0-only
LicenseInfoInFile: NOASSERTION
FileCopyrightText: NOASSERTION
FileName: ./l4util/lib/src/base64.c
SPDXID: SPDXRef-l4util-base64.c
LicenseConcluded: MIT
LicenseInfoInFile: NOASSERTION
FileCopyrightText: NOASSERTION
FileName: ./l4util/lib/src/llulc.cc
SPDXID: SPDXRef-l4util-llulc.cc
LicenseConcluded: GPL-2.0-only
LicenseInfoInFile: NOASSERTION
FileCopyrightText: NOASSERTION
PackageName: ldscripts
SPDXID: SPDXRef-ldscripts
PackageFileName: ./ldscripts
PackageOriginator: Organization: Free Software Foundation, Inc
PackageLicenseDeclared: FSFAP
PackageLicenseConcluded: FSFAP
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: ldso
SPDXID: SPDXRef-ldso
PackageFileName: ./ldso
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: LGPL-2.1-only
PackageLicenseConcluded: LGPL-2.1-only
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: libc_backends
SPDXID: SPDXRef-libc-backends
PackageFileName: ./libc_backends
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: LGPL-2.1-only
PackageLicenseConcluded: LGPL-2.1-only
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: libgcc
SPDXID: SPDXRef-libgcc
PackageFileName: ./libgcc
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: GPL-3.0-only
PackageLicenseConcluded: (GPL-3.0-only WITH GCC-exception-3.1)
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: libgcc-pure
SPDXID: SPDXRef-libgcc-pure
PackageFileName: ./libgcc-pure
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: GPL-3.0-only
PackageLicenseConcluded: (GPL-3.0-only WITH GCC-exception-3.1)
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: libkproxy
SPDXID: SPDXRef-libkproxy
PackageFileName: ./libkproxy
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: GPL-2.0-only
PackageLicenseConcluded: GPL-2.0-only WITH GCC-exception-2.0
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: libloader
SPDXID: SPDXRef-libloader
PackageFileName: ./libloader
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: LGPL-2.1-only
PackageLicenseConcluded: LGPL-2.1-only
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: libsigma0
SPDXID: SPDXRef-libsigma0
PackageFileName: ./libsigma0
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: LGPL-2.1-only
PackageLicenseConcluded: LGPL-2.1-only
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: libstdc++-headers
SPDXID: SPDXRef-libstdc++-headers
PackageFileName: ./libstdc++-headers
PackageOriginator: Organization: Free Software Foundation, Inc
PackageLicenseDeclared: GPL-3.0-or-later
PackageLicenseConcluded: (GPL-3.0-or-later WITH GCC-exception-3.1)
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: libstdc++-v3
SPDXID: SPDXRef-libstdc++-v3
PackageFileName: ./libstdc++-v3
PackageOriginator: Organization: Free Software Foundation, Inc
PackageLicenseDeclared: GPL-3.0-or-later
PackageLicenseConcluded: ((GPL-3.0-or-later WITH GCC-exception-3.1) AND GFDL-1.3-or-later)
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: libstdc++-v3-minimal
SPDXID: SPDXRef-libstdc++-v3-minimal
PackageFileName: ./libstdc++-v3-minimal
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: GPL-3.0-only
PackageLicenseConcluded: ((GPL-3.0-or-later WITH GCC-exception-3.1) AND GFDL-1.3-or-later)
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: libsupc++
SPDXID: SPDXRef-libsupc++
PackageFileName: ./libsupc++
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: GPL-3.0-only
PackageLicenseConcluded: ((GPL-3.0-or-later WITH GCC-exception-3.1) AND GFDL-1.3-or-later)
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: libsupc++-minimal
SPDXID: SPDXRef-libsupc++-minimal
PackageFileName: ./libsupc++-minimal
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: GPL-3.0-only
PackageLicenseConcluded: ((GPL-3.0-or-later WITH GCC-exception-3.1) AND GFDL-1.3-or-later)
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: lua
SPDXID: SPDXRef-lua
PackageFileName: ./lua
PackageOriginator: Organization: Pontifical Catholic University of Rio de Janeiro
PackageLicenseDeclared: MIT
PackageLicenseConcluded: MIT
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: moe
SPDXID: SPDXRef-moe
PackageFileName: ./moe
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: GPL-2.0-only
PackageLicenseConcluded: GPL-2.0-only
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: ned
SPDXID: SPDXRef-ned
PackageFileName: ./ned
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: GPL-2.0-only
PackageLicenseConcluded: GPL-2.0-only
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: prj-config
SPDXID: SPDXRef-prj-config
PackageFileName: ./prj-config
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: GPL-2.0-only
PackageLicenseConcluded: GPL-2.0-only
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: sigma0
SPDXID: SPDXRef-sigma0
PackageFileName: ./sigma0
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: GPL-2.0-only
PackageLicenseConcluded: GPL-2.0-only
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: uclibc
SPDXID: SPDXRef-uclibc
PackageFileName: ./uclibc
PackageOriginator: NOASSERTION
PackageLicenseDeclared: LGPL-2.1-only
PackageLicenseConcluded: LGPL-2.1-only
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
PackageLicenseComments: <text>
This package contains header files that have been copied from the Linux
kernel. These headers are licensed under GPL-2.0 WITH
Linux-syscall-note.</text>
FilesAnalyzed: false
PackageName: uclibc-headers
SPDXID: SPDXRef-uclibc-headers
PackageFileName: ./uclibc-headers
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: GPL-2.0-only
PackageLicenseConcluded: GPL-2.0-only
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: uclibc-minimal
SPDXID: SPDXRef-uclibc-minimal
PackageFileName: ./uclibc-minimal
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: GPL-2.0-only
PackageLicenseConcluded: GPL-2.0-only
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: libclang_rt
SPDXID: SPDXRef-libclang-rt
PackageFileName: ./libclang_rt
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: Apache-2.0 WITH LLVM-exception
PackageLicenseConcluded: Apache-2.0 WITH LLVM-exception
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: libclang_rt-crt
SPDXID: SPDXRef-libclang-rt-crt
PackageFileName: ./libclang_rt-crt
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: Apache-2.0 WITH LLVM-exception
PackageLicenseConcluded: Apache-2.0 WITH LLVM-exception
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: libclang_rt-pure
SPDXID: SPDXRef-libclang-rt-pure
PackageFileName: ./libclang_rt-pure
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: Apache-2.0 WITH LLVM-exception
PackageLicenseConcluded: Apache-2.0 WITH LLVM-exception
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: libunwind_llvm
SPDXID: SPDXRef-libunwind-llvm
PackageFileName: ./libunwind_llvm
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: Apache-2.0 WITH LLVM-exception
PackageLicenseConcluded: Apache-2.0 WITH LLVM-exception
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageName: libunwind_llvm-pure
SPDXID: SPDXRef-libunwind-llvm-pure
PackageFileName: ./libunwind_llvm-pure
PackageOriginator: Organization: Kernkonzept GmbH (info@kernkonzept.com)
PackageLicenseDeclared: Apache-2.0 WITH LLVM-exception
PackageLicenseConcluded: Apache-2.0 WITH LLVM-exception
PackageCopyrightText: NOASSERTION
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
## Relationships
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-crtn
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-cxx
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-cxx-libc-io
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-l4re
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-l4re-c
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-l4re-kernel
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-l4re-vfs
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-l4sys
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-l4util
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-ldscripts
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-ldso
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-libc-backends
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-libgcc
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-libgcc-pure
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-libkproxy
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-libloader
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-libsigma0
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-libstdc++-headers
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-libstdc++-v3
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-libstdc++-v3-minimal
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-libsupc++
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-libsupc++-minimal
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-lua
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-moe
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-ned
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-prj-config
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-sigma0
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-uclibc
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-uclibc-headers
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-uclibc-minimal
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-libclang-rt
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-libclang-rt-pure
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-libunwind-llvm
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-libunwind-llvm-pure
Relationship: SPDXRef-l4re-core CONTAINS SPDXRef-libclang-rt-pure

View File

@@ -0,0 +1,3 @@
L4DIR ?= ../..
include $(L4DIR)/mk/project.mk

View File

@@ -0,0 +1,27 @@
# L4Re Core Components
This package contains the core components for the L4Re operating system.
It includes the following components:
* sigma0 - the initial memory manager
* moe - the root task
* ned - the default init process
* libc and libstdc++
* kernel bindings
* and more support libraries
# Documentation
This package is part of the L4Re operating system. For documentation and
build instructions see the
[L4Re wiki](https://kernkonzept.com/L4Re/guides/l4re).
# Contributions
We welcome contributions. Please see our contributors guide on
[how to contribute](https://kernkonzept.com/L4Re/contributing/l4re).
# License
Detailed licensing information can be found in the [LICENSE](LICENSE.spdx)
file.

View File

@@ -0,0 +1,29 @@
# Security Policy
This document outlines security procedures for the open-source projects of the
L4Re Operating System Framework as found on https://github.com/kernkonzept.
# Reporting a vulnerability
Security is very important to us and we take all security vulnerabilities
seriously. Thank you for improving the security of our open source software. If
you have discovered a security issue, we appreciate your efforts and your
responsible disclosure.
Please report a security vulnerability by sending an encrypted email to our
security team using our [public
key](https://www.kernkonzept.com/dl/security-at-kernkonzept.pub)
to **security@kernkonzept.com**. The fingerprint of our public key is
````
C4DC 2909 A22E D080 C012 5373 4055 CBA2 A4FD 855B
````
Please include the following in your report:
* A description of the vulnerability
* Steps to reproduce the vulnerability
A member of Kernkonzept's security team will confirm the vulnerability,
determine its impact, and develop a fix. The fix will be applied to the master
branch, tested, and released.

View File

@@ -0,0 +1,4 @@
provides: compiler-rt-crt
requires: libgcc-crt libclang_rt-crt
source-pkg: compiler-rt
maintainer: georg.kotheimer@kernkonzept.com

View File

@@ -0,0 +1,4 @@
PKGDIR = .
L4DIR ?= $(PKGDIR)/../../..
include $(L4DIR)/mk/subdir.mk

View File

@@ -0,0 +1,2 @@
Part of compiler-rt package, provides C runtime library object files
(`crt<...>.o`), used by ldscripts package.

View File

@@ -0,0 +1,6 @@
# Both libgcc-crt and libclang_rt-crt do not provide libraries to link against,
# therefore no pc file is generated for them. Consequently, they do not need to
# be considered as link dependencies, only the build order is important.
compiler-rt-crt-gcc := libgcc-crt[build-only]
compiler-rt-crt-clang := libclang_rt-crt[build-only]
compiler-rt-crt := compiler-rt-crt-gcc[config(CONFIG_COMPILER_RT_USE_LIBGCC)] compiler-rt-crt-clang[config(CONFIG_COMPILER_RT_USE_LIBCLANG_RT)]

View File

@@ -0,0 +1,5 @@
provides: compiler-rt-pure
requires: libgcc-pure libgcc_eh-pure
libclang_rt-builtins-pure libunwind_llvm-pure
source-pkg: compiler-rt
maintainer: georg.kotheimer@kernkonzept.com

View File

@@ -0,0 +1,4 @@
PKGDIR = .
L4DIR ?= $(PKGDIR)/../../..
include $(L4DIR)/mk/subdir.mk

View File

@@ -0,0 +1,2 @@
Part of compiler-rt package, provides variant of compiler-rt without L4 specific
functionality.

View File

@@ -0,0 +1,7 @@
# libgcc_eh must be before libgcc in link order as it might reference hidden
# symbols defined in libgcc (for example outline atomics). The order is
# important for shared objects, as these are linked without library grouping,
# i.e. libraries are searched only once in the order they are specified.
compiler-rt-pure-gcc := libgcc_eh-pure libgcc-pure
compiler-rt-pure-clang := libclang_rt-builtins-pure libunwind_llvm-pure
compiler-rt-pure := compiler-rt-pure-gcc[config(CONFIG_COMPILER_RT_USE_LIBGCC)] compiler-rt-pure-clang[config(CONFIG_COMPILER_RT_USE_LIBCLANG_RT)]

View File

@@ -0,0 +1,4 @@
provides: compiler-rt
requires: libgcc libgcc_eh libatomic[arch(riscv)]
libclang_rt-builtins libunwind_llvm
maintainer: georg.kotheimer@kernkonzept.com

View File

@@ -0,0 +1,53 @@
menu "Compiler runtime"
config COMPILER_RT_USE_LIBGCC
bool
# Clang is not able to compile libgcc.
select COMPILER_RT_USE_TOOLCHAIN_LIBGCC if $(BID_COMPILER_TYPE) = "clang"
# Sparc and PPC32 cannot be build from source.
select COMPILER_RT_USE_TOOLCHAIN_LIBGCC if BUILD_ARCH = "sparc" || BUILD_ARCH = "ppc32"
config COMPILER_RT_USE_LIBCLANG_RT
# libunwind requires unwind tables also for static binaries.
select BID_LD_EMIT_UNWIND
bool
choice
prompt "Runtime library"
default COMPILER_RT_CHOICE_AUTO
config COMPILER_RT_CHOICE_AUTO
bool "Determine automatically"
select COMPILER_RT_USE_LIBGCC if $(BID_COMPILER_TYPE) = "gcc"
select COMPILER_RT_USE_LIBCLANG_RT if $(BID_COMPILER_TYPE) = "clang"
help
Use libgcc if GCC is used as the compiler and use libclang_rt if Clang is
used as the compiler.
config COMPILER_RT_CHOICE_LIBGCC
bool "libgcc"
select COMPILER_RT_USE_LIBGCC
config COMPILER_RT_CHOICE_LIBCLANG_RT
bool "libclang_rt"
select COMPILER_RT_USE_LIBCLANG_RT
depends on $(BID_COMPILER_TYPE) = "clang"
endchoice
config COMPILER_RT_LIBGCC_SHARED
bool "Use shared libgcc"
depends on COMPILER_RT_USE_LIBGCC && !COMPILER_RT_USE_TOOLCHAIN_LIBGCC
help
Say Y if you want to use shared libgcc (libgcc_s.so).
# force to y if compiler clang, we cannot compile libgcc with clang!
config COMPILER_RT_USE_TOOLCHAIN_LIBGCC
bool "Use libgcc from toolchain"
depends on COMPILER_RT_USE_LIBGCC
default n
help
Say Y if you want to use the libgcc shipped with your toolchain instead of
the one built specifically for L4Re.
endmenu

View File

@@ -0,0 +1,4 @@
PKGDIR = .
L4DIR ?= $(PKGDIR)/../../..
include $(L4DIR)/mk/subdir.mk

View File

@@ -0,0 +1,6 @@
# Compiler runtime
This is a meta-package that provides configuration and selection of the compiler
runtime libraries for GCC and Clang.
See libgcc, libgcc_eh, libclang_rt and libunwind_llvm, and each of their pure
and crt variants.

View File

@@ -0,0 +1,19 @@
# RISC-V does not natively support subword atomics, such as __atomic_load_1 or
# __atomic_load_2. The RISC-V gcc developers have decided to emulate these via
# libatomic, which is suboptimal as it forces you to link against libatomic.
# However, there are plans to solve this properly in the future, without
# libatomic, analogous to how gcc does it on other architectures:
# https://github.com/riscv/riscv-gcc/issues/12#issuecomment-542735796
#
# Until then, we need an interim solution for L4Re, because the official
# workaround, which is that gcc on RISC-V just always automatically links
# against libatomic, does not work for L4Re because we call the linker directly,
# not through gcc.
# libgcc_eh must be before libgcc in link order as it might reference hidden
# symbols defined in libgcc (for example outline atomics). The order is
# important for shared objects, as these are linked without library grouping,
# i.e. libraries are searched only once in the order they are specified.
compiler-rt-gcc := libgcc_eh libgcc libatomic[arch(riscv)]
compiler-rt-clang := libclang_rt-builtins libunwind_llvm
compiler-rt := compiler-rt-gcc[config(CONFIG_COMPILER_RT_USE_LIBGCC)] compiler-rt-clang[config(CONFIG_COMPILER_RT_USE_LIBCLANG_RT)]

View File

@@ -0,0 +1,2 @@
provides: crtn
maintainer: warg@os.inf.tu-dresden.de

View File

@@ -0,0 +1,4 @@
PKGDIR = .
L4DIR ?= $(PKGDIR)/../../..
include $(L4DIR)/mk/subdir.mk

View File

@@ -0,0 +1,4 @@
PKGDIR = ..
L4DIR ?= $(PKGDIR)/../../..
include $(L4DIR)/mk/include.mk

View File

@@ -0,0 +1,20 @@
/**
* \file
* \brief List of all init priorities.
*/
/*
* (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#define INIT_PRIO_EARLY 101
#define INIT_PRIO_L4RE_UTIL_CAP_ALLOC 200
#define INIT_PRIO_VFS_INIT 400
#define INIT_PRIO_LIBIO_INIT 1100
#define INIT_PRIO_RTC_L4LIBC_INIT 1200
#define INIT_PRIO_TCPIP_INIT 1300
#define INIT_PRIO_LATE 5000

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2021, 2024 Kernkonzept GmbH.
* Author(s): Georg Kotheimer <georg.kotheimer@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
.section .text.init, "ax"
.type _start, @function
.globl _start
_start:
.option push
.option norelax
la gp, __global_pointer$
.option pop
lw a0, sp /* argc */
#if __riscv_xlen == 32
addi a1, sp, 4 /* argv */
#else
addi a1, sp, 8 /* argv */
#endif
call __main
1:
j 1b
.section ".data"
.global __dso_handle
__dso_handle:
.8byte 0

View File

@@ -0,0 +1,5 @@
requires: l4sys l4util
provides: cxx_atexit cxx_atexit_e cxx_base cxx_base_e cxx_io
cxx_io_e cxx_io_kdebug cxx_io_kdebug_e cxx_util
cxx_util_e
Maintainer: warg@os.inf.tu-dresden.de

View File

@@ -0,0 +1,8 @@
PKGDIR = .
L4DIR ?= $(PKGDIR)/../../..
TARGET = lib
include $(L4DIR)/mk/subdir.mk
include:
$(foreach DIR, $(SUBDIR), $(MAKE) -C $(DIR) include)

View File

@@ -0,0 +1,8 @@
/* vim:set ft=c: */
/**
* \defgroup cxx_api Small C++ Template Library
*/
/**
* Small Low-Level C++ Library
*/
namespace cxx {}

View File

@@ -0,0 +1,2 @@
INPUT += l4/cxx
INPUT += %PKGDIR%/doc/cxx.dox

View File

@@ -0,0 +1,12 @@
PKGDIR = ..
L4DIR ?= $(PKGDIR)/../../..
TARGET = io base be start util tl ipc
include $(L4DIR)/mk/subdir.mk
base: io
be: io
start: base util
util: io
ipc: base tl

View File

@@ -0,0 +1,32 @@
# vim:set ft=make:
TARGET_BASENAME := $(TARGET)
TARGET_A := $(TARGET_BASENAME).a
TARGET_E_A := $(TARGET_BASENAME)_e.a
PC_FILENAMES := $(PC_FILENAME) $(PC_FILENAME)_e
PC_LIBS_$(PC_FILENAME) := -l$(patsubst lib%,%,$(TARGET_BASENAME))
PC_LIBS_$(PC_FILENAME)_e := -l$(patsubst lib%,%,$(TARGET_BASENAME))_e
$(foreach src,$(SRC_CC),$(eval CXXFLAGS_$$(src) += -DL4_NO_RTTI -fno-exceptions -fno-rtti))
# Prevent the removal of the %.e.cc files. The build system shall not rebuild
# an unchanged source tree.
.SECONDARY: $(patsubst %.cc,%.e.cc,$(SRC_CC))
SRC_CC_$(TARGET_BASENAME).a := $(SRC_CC)
SRC_CC_$(TARGET_BASENAME).p.a := $(SRC_CC)
SRC_CC_$(TARGET_BASENAME)_e.a := $(patsubst %.cc,%.e.cc,$(SRC_CC))
SRC_CC_$(TARGET_BASENAME)_e.p.a := $(patsubst %.cc,%.e.cc,$(SRC_CC))
SRC_CC :=
PRIVATE_INCDIR += $(SRC_DIR)/
TARGET := $(TARGET_BASENAME).a $(TARGET_BASENAME).p.a \
$(TARGET_BASENAME)_e.a $(TARGET_BASENAME)_e.p.a
all::
%.e.cc: %.cc
$(VERBOSE)ln -s $< $@

View File

@@ -0,0 +1,5 @@
PKGDIR = ../..
L4DIR ?= $(PKGDIR)/../../..
TARGET := include src
include $(L4DIR)/mk/subdir.mk

View File

@@ -0,0 +1,5 @@
PKGDIR = ../../..
L4DIR ?= $(PKGDIR)/../../..
EXTRA_TARGET := exceptions string
include $(L4DIR)/mk/include.mk

View File

@@ -0,0 +1,312 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/**
* \file
* \brief Base exceptions
* \ingroup l4cxx_exceptions
*/
/*
* (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/cxx/l4types.h>
#include <l4/cxx/basic_ostream>
#include <l4/sys/err.h>
#include <l4/sys/capability>
/**
* \defgroup l4cxx_exceptions C++ Exceptions
* \ingroup api_l4re
*/
/**@{*/
#ifndef L4_CXX_NO_EXCEPTION_BACKTRACE
# define L4_CXX_EXCEPTION_BACKTRACE 20 ///< Number of instruction pointers in backtrace
#endif
#if defined(L4_CXX_EXCEPTION_BACKTRACE)
#include <l4/util/backtrace.h>
#endif
/**@}*/
namespace L4
{
/**
* \addtogroup l4cxx_exceptions
*/
/**@{*/
/**
* \brief Back-trace support for exceptions.
* \headerfile l4/cxx/exceptions
*
* This class holds an array of at most #L4_CXX_EXCEPTION_BACKTRACE
* instruction pointers containing the call trace at the instant when an
* exception was thrown.
*/
class Exception_tracer
{
#if defined(L4_CXX_EXCEPTION_BACKTRACE)
private:
void *_pc_array[L4_CXX_EXCEPTION_BACKTRACE];
int _frame_cnt;
protected:
/**
* \brief Create a back trace.
*/
#if defined(__PIC__)
Exception_tracer() noexcept : _frame_cnt(0) {}
#else
Exception_tracer() noexcept
: _frame_cnt(l4util_backtrace(_pc_array, L4_CXX_EXCEPTION_BACKTRACE)) {}
#endif
public:
/**
* \brief Get the array containing the call trace.
*/
void const *const *pc_array() const noexcept { return _pc_array; }
/**
* \brief Get the number of entries that are valid in the call trace.
*/
int frame_count() const noexcept { return _frame_cnt; }
#else
protected:
/**
* \brief Create a back trace.
*/
Exception_tracer() noexcept {}
public:
/**
* \brief Get the array containing the call trace.
*/
void const *const *pc_array() const noexcept { return 0; }
/**
* \brief Get the number of entries that are valid in the call trace.
*/
int frame_count() const noexcept { return 0; }
#endif
};
/**
* \brief Base class for all exceptions, thrown by the L4Re framework.
* \headerfile l4/cxx/exceptions
*
* This is the abstract base of all exceptions thrown within the
* L4Re framework. It is basically also a good idea to use it as base of
* all user defined exceptions.
*/
class Base_exception : public Exception_tracer
{
protected:
/// Create a base exception.
Base_exception() noexcept {}
public:
/**
* Return a human readable string for the exception.
*/
virtual char const *str() const noexcept = 0;
/// Destruction
virtual ~Base_exception() noexcept {}
};
/**
* \brief Exception for an abstract runtime error.
* \headerfile l4/cxx/exceptions
*
* This is the base class for a set of exceptions that cover all errors
* that have a C error value (see #l4_error_code_t).
*/
class Runtime_error : public Base_exception
{
private:
long _errno;
char _extra[80];
public:
/**
* Create a new Runtime_error.
*
* \param err_no Error value for this runtime error.
* \param extra Description of what happened when the error occurred.
*/
explicit Runtime_error(long err_no, char const *extra = 0) noexcept
: _errno(err_no)
{
if (!extra)
_extra[0] = 0;
else
{
unsigned i = 0;
for (; i < sizeof(_extra) && extra[i]; ++i)
_extra[i] = extra[i];
_extra[i < sizeof(_extra) ? i : sizeof(_extra) - 1] = 0;
}
}
char const *str() const noexcept override
{ return l4sys_errtostr(_errno); }
/**
* Get the description text for this runtime error.
*
* \return Pointer to the description string.
*/
char const *extra_str() const { return _extra; }
~Runtime_error() noexcept {}
/**
* Get the error value for this runtime error.
*
* \return Error value.
*/
long err_no() const noexcept { return _errno; }
};
/**
* \brief Exception signalling insufficient memory.
* \headerfile l4/cxx/exceptions
*/
class Out_of_memory : public Runtime_error
{
public:
/// Create an out-of-memory exception.
explicit Out_of_memory(char const *extra = "") noexcept
: Runtime_error(-L4_ENOMEM, extra) {}
/// Destruction
~Out_of_memory() noexcept {}
};
/**
* \brief Exception for duplicate element insertions.
* \headerfile l4/cxx/exceptions
*/
class Element_already_exists : public Runtime_error
{
public:
explicit Element_already_exists(char const *e = "") noexcept
: Runtime_error(-L4_EEXIST, e) {}
~Element_already_exists() noexcept {}
};
/**
* \brief Exception for an unknown condition.
* \headerfile l4/cxx/exceptions
*
* This error is usually used when a server returns an unknown return state
* to the client, this may indicate incompatible messages used by the client
* and the server.
*/
class Unknown_error : public Base_exception
{
public:
Unknown_error() noexcept {}
char const *str() const noexcept override { return "unknown error"; }
~Unknown_error() noexcept {}
};
/**
* \brief Exception for a failed lookup (element not found).
* \headerfile l4/cxx/exceptions
*/
class Element_not_found : public Runtime_error
{
public:
explicit Element_not_found(char const *e = "") noexcept
: Runtime_error(-L4_ENOENT, e) {}
};
/**
* \brief Indicates that an invalid object was invoked.
* \headerfile l4/cxx/exceptions
*
* An Object is invalid if it has L4_INVALID_ID as server L4 UID,
* or if the server does not know the object ID.
*/
class Invalid_capability : public Base_exception
{
private:
Cap<void> const _o;
public:
/**
* \brief Create an Invalid_object exception for the Object o.
* \param o The object that caused the server side error.
*/
explicit Invalid_capability(Cap<void> const &o) noexcept : _o(o) {}
template< typename T>
explicit Invalid_capability(Cap<T> const &o) noexcept : _o(o.cap()) {}
char const *str() const noexcept override { return "invalid object"; }
/**
* \brief Get the object that caused the error.
* \return The object that caused the error on invocation.
*/
Cap<void> const &cap() const noexcept { return _o; }
~Invalid_capability() noexcept {}
};
/**
* \brief Error conditions during IPC.
* \headerfile l4/cxx/exceptions
*
* This exception encapsulates all IPC error conditions of L4 IPC.
*/
class Com_error : public Runtime_error
{
public:
/**
* \brief Create a Com_error for the given L4 IPC error code.
* \param err The L4 IPC error code (l4_ipc... return value).
*/
explicit Com_error(long err) noexcept : Runtime_error(err) {}
~Com_error() noexcept {}
};
/**
* \brief Access out of bounds.
*/
class Bounds_error : public Runtime_error
{
public:
explicit Bounds_error(char const *e = "") noexcept
: Runtime_error(-L4_ERANGE, e) {}
~Bounds_error() noexcept {}
};
/**@}*/
};
inline
L4::BasicOStream &
operator << (L4::BasicOStream &o, L4::Base_exception const &e)
{
o << "Exception: " << e.str() << ".\n";
o << "Backtrace:\n";
for (int i = 0; i < e.frame_count(); ++i)
o << " " << L4::n_hex(l4_addr_t(e.pc_array()[i])) << '\n';
return o;
}
inline
L4::BasicOStream &
operator << (L4::BasicOStream &o, L4::Runtime_error const &e)
{
o << "Exception: " << e.str();
if (e.extra_str())
o << ": " << e.extra_str();
o << "\n" << "Backtrace:\n";
for (int i = 0; i < e.frame_count(); ++i)
o << " " << L4::n_hex(l4_addr_t(e.pc_array()[i])) << '\n';
return o;
}

View File

@@ -0,0 +1,313 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
/**
* Strings.
*/
#pragma once
#include <l4/cxx/minmax>
#include <l4/cxx/basic_ostream>
namespace cxx {
/**
* Allocation free string class with explicit length field.
*
* This class is used to group characters of a string which belong
* to one syntactical token types number, identifier, string,
* whitespace or another single character.
*
* Stings in this class can contain null bytes and may denote parts of
* other strings.
*/
class String
{
public:
/// Character index type.
typedef char const *Index;
/// Initialize from a zero-terminated string.
String(char const *s) noexcept : _start(s), _len(__builtin_strlen(s)) {}
/// Initialize from a pointer to first character and a length.
String(char const *s, unsigned long len) noexcept : _start(s), _len(len) {}
/**
* Initialize with start and end pointer.
*
* \param s first character of the string
* \param e pointer to first byte behind the string
*/
String(char const *s, char const *e) noexcept : _start(s), _len(e - s) {}
/// Zero-initialize. Create an invalid string.
String() : _start(0), _len(0) {}
/// Pointer to first character.
Index start() const { return _start; }
/// Pointer to first byte behind the string.
Index end() const { return _start + _len; }
/// Length.
int len() const { return _len; }
/// Set start.
void start(char const *s) { _start = s; }
/// Set length.
void len(unsigned long len) { _len = len; }
/// Check if the string has length zero.
bool empty() const { return !_len; }
/// Return prefix up to index.
String head(Index end) const
{
if (end < _start)
return String();
if (eof(end))
return *this;
return String(_start, end - _start);
}
/// Prefix of length `end`.
String head(unsigned long end) const
{ return head(start() + end); }
/// Substring of length `len` starting at `idx`.
String substr(unsigned long idx, unsigned long len = ~0UL) const
{
if (idx >= _len)
return String(end(), 0UL);
return String(_start + idx, cxx::min(len, _len - idx));
}
/// Substring of length `len` starting at `start`.
String substr(char const *start, unsigned long len = 0) const
{
if (start >= _start && !eof(start))
{
unsigned long nlen = _start + _len - start;
if (len != 0)
nlen = cxx::min(nlen, len);
return String(start, nlen);
}
return String(end(), 0UL);
}
/// Find matching character. `match` should be a function such as `isspace`.
template< typename F >
char const *find_match(F &&match) const
{
String::Index s = _start;
while (1)
{
if (eof(s))
return s;
if (match(*s))
return s;
++s;
}
}
/// Find character. Return end() if not found.
char const *find(char const *c) const
{ return find(c, start()); }
/// Find character. Return end() if not found.
char const *find(int c) const
{ return find(c, start()); }
/// Find right-most character. Return end() if not found.
char const *rfind(char const *c) const
{
if (!_len)
return end();
char const *p = end();
--p;
while (p >= _start)
{
if (*p == *c)
return p;
--p;
}
return end();
}
/**
* Check if `c` is a prefix of string.
*
* \return 0 if `c` is not a prefix, if it is a prefix, return
* first position not in `c` (which might be end()).
*/
Index starts_with(cxx::String const &c) const
{
unsigned long i;
for (i = 0; i < c._len && i < _len; ++i)
if (_start[i] != c[i])
return 0;
return i == c._len ? start() + i : 0;
}
/// Find character `c` starting at position `s`. Return end() if not found.
char const *find(int c, char const *s) const
{
if (s < _start)
return end();
while (1)
{
if (eof(s))
return s;
if (*s == c)
return s;
++s;
}
}
/**
* Find character set at position.
*
* \param c zero-terminated string of characters to search for
* \param s start position of search in string
*
* \retval end() if no char in `c` is contained in string at or behind `s`.
* \retval position in string of some character in `c`.
*/
char const *find(char const *c, char const *s) const
{
if (s < _start)
return end();
while (1)
{
if (eof(s))
return s;
for (char const *x = c; *x; ++x)
if (*s == *x)
return s;
++s;
}
}
/// Get character at `idx`.
char const &operator [] (unsigned long idx) const { return _start[idx]; }
/// Get character at `idx`.
char const &operator [] (int idx) const { return _start[idx]; }
/// Get character at `idx`.
char const &operator [] (Index idx) const { return *idx; }
/// Check if pointer `s` points behind string.
bool eof(char const *s) const { return s >= _start + _len || !*s; }
/**
* Convert decimal string to integer.
*
* \tparam INT result integer type
* \param[out] v conversion result
*
* \return position of first character not converted.
*/
template<typename INT>
int from_dec(INT *v) const
{
*v = 0;
Index c;
for (c = start(); !eof(c); ++c)
{
unsigned char n;
if (*c >= '0' && *c <= '9')
n = *c - '0';
else
return c - start();
*v *= 10;
*v += n;
}
return c - start();
}
/**
* Convert hex string to integer.
*
* \tparam INT result integer type
* \param[out] v conversion result
*
* \retval -1 if the maximal amount of digits fitting into `INT` have
* been read,
* \retval position of first character not converted otherwise.
*/
template<typename INT>
int from_hex(INT *v) const
{
*v = 0;
unsigned shift = 0;
Index c;
for (c = start(); !eof(c); ++c)
{
shift += 4;
if (shift > sizeof(INT) * 8)
return -1;
unsigned char n;
if (*c >= '0' && *c <= '9')
n = *c - '0';
else if (*c >= 'A' && *c <= 'F')
n = *c - 'A' + 10;
else if (*c >= 'a' && *c <= 'f')
n = *c - 'a' + 10;
else
return c - start();
*v <<= 4;
*v |= n;
}
return c - start();
}
/// Equality.
bool operator == (String const &o) const
{
if (len() != o.len())
return false;
for (unsigned long i = 0; i < _len; ++i)
if (_start[i] != o._start[i])
return false;
return true;
}
/// Inequality.
bool operator != (String const &o) const
{ return ! (operator == (o)); }
private:
char const *_start;
unsigned long _len;
};
}
/// Write `str` on `s`.
inline
L4::BasicOStream &operator << (L4::BasicOStream &s, cxx::String const &str)
{
s.write(str.start(), str.len());
return s;
}

View File

@@ -0,0 +1,15 @@
PKGDIR ?= ../../..
L4DIR ?= $(PKGDIR)/../../..
TARGET = libcxx_base
SYSTEMS = $(SYSTEMS_PLAIN)
PC_FILENAME = cxx_base
SRC_CC = cxa_pure_virtual.cc cxa_pure_delete.cc
SRC_CC_arm = dso_handle.cc
REQUIRES_LIBS := cxx_io
CXX_PKG_DIR=$(PKGDIR)
include $(PKGDIR)/lib/Makefile.inc
include $(L4DIR)/mk/lib.mk
$(GENERAL_D_LOC): $(CXX_PKG_DIR)/lib/Makefile.inc

View File

@@ -0,0 +1,25 @@
/*
* (c) 2004-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include <stddef.h>
#include <l4/cxx/iostream>
void operator delete (void *obj) noexcept
{
L4::cerr << "cxa pure delete operator called for object @"
<< L4::hex << obj << L4::dec << "\n";
}
#if __cplusplus >= 201400
void operator delete (void *obj, size_t size) noexcept;
void operator delete (void *obj, size_t size) noexcept
{
L4::cerr << "cxa pure delete operator called for object @"
<< L4::hex << obj << L4::dec
<< " size " << size << "\n";
}
#endif

View File

@@ -0,0 +1,23 @@
/*
* (c) 2004-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include <l4/cxx/iostream>
extern "C" void __cxa_pure_virtual(void);
void __cxa_pure_virtual()
{
L4::cerr << "cxa pure virtual function called\n";
}
extern "C" void __pure_virtual(void);
void __pure_virtual()
{
L4::cerr << "cxa pure virtual function called\n";
}

View File

@@ -0,0 +1,9 @@
/*
* (c) 2004-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
/* ARM C++ ABI requirement */
void *__dso_handle __attribute__ ((__visibility__ ("hidden"))) = &__dso_handle;

View File

@@ -0,0 +1,5 @@
PKGDIR = ../..
L4DIR ?= $(PKGDIR)/../../..
TARGET := kdebug
include $(L4DIR)/mk/subdir.mk

View File

@@ -0,0 +1,12 @@
PKGDIR ?= ../../..
L4DIR ?= $(PKGDIR)/../../..
TARGET = libcxx_io_kdebug
PC_FILENAME = cxx_io_kdebug
SRC_CC = iostream.cc
CXX_PKG_DIR=$(PKGDIR)
include $(PKGDIR)/lib/Makefile.inc
include $(L4DIR)/mk/lib.mk
$(GENERAL_D_LOC): $(CXX_PKG_DIR)/lib/Makefile.inc

View File

@@ -0,0 +1,52 @@
/*
* (c) 2004-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include <l4/cxx/basic_ostream>
#include <l4/sys/kdebug.h>
#include <l4/sys/l4int.h>
#include <l4/util/atomic.h>
#include <stddef.h>
inline void *operator new (size_t, void *p) { return p; }
namespace L4 {
class KdbgIOBackend : public IOBackend
{
protected:
void write(char const *str, unsigned len) override;
};
void KdbgIOBackend::write(char const *str, unsigned len)
{
outnstring(str,len);
}
typedef char Fake_iobackend[sizeof(KdbgIOBackend)]
__attribute__((aligned(__alignof__(KdbgIOBackend))));
typedef char Fake_ostream[sizeof(BasicOStream)]
__attribute__((aligned(__alignof__(BasicOStream))));
Fake_ostream cout;
Fake_ostream cerr;
static Fake_iobackend _iob;
void iostream_init();
void iostream_init()
{
static l4_umword_t _initialized;
if (l4util_xchg(&_initialized, 1) == 0)
{
KdbgIOBackend *iob = new (&_iob) KdbgIOBackend();
new (&cerr) BasicOStream(iob);
new (&cout) BasicOStream(iob);
}
}
};

View File

@@ -0,0 +1,8 @@
PKGDIR = ../..
L4DIR ?= $(PKGDIR)/../../..
TARGET := include src
include $(L4DIR)/mk/subdir.mk
src: include

View File

@@ -0,0 +1,6 @@
PKGDIR = ../../..
L4DIR ?= $(PKGDIR)/../../..
EXTRA_TARGET := basic_ostream iostream l4iostream
include $(L4DIR)/mk/include.mk

View File

@@ -0,0 +1,281 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/**
* \file
* \brief Basic IO stream
*/
/*
* (c) 2009 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
namespace L4 {
/**
* \brief Modifier class for the IO stream.
*
* An IO Modifier can be used to change properties of an IO stream
* for example the number format.
*/
class IOModifier
{
public:
IOModifier(int x) : mod(x) {}
bool operator == (IOModifier o) { return mod == o.mod; }
bool operator != (IOModifier o) { return mod != o.mod; }
int mod;
};
/**
* \internal
* \brief Backend to write or read stream data.
*/
class IOBackend
{
public:
typedef int Mode;
protected:
friend class BasicOStream;
IOBackend()
: int_mode(10)
{}
virtual ~IOBackend() {}
virtual void write(char const *str, unsigned len) = 0;
private:
void write(IOModifier m);
void write(long long int c, int len);
void write(long long unsigned c, int len);
void write(long long unsigned c, unsigned char base = 10,
unsigned char len = 0, char pad = ' ');
Mode mode() const
{ return int_mode; }
void mode(Mode m)
{ int_mode = m; }
int int_mode;
};
/**
* \internal
* \brief Write-only backend for stream data.
*/
class BasicOStream
{
public:
BasicOStream(IOBackend *b)
: iob(b)
{}
void write(char const *str, unsigned len)
{
if (iob)
iob->write(str, len);
}
void write(long long int c, int len)
{
if (iob)
iob->write(c, len);
}
void write(long long unsigned c, unsigned char base = 10,
unsigned char len = 0, char pad = ' ')
{
if (iob)
iob->write(c, base, len, pad);
}
void write(long long unsigned c, int len)
{
if (iob)
iob->write(c, len);
}
void write(IOModifier m)
{
if (iob)
iob->write(m);
}
IOBackend::Mode be_mode() const
{
if (iob)
return iob->mode();
return 0;
}
void be_mode(IOBackend::Mode m)
{
if (iob)
iob->mode(m);
}
private:
IOBackend *iob;
};
/**
* \internal
* \brief Container class describing a the number format.
*/
class IONumFmt
{
public:
IONumFmt(unsigned long long n, unsigned char base = 10,
unsigned char len = 0, char pad = ' ')
: n(n), base(base), len(len), pad(pad)
{}
BasicOStream &print(BasicOStream &o) const;
private:
unsigned long long n;
unsigned char base, len;
char pad;
};
inline IONumFmt n_hex(unsigned long long n) { return IONumFmt(n, 16); }
/**
* \brief Modifies the stream to print numbers as hexadecimal values.
*/
extern IOModifier const hex;
/**
* \brief Modifies the stream to print numbers as decimal values.
*/
extern IOModifier const dec;
inline
BasicOStream &IONumFmt::print(BasicOStream &o) const
{
o.write(n, base, len, pad);
return o;
}
}
// Implementation
inline
L4::BasicOStream &
operator << (L4::BasicOStream &s, char const * const str)
{
if (!str)
{
s.write("(NULL)", 6);
return s;
}
unsigned l = 0;
for (; str[l] != 0; l++)
;
s.write(str, l);
return s;
}
inline
L4::BasicOStream &
operator << (L4::BasicOStream &s, signed short u)
{
s.write(static_cast<long long signed>(u), -1);
return s;
}
inline
L4::BasicOStream &
operator << (L4::BasicOStream &s, signed u)
{
s.write(static_cast<long long signed>(u), -1);
return s;
}
inline
L4::BasicOStream &
operator << (L4::BasicOStream &s, signed long u)
{
s.write(static_cast<long long signed>(u), -1);
return s;
}
inline
L4::BasicOStream &
operator << (L4::BasicOStream &s, signed long long u)
{
s.write(u, -1);
return s;
}
inline
L4::BasicOStream &
operator << (L4::BasicOStream &s, unsigned short u)
{
s.write(static_cast<long long unsigned>(u), -1);
return s;
}
inline
L4::BasicOStream &
operator << (L4::BasicOStream &s, unsigned u)
{
s.write(static_cast<long long unsigned>(u), -1);
return s;
}
inline
L4::BasicOStream &
operator << (L4::BasicOStream &s, unsigned long u)
{
s.write(static_cast<long long unsigned>(u), -1);
return s;
}
inline
L4::BasicOStream &
operator << (L4::BasicOStream &s, unsigned long long u)
{
s.write(u, -1);
return s;
}
inline
L4::BasicOStream &
operator << (L4::BasicOStream &s, void const *u)
{
long unsigned x = reinterpret_cast<long unsigned>(u);
L4::IOBackend::Mode mode = s.be_mode();
s.write(L4::hex);
s.write(static_cast<long long unsigned>(x), -1);
s.be_mode(mode);
return s;
}
inline
L4::BasicOStream &
operator << (L4::BasicOStream &s, L4::IOModifier m)
{
s.write(m);
return s;
}
inline
L4::BasicOStream &
operator << (L4::BasicOStream &s, char c)
{
s.write(&c, 1);
return s;
}
inline
L4::BasicOStream &
operator << (L4::BasicOStream &o, L4::IONumFmt const &n)
{ return n.print(o); }

View File

@@ -0,0 +1,34 @@
// -*- Mode: C++ -*-
// vim:ft=cpp
/**
* \file
* \brief IO Stream
*/
/*
* (c) 2004-2009 Alexander Warg <warg@os.inf.tu-dresden.de>,
* Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/cxx/basic_ostream>
namespace L4 {
/**
* \brief Standard output stream.
*/
extern BasicOStream cout;
/**
* \brief Standard error stream.
*/
extern BasicOStream cerr;
extern void iostream_init();
static void __attribute__((used, constructor)) __iostream_init()
{ iostream_init(); }
};

View File

@@ -0,0 +1,35 @@
// -*- Mode: C++ -*-
// vim:ft=cpp
/**
* \file
* \brief L4 IO stream
*/
/*
* (c) 2004-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/cxx/basic_ostream>
#include <l4/sys/types.h>
#include <l4/sys/capability>
inline
L4::BasicOStream &operator << (L4::BasicOStream &o, l4_msgtag_t const &tag)
{
L4::IOBackend::Mode m = o.be_mode();
o << "[l=" << L4::dec << tag.label() << "; w=" << tag.words() << "; i="
<< tag.items() << "]";
o.be_mode(m);
return o;
}
template<typename T>
inline
L4::BasicOStream &operator << (L4::BasicOStream &o, L4::Cap<T> const &cap)
{
o << "[C:" << L4::n_hex(cap.cap()) << "]";
return o;
}

View File

@@ -0,0 +1,13 @@
PKGDIR ?= ../../..
L4DIR ?= $(PKGDIR)/../../..
TARGET = libcxx_io
SRC_CC = iob_write.cc
PC_FILENAME = cxx_io
SYSTEMS = $(SYSTEMS_PLAIN)
CXX_PKG_DIR=$(PKGDIR)
include $(PKGDIR)/lib/Makefile.inc
include $(L4DIR)/mk/lib.mk
$(GENERAL_D_LOC): $(CXX_PKG_DIR)/lib/Makefile.inc

View File

@@ -0,0 +1,87 @@
/*
* (c) 2004-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>,
* Frank Mehnert <fm3@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include <l4/cxx/basic_ostream>
namespace L4
{
IOModifier const hex(16);
IOModifier const dec(10);
static char const hex_chars[] = "0123456789abcdef";
void IOBackend::write(IOModifier m)
{
if (m == dec)
int_mode = 10;
else if (m == hex)
int_mode = 16;
}
void IOBackend::write(long long int u, int /*len*/)
{
char buffer[20];
int pos = 20;
bool sign = u < 0;
if (sign)
u = -u;
buffer[19] = '0';
while (u)
{
buffer[--pos] = hex_chars[u % int_mode];
u /= int_mode;
}
if (pos == 20)
pos = 19;
if (sign)
buffer[--pos] = '-';
write(buffer + pos, 20 - pos);
}
void IOBackend::write(long long unsigned u, int /*len*/)
{
char buffer[20];
int pos = 20;
buffer[19] = '0';
while (u)
{
buffer[--pos] = hex_chars[u % int_mode];
u /= int_mode;
}
if (pos == 20)
pos = 19;
write(buffer + pos, 20 - pos);
}
void IOBackend::write(long long unsigned u, unsigned char base,
unsigned char len, char pad)
{
char buffer[30];
unsigned pos = sizeof(buffer) - !u;
buffer[sizeof(buffer) - 1] = '0';
while (pos > 0 && u)
{
buffer[--pos] = hex_chars[u % base];
u /= base;
}
if (len > sizeof(buffer))
len = sizeof(buffer);
if (len && sizeof(buffer) - pos > len)
pos = sizeof(buffer) - len;
while (sizeof(buffer) - pos < len)
buffer[--pos] = pad;
write(buffer + pos, sizeof(buffer) - pos);
}
};

View File

@@ -0,0 +1,6 @@
PKGDIR = ../..
L4DIR ?= $(PKGDIR)/../../..
TARGET := include
include $(L4DIR)/mk/subdir.mk

View File

@@ -0,0 +1,5 @@
PKGDIR = ../../..
L4DIR ?= $(PKGDIR)/../../..
EXTRA_TARGET := ipc_helper ipc_stream ipc_server ipc_timeout_queue
include $(L4DIR)/mk/include.mk

View File

@@ -0,0 +1,55 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/**
* \file
* \brief IPC helper
*/
/*
* (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/cxx/exceptions>
#include <l4/sys/utcb.h>
/**
* \defgroup helper IPC Helpers
*/
namespace L4
{
#ifdef __EXCEPTIONS
/**
* \brief Throw an L4 IPC error as exception.
*
* \ingroup helper
* \param o The client side object, for which the IPC was invoked.
* \param err The IPC result code (error code).
* \utcb{utcb}
*/
inline void
throw_ipc_exception([[maybe_unused]] L4::Cap<void> const &o,
l4_msgtag_t const &err, l4_utcb_t *utcb)
{
if (err.has_error())
throw (L4::Com_error(l4_error_u(err, utcb)));
}
/**
* \brief Throw an L4 IPC error as exception.
*
* \ingroup helper
* \param o The client side object, for which the IPC was invoked.
* \param err The IPC result code (error code).
* \utcb{utcb}
*/
inline void
throw_ipc_exception(void const *o, l4_msgtag_t const &err,
l4_utcb_t *utcb)
{ throw_ipc_exception(L4::Cap<void>(o), err, utcb); }
#endif
}

View File

@@ -0,0 +1,163 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/**
* \file
* \brief IPC server loop
*/
/*
* (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>,
* Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/sys/capability>
#include <l4/sys/typeinfo_svr>
#include <l4/sys/err.h>
#include <l4/cxx/ipc_stream>
#include <l4/sys/cxx/ipc_epiface>
#include <l4/sys/cxx/ipc_server_loop>
#include <l4/cxx/type_traits>
#include <l4/cxx/exceptions>
namespace L4 {
/**
* \ingroup cxx_ipc_server
* \brief Abstract server object to be used with L4::Server and
* L4::Basic_registry.
* \note Usually L4::Server_object_t is used as a base class when writing
* server objects.
*
* This server object provides an abstract interface that is used by the
* L4::Registry_dispatcher model. You can derive subclasses from this
* interface and implement application specific server objects.
*/
class Server_object : public Epiface
{
public:
/**
* \brief The abstract handler for client requests to the object.
* \param rights The rights bits in the invoked capability.
* \param ios The Ipc::Iostream for reading the request and writing the reply.
* \retval -L4_ENOREPLY Instructs the server loop to not send a reply.
* \retval <0 Error, reply with error code.
* \retval >=0 Success, reply with return value.
*
* This function must be implemented by application specific server
* objects. The implementation must unmarshall data from the stream (`ios`)
* and create a reply by marshalling to the stream (`ios`). For details
* about the IPC stream see [IPC stream operators](\ref ipc_stream).
*
* \note You need to extract the complete message from the \a ios stream
* before inserting any reply data or before doing any function call
* that may use the UTCB. Otherwise, the incoming message may get lost.
*/
virtual int dispatch(unsigned long rights, Ipc::Iostream &ios) = 0;
l4_msgtag_t dispatch(l4_msgtag_t tag, unsigned rights, l4_utcb_t *utcb) override
{
L4::Ipc::Iostream ios(utcb);
ios.tag() = tag;
int r = dispatch(rights, ios);
return ios.prepare_ipc(r);
}
Cap<Kobject> obj_cap() const
{ return cap_cast<Kobject>(Epiface::obj_cap()); }
};
/**
* \ingroup cxx_ipc_server
* Base class (template) for server implementing server objects.
* \tparam IFACE The IPC interface class that defines the interface that shall
* be implemented.
* \tparam BASE The server object base class (usually L4::Server_object).
*/
template<typename IFACE, typename BASE = L4::Server_object>
struct Server_object_t : BASE
{
/// Data type of the IPC interface definition
typedef IFACE Interface;
/// \return the server-side buffer demand based in \a IFACE.
typename BASE::Demand get_buffer_demand() const override
{ return typename L4::Kobject_typeid<IFACE>::Demand(); }
/**
* Implementation of the meta protocol based on \a IFACE.
* \param ios The IO stream used for receiving the message.
*
* This function can be used to handle incoming #L4_PROTO_META protocol
* requests. The implementation uses the L4::Type_info of \a IFACE
* to handle the requests. Call this function in the implementation of
* Server_object::dispatch() when the received message tag has protocol
* #L4_PROTO_META (L4::Meta::Protocol).
*/
int dispatch_meta_request(L4::Ipc::Iostream &ios)
{ return L4::Util::handle_meta_request<IFACE>(ios); }
/**
* Implementation of protocol-based dispatch for this server object.
* \param self The this pointer for the object (inherits from
* Server_object_t).
* \param rights The rights from the received IPC (forwarded to p_dispatch()).
* \param ios The message stream for the incoming and the reply message.
*
* Server objects may call this function from their dispatch() function.
* This function reads the protocol ID from the message tag and uses the
* p_dispatch code to dispatch to overloaded p_dispatch functions of self.
*/
template<typename THIS>
static int proto_dispatch(THIS *self, l4_umword_t rights, L4::Ipc::Iostream &ios)
{
l4_msgtag_t t;
ios >> t;
return Kobject_typeid<IFACE>::proto_dispatch(self, t.label(), rights, ios);
}
};
/**
* \ingroup cxx_ipc_server
* Helper class to implement p_dispatch based server objects.
* \tparam Derived The data type of your server object class.
* \tparam IFACE The data type providing the interface definition
* for the object.
* \tparam BASE Optional data-type of the base server object (usually
* L4::Server_object)
* \implements L4::Server_object
*
* This class implements the standard dispatch() function of L4::Server_object
* and forwards incoming messages to a set of overloaded p_dispatch() functions.
* There must be a p_dispatch() function in Derived for each interface provided
* by IFACE with the signature
* \code int p_dispatch(Iface *, unsigned rights, L4::Ipc::Iostream &) \endcode
* that is called for messages with protocol == Iface::Protocol.
*
* Example signature for L4Re::Dataspace is:
* \code int p_dispatch(L4Re::Dataspace *, unsigned, L4::Ipc::Iostream &) \endcode
*/
template<typename Derived, typename IFACE, typename BASE = L4::Server_object>
struct Server_object_x : Server_object_t<IFACE, BASE>
{
/// Implementation forwarding to p_dispatch().
int dispatch(l4_umword_t r, L4::Ipc::Iostream &ios)
{
return Server_object_t<IFACE, BASE>::proto_dispatch(static_cast<Derived *>(this),
r, ios);
}
};
/**
* \ingroup cxx_ipc_server
* Server object base class for handling IRQ messages.
*
* This server object base class implements the empty interface
* (L4::Kobject). The implementation of Server_object::dispatch() must
* return -#L4_ENOREPLY, because IRQ messages do not handle replies.
*/
struct Irq_handler_object : Server_object_t<Kobject> {};
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,224 @@
// vim:set ft=cpp: -*- Mode: C++ -*-
/*
* (c) 2014 Steffen Liebergeld <steffen.liebergeld@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/cxx/hlist>
#include <l4/sys/cxx/ipc_server_loop>
namespace L4 { namespace Ipc_svr {
/**
* \brief Callback interface for Timeout_queue
* \ingroup cxx_ipc_server
*/
class Timeout : public cxx::H_list_item
{
friend class Timeout_queue;
public:
/// Make a timeout
Timeout() : _timeout(0) {}
/// Destroy a timeout
virtual ~Timeout() = 0;
/**
* \brief callback function to be called when timeout happened
* \note The timeout object is already dequeued when this function is called,
* this means the timeout may be safely queued again within the expired()
* function.
*/
virtual void expired() = 0;
/**
* \brief return absolute timeout of this callback.
* \return absolute timeout for this instance of the timeout.
* \pre The timeout object must have been in a queue before, otherwise the
* timeout is not set.
*/
l4_kernel_clock_t timeout() const
{ return _timeout; }
private:
l4_kernel_clock_t _timeout;
};
inline Timeout::~Timeout() {}
/**
* \brief Timeout queue to be used in l4re server loop
* \ingroup cxx_ipc_server
*/
class Timeout_queue
{
public:
/// Provide a local definition of Timeout for backward compatibility.
typedef L4::Ipc_svr::Timeout Timeout;
/**
* \brief Get the time for the next timeout.
* \return the time for the next timeout or 0 if there is none
*/
l4_kernel_clock_t next_timeout() const
{
if (auto e = _timeouts.front())
return e->timeout();
return 0;
}
/**
* \brief Determine if a timeout has happened.
*
* \param now The current time.
*
* \retval true There is at least one expired timeout in the queue.
* false No expired timeout in the queue.
*/
bool timeout_expired(l4_kernel_clock_t now) const
{
l4_kernel_clock_t next = next_timeout();
return (next != 0) && (next <= now);
}
/**
* \brief run the callbacks of expired timeouts
* \param now the current time.
*/
void handle_expired_timeouts(l4_kernel_clock_t now)
{
while (!_timeouts.empty())
{
Queue::Iterator top = _timeouts.begin();
if ((*top)->_timeout > now)
return;
Timeout *t = *top;
top = _timeouts.erase(top);
t->expired();
}
}
/**
* \brief Add a timeout to the queue
* \param timeout timeout object to add
* \param time the time when the timeout expires
* \pre \a timeout must not be in any queue already
*/
void add(Timeout *timeout, l4_kernel_clock_t time)
{
timeout->_timeout = time;
Queue::Iterator i = _timeouts.begin();
while (i != _timeouts.end() && (*i)->timeout() < time)
++i;
_timeouts.insert_before(timeout, i);
}
/**
* \brief Remove \a timeout from the queue.
* \param timeout timeout to remove from timeout queue
* \pre \a timeout must be in this queue
*/
void remove(Timeout *timeout)
{
_timeouts.remove(timeout);
}
private:
typedef cxx::H_list<Timeout> Queue;
Queue _timeouts;
};
/**
* \ingroup cxx_ipc_server
* \brief Loop hooks mixin for integrating a timeout queue into the server
* loop.
* \tparam HOOKS has to inherit from Timeout_queue_hooks<> and provide
* the functions now() that has to return the current time.
* \tparam BR_MAN This used as a base class for and provides the API for
* selecting the buffer register (BR) that is used to store the
* timeout value. This is usually L4Re::Util::Br_manager or
* L4::Ipc_svr::Br_manager_no_buffers.
*
* \implements L4::Ipc_svr::Server_iface
*/
template< typename HOOKS, typename BR_MAN = Br_manager_no_buffers >
class Timeout_queue_hooks : public BR_MAN
{
l4_kernel_clock_t _now()
{ return static_cast<HOOKS*>(this)->now(); }
unsigned _timeout_br()
{ return this->first_free_br(); }
public:
/// get the time for the next timeout
l4_timeout_t timeout()
{
l4_kernel_clock_t t = queue.next_timeout();
if (t)
return l4_timeout(L4_IPC_TIMEOUT_0, l4_timeout_abs(t, _timeout_br()));
return L4_IPC_SEND_TIMEOUT_0;
}
/// setup_wait() for the server loop
void setup_wait(l4_utcb_t *utcb, L4::Ipc_svr::Reply_mode mode)
{
// we must handle the timer only when called after a possible reply
// otherwise we probably destroy the reply message.
if (mode == L4::Ipc_svr::Reply_separate)
{
l4_kernel_clock_t now = _now();
if (queue.timeout_expired(now))
queue.handle_expired_timeouts(now);
}
BR_MAN::setup_wait(utcb, mode);
}
/// server loop hook
L4::Ipc_svr::Reply_mode before_reply(l4_msgtag_t, l4_utcb_t *)
{
// split up reply and wait when a timeout has expired
if (queue.timeout_expired(_now()))
return L4::Ipc_svr::Reply_separate;
return L4::Ipc_svr::Reply_compound;
}
/**
* Add a timeout to the queue for time \a time.
* \param timeout The timeout object to add into the queue (must not be in
* any queue currently).
* \param time The time when the timeout shall expire.
* \pre timeout must not be in any queue.
*
* \note The timeout is automatically dequeued before the Timeout::expired()
* function is called
*/
int add_timeout(Timeout *timeout, l4_kernel_clock_t time) override
{
queue.add(timeout, time);
return 0;
}
/**
* Remove timeout from the queue.
* \param timeout The timeout object to be removed from the queue.
* \note This function may be safely called even if the timeout is not
* currently enqueued.
* \note in Timeout::expired() the timeout is already dequeued!
*/
int remove_timeout(Timeout *timeout) override
{
queue.remove(timeout);
return 0;
}
Timeout_queue queue; ///< Use this timeout queue
};
}}

View File

@@ -0,0 +1,5 @@
PKGDIR = ../..
L4DIR ?= $(PKGDIR)/../../..
TARGET := include src
include $(L4DIR)/mk/subdir.mk

View File

@@ -0,0 +1,4 @@
PKGDIR = ../../..
L4DIR ?= $(PKGDIR)/../../..
include $(L4DIR)/mk/include.mk

View File

@@ -0,0 +1,13 @@
PKGDIR ?= ../../..
L4DIR ?= $(PKGDIR)/../../..
TARGET = libcxx_atexit
SYSTEMS = $(SYSTEMS_PLAIN)
SRC_CC = cxx_atexit.cc
PC_FILENAME = cxx_atexit
CXX_PKG_DIR=$(PKGDIR)
include $(PKGDIR)/lib/Makefile.inc
include $(L4DIR)/mk/lib.mk
$(GENERAL_D_LOC): $(CXX_PKG_DIR)/lib/Makefile.inc

View File

@@ -0,0 +1,57 @@
/*
* (c) 2004-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include "cxx_atexit.h"
#define NUM_ATEXIT 64
struct __exit_handler
{
void (*f)(void *);
void *arg;
void *dso_handle;
};
static __exit_handler __atexitlist[NUM_ATEXIT];
static volatile unsigned atexit_counter;
int __cxa_atexit(void (*f)(void*), void *arg, void *dso_handle)
{
unsigned c = atexit_counter++;
if (c >= NUM_ATEXIT)
return -1;
__atexitlist[c].f = f;
__atexitlist[c].arg = arg;
__atexitlist[c].dso_handle = dso_handle;
return 0;
}
extern void *__dso_handle __attribute__((weak));
int atexit(void (*f)(void))
{
void (*fct)(void *) = reinterpret_cast<void (*)(void*)>(f);
return __cxa_atexit(fct, 0, (!&__dso_handle) ? nullptr : __dso_handle);
}
void __cxa_finalize(void *dso_handle)
{
unsigned co = atexit_counter;
if (co > NUM_ATEXIT)
co = NUM_ATEXIT;
while(co)
{
__exit_handler *h = &__atexitlist[--co];
if (h->f && (dso_handle == 0 || h->dso_handle == dso_handle))
{
h->f(h->arg);
h->f = 0;
}
}
}

View File

@@ -0,0 +1,15 @@
/*
* (c) 2004-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#ifndef L4_CXX_ATEXIT_H__
#define L4_CXX_ATEXIT_H__
extern "C" void __cxa_finalize(void *dso_handle);
extern "C" int __cxa_atexit(void (*f)(void*), void *arg, void *dso_handle);
extern "C" int atexit(void (*f)(void));
#endif

View File

@@ -0,0 +1,5 @@
PKGDIR = ../..
L4DIR ?= $(PKGDIR)/../../..
TARGET := src
include $(L4DIR)/mk/subdir.mk

View File

@@ -0,0 +1,12 @@
PKGDIR ?= ../../..
L4DIR ?= $(PKGDIR)/../../..
TARGET = libsupc++-support
SRC_C = memset.c
SRC_CC = abort.cc
CXX_PKG_DIR=$(PKGDIR)
include $(PKGDIR)/lib/Makefile.inc
include $(L4DIR)/mk/lib.mk
$(GENERAL_D_LOC): $(CXX_PKG_DIR)/lib/Makefile.inc

View File

@@ -0,0 +1,20 @@
/*
* (c) 2004-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include <l4/sys/ipc.h>
#include <l4/cxx/iostream>
extern "C"
void abort(void) __attribute((noreturn));
void abort(void)
{
L4::cerr << "Aborted\n";
for (;;)
l4_ipc_sleep(L4_IPC_NEVER, l4sys_utcb());
}

View File

@@ -0,0 +1,20 @@
/*
* (c) 2004-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include <stddef.h>
void *memset(void *s, int c, size_t n);
void *memset(void *s, int c, size_t n)
{
size_t x;
char *p = s;
for (x=0; x<n; ++x)
*p++ = c;
return s;
}

View File

@@ -0,0 +1,5 @@
PKGDIR = ../..
L4DIR ?= $(PKGDIR)/../../..
TARGET := include
include $(L4DIR)/mk/subdir.mk

View File

@@ -0,0 +1,33 @@
PKGDIR = ../../..
L4DIR ?= $(PKGDIR)/../../..
EXTRA_TARGET := \
arith \
avl_tree \
avl_set \
avl_map \
bitmap \
dlist \
hlist \
slist \
list \
list_alloc \
minmax \
numeric \
observer \
pair \
ref_ptr \
slab_alloc \
static_container \
static_vector \
std_alloc \
std_ops \
type_traits \
type_list \
bitfield \
unique_ptr \
utils \
weak_ref \
unique_ptr_list \
ref_ptr_list
include $(L4DIR)/mk/include.mk

View File

@@ -0,0 +1,107 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
namespace cxx { namespace arith {
/**
* Divides two integers, and rounds the result to the next largest integer if
* the division yields a remainder.
*
* Examples:
* 6 / 3 = 2
* 7 / 3 = 3
* -7 / 3 = -2
*
* \param n Numerator
* \param d Denominator
*
* \return ceil(n / d)
*/
template<typename N, typename D>
constexpr N
div_ceil(N const &n, D const &d)
{
// Since C++11 the "quotient is truncated towards zero (fractional part is
// discarded)". Thus a negative quotient is already ceiled, whereas a
// positive quotient is floored. Furthermore, since C++11 the sign of the
// % operator is no longer implementation defined, thus we can use n % d to
// detect if the quotient is positive (n % d >= 0) and was truncated (n % d !=
// 0). In that case, we add one to round to the next largest integer.
return n / d + (n % d > 0);
}
/**
* Computes the binary logarithm of the given number at compile time.
*
* \param val Number whose logarithm to compute, must be greater than zero.
*
* \return The binary logarithm of `val`.
*/
template< unsigned long V >
struct Ld
{
enum { value = Ld<V / 2>::value + 1 };
};
template<>
struct Ld<0>
{
enum { value = ~0UL };
};
template<>
struct Ld<1>
{
enum { value = 0 };
};
/**
* Computes the binary logarithm of the given number.
*
* \param val Number whose logarithm to compute, must be greater than zero.
*
* \return The binary logarithm of `val`.
*/
constexpr unsigned
log2u(unsigned val)
{
return 8 * sizeof(val) - __builtin_clz(val) - 1;
}
/// \copydoc log2u(unsigned)
constexpr unsigned
log2u(unsigned long val)
{
return 8 * sizeof(val) - __builtin_clzl(val) - 1;
}
/// \copydoc log2u(unsigned)
constexpr unsigned
log2u(unsigned long long val)
{
return 8 * sizeof(val) - __builtin_clzll(val) - 1;
}
/**
* Computes the ceiling of the binary logarithm of the given number.
*
* \param val Number whose ceiling of the logarithm to compute, must be
* greater than zero.
*
* \return The ceiling of the binary logarithm of `val`.
*/
template<typename T>
constexpr unsigned
log2u_ceil(T val)
{
return val == 1 ? 0 : log2u(val - 1) + 1;
}
}}

View File

@@ -0,0 +1,134 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/**
* \file
* \brief AVL map
*/
/*
* (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/cxx/std_alloc>
#include <l4/cxx/std_ops>
#include <l4/cxx/pair>
#include <l4/cxx/avl_set>
namespace cxx {
namespace Bits {
/// Key-getter for Avl_map
template<typename KEY_TYPE>
struct Avl_map_get_key
{
typedef KEY_TYPE Key_type;
template<typename NODE>
static Key_type const &key_of(NODE const *n)
{ return n->item.first; }
};
}
/**
* AVL tree based associative container.
*
* \tparam KEY_TYPE Type of the key values.
* \tparam DATA_TYPE Type of the data values.
* \tparam COMPARE Type comparison functor for the key values.
* \tparam ALLOC Type of the allocator used for the nodes.
*/
template< typename KEY_TYPE, typename DATA_TYPE,
template<typename A> class COMPARE = Lt_functor,
template<typename B> class ALLOC = New_allocator >
class Avl_map :
public Bits::Base_avl_set<Pair<KEY_TYPE, DATA_TYPE>,
COMPARE<KEY_TYPE>, ALLOC,
Bits::Avl_map_get_key<KEY_TYPE> >
{
private:
typedef Pair<KEY_TYPE, DATA_TYPE> Local_item_type;
typedef Bits::Base_avl_set<Local_item_type, COMPARE<KEY_TYPE>, ALLOC,
Bits::Avl_map_get_key<KEY_TYPE> > Base_type;
public:
/// Type of the comparison functor.
typedef COMPARE<KEY_TYPE> Key_compare;
/// Type of the key values.
typedef KEY_TYPE Key_type;
/// Type of the data values.
typedef DATA_TYPE Data_type;
/// Return type for find.
typedef typename Base_type::Node Node;
/// Type of the allocator
typedef typename Base_type::Node_allocator Node_allocator;
typedef typename Base_type::Iterator Iterator;
typedef typename Base_type::Iterator iterator;
typedef typename Base_type::Const_iterator Const_iterator;
typedef typename Base_type::Const_iterator const_iterator;
typedef typename Base_type::Rev_iterator Rev_iterator;
typedef typename Base_type::Rev_iterator reverse_iterator;
typedef typename Base_type::Const_rev_iterator Const_rev_iterator;
typedef typename Base_type::Const_rev_iterator const_reverse_iterator;
/**
* \brief Create an empty AVL-tree based map.
* \param alloc The node allocator.
*/
Avl_map(Node_allocator const &alloc = Node_allocator())
: Base_type(alloc)
{}
/**
* Insert a <key, data> pair into the map.
*
* \param key The key value.
* \param data The data value to insert.
*
* \return A pair of iterator (`first`) and return value (`second`).
* `second` will be 0 if the element was inserted into the set
* and `-#E_exist` if the key was already in the set and the
* set was therefore not updated.
* In both cases, `first` contains an iterator that points to
* the element.
* `second` may also be `-#E_nomem` when memory for the new node
* could not be allocated. `first` is then invalid.
*/
cxx::Pair<Iterator, int> insert(Key_type const &key, Data_type const &data)
{ return Base_type::insert(Pair<Key_type, Data_type>(key, data)); }
template<typename... Args>
cxx::Pair<Iterator, int> emplace(Args &&...args)
{ return Base_type::emplace(cxx::forward<Args>(args)...); }
/**
* \brief Get the data for the given key.
* \param key The key value to use for lookup.
* \pre A <key, data> pair for the given key value must exist.
*/
Data_type const &operator [] (Key_type const &key) const
{ return this->find_node(key)->second; }
/**
* Get or insert data for the given key.
*
* \param key The key value to use for lookup.
*
* \return If the item already exists, a reference to the data item.
* Otherwise a new data item is default-constructed and inserted
* under the given key before a reference is returned.
*/
Data_type &operator [] (Key_type const &key)
{
Node n = this->find_node(key);
if (n)
return const_cast<Data_type&>(n->second);
else
return insert(key, Data_type()).first->second;
}
};
}

View File

@@ -0,0 +1,481 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/**
* \file
* \brief AVL set
*/
/*
* (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>,
* Carsten Weinhold <weinhold@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/cxx/std_alloc>
#include <l4/cxx/std_ops>
#include <l4/cxx/type_traits>
#include <l4/cxx/avl_tree>
struct Avl_set_tester;
namespace cxx {
namespace Bits {
/**
* \internal
* \brief Generic iterator for the AVL-tree based set.
* \param Cmp the type of the comparison functor.
* \param Node the type of a node.
* \param Key the type of the item stored in a node.
* \param Node_op the type used to determine the direction of the iterator.
*/
template< typename Node, typename Key, typename Node_op >
class Avl_set_iter : public __Bst_iter_b<Node, Node_op>
{
private:
/// Super-class type
typedef __Bst_iter_b<Node, Node_op> Base;
/// our non-const key type
typedef typename Type_traits<Key>::Non_const_type Non_const_key;
/// our non-const iterator type
typedef Avl_set_iter<Node, Non_const_key, Node_op> Non_const_iter;
using Base::_n;
using Base::_r;
using Base::inc;
public:
/// Create an invalid iterator (end marker)
Avl_set_iter() = default;
/**
* Create an iterator for the given tree.
* \param t the root node of the tree to iterate.
*/
Avl_set_iter(Node const *t) : Base(t) {}
/**
* Create an iterator from a BST iterator.
* \prarm o The BST iterator that shall be copied.
*/
Avl_set_iter(Base const &o) : Base(o) {}
/// Allow copy of non-const iterator to const iterator versions.
Avl_set_iter(Non_const_iter const &o)
: Base(o) {}
/// Allow assignment of non-const iterator to const iterator versions.
Avl_set_iter &operator = (Non_const_iter const &o)
{ Base::operator = (o); return *this; }
/**
* \brief Dereference the iterator and get the item out of the tree.
* \return A reference to the data stored in the AVL tree.
*/
Key &operator * () const { return const_cast<Node*>(_n)->item; }
/**
* \brief Member access to the item the iterator points to.
* \return A pointer to the item in the node.
*/
Key *operator -> () const { return &const_cast<Node*>(_n)->item; }
/**
* \brief Set the iterator to the next element (pre increment).
*/
Avl_set_iter &operator ++ () { inc(); return *this; }
/**
* \brief Set the iterator to the next element (post increment).
*/
Avl_set_iter operator ++ (int)
{ Avl_set_iter tmp = *this; inc(); return tmp; }
};
/// Internal, key-getter for Avl_set nodes.
template<typename KEY_TYPE>
struct Avl_set_get_key
{
typedef KEY_TYPE Key_type;
template<typename NODE>
static Key_type const &key_of(NODE const *n)
{ return n->item; }
};
/**
* Internal: AVL set with internally managed nodes.
*
* Use Avl_set, Avl_map, or Avl_tree in applications.
*
* \tparam ITEM_TYPE The type of the items to be stored in the set.
* \tparam COMPARE The relation to define the partial order, default is
* to use operator '<'.
* \tparam ALLOC The allocator to use for the nodes of the AVL set.
* \tparam GET_KEY Sort-key getter (must provide the `Key_type` and
* sort-key for an item (of `ITEM_TYPE`).
*/
template< typename ITEM_TYPE, class COMPARE,
template<typename A> class ALLOC,
typename GET_KEY>
class Base_avl_set
{
friend struct ::Avl_set_tester;
public:
/**
* Return status constants.
*
* These constants are compatible with the L4 error codes, see
* #l4_error_code_t.
*/
enum
{
E_noent = 2, ///< Item does not exist.
E_exist = 17, ///< Item exists already.
E_nomem = 12, ///< Memory allocation failed.
E_inval = 22 ///< Internal error.
};
/// Type for the items store in the set
typedef ITEM_TYPE Item_type;
/// Key-getter type to derive the sort key of an internal node.
typedef GET_KEY Get_key;
/// Type of the sort key used for the items
typedef typename GET_KEY::Key_type Key_type;
/// Type used for const items within the set
typedef typename Type_traits<Item_type>::Const_type Const_item_type;
/// Type for the comparison functor.
typedef COMPARE Item_compare;
private:
/// Internal representation of a tree node.
class _Node : public Avl_tree_node
{
public:
/// The actual item stored in the node.
Item_type item;
_Node() = default;
_Node(Item_type const &item) : Avl_tree_node(), item(item) {}
template<typename ...ARGS>
_Node(ARGS &&...args) : Avl_tree_node(), item(cxx::forward<ARGS>(args)...)
{}
};
public:
/**
* \brief A smart pointer to a tree item.
*/
class Node
{
private:
struct No_type;
friend class Base_avl_set<ITEM_TYPE, COMPARE, ALLOC, GET_KEY>;
_Node const *_n;
explicit Node(_Node const *n) : _n(n) {}
public:
/// Default construction for NIL pointer.
Node() : _n(0) {}
/**
* Dereference the pointer.
*
* \pre Node is valid.
*/
Item_type const &operator * () { return _n->item; }
/**
* Dereferenced member access.
*
* \pre Node is valid.
*/
Item_type const *operator -> () { return &_n->item; }
/**
* \brief Validity check.
* \return false if the pointer is NIL, true if valid.
*/
bool valid() const { return _n; }
/// Cast to a real item pointer.
operator Item_type const * () { return _n ? &_n->item : 0; }
};
/// Type for the node allocator.
typedef ALLOC<_Node> Node_allocator;
private:
typedef Avl_tree<_Node, GET_KEY, COMPARE> Tree;
Tree _tree;
/// The allocator for new nodes
Node_allocator _alloc;
Base_avl_set &operator = (Base_avl_set const &) = delete;
typedef typename Tree::Fwd_iter_ops Fwd;
typedef typename Tree::Rev_iter_ops Rev;
public:
typedef typename Type_traits<Item_type>::Param_type Item_param_type;
/// Forward iterator for the set.
typedef Avl_set_iter<_Node, Item_type, Fwd> Iterator;
typedef Iterator iterator;
/// Constant forward iterator for the set.
typedef Avl_set_iter<_Node, Const_item_type, Fwd> Const_iterator;
typedef Const_iterator const_iterator;
/// Backward iterator for the set.
typedef Avl_set_iter<_Node, Item_type, Rev> Rev_iterator;
typedef Rev_iterator reverse_iterator;
/// Constant backward iterator for the set.
typedef Avl_set_iter<_Node, Const_item_type, Rev> Const_rev_iterator;
typedef Const_rev_iterator const_reverse_iterator;
/**
* \brief Create a AVL-tree based set.
* \param alloc Node allocator.
*
* Create an empty set (AVL-tree based).
*/
explicit Base_avl_set(Node_allocator const &alloc = Node_allocator())
: _tree(), _alloc(alloc)
{}
~Base_avl_set()
{
_tree.remove_all([this](_Node *n)
{
n->~_Node();
_alloc.free(n);
});
}
/**
* Create a copy of an AVL-tree based set.
*
* \param o The set to copy.
*
* Creates a deep copy of the set with all its items.
*/
inline Base_avl_set(Base_avl_set const &o);
/**
* Insert an item into the set.
*
* \param item The item to insert.
*
* \return A pair of iterator (`first`) and return value (`second`).
* `second` will be 0 if the element was inserted into the set
* and `-#E_exist` if the element was already in the set and
* the set was therefore not updated.
* In both cases, `first` contains an iterator that points to
* the element.
* `second` may also be `-#E_nomem` when memory for the node
* could not be allocated. `first` is then invalid.
*
* Insert a new item into the set, each item can only be once in
* the set.
*/
cxx::Pair<Iterator, int> insert(Item_type const &item);
template<typename... Args>
cxx::Pair<Iterator, int> emplace(Args&&... args);
/**
* Remove an item from the set.
*
* \param item The item to remove.
*
* \retval 0 Success
* \retval -E_noent Item does not exist
*/
int remove(Key_type const &item)
{
_Node *n = _tree.remove(item);
if (n)
{
n->~_Node();
_alloc.free(n);
return 0;
}
return -E_noent;
}
/**
* Erase the item with the given key.
* \param item The key of the item to remove.
*/
int erase(Key_type const &item)
{ return remove(item); }
/**
* Lookup a node equal to `item`.
*
* \param item The value to search for.
*
* \return A smart pointer to the element found.
* If no element was found the smart pointer will be invalid.
*/
Node find_node(Key_type const &item) const
{ return Node(_tree.find_node(item)); }
/**
* Find the first node greater or equal to `key`.
*
* \param key Minimum key to look for.
*
* \return Smart pointer to the first node greater or equal to `key`.
* Will be invalid if no such element was found.
*/
Node lower_bound_node(Key_type const &key) const
{ return Node(_tree.lower_bound_node(key)); }
Node lower_bound_node(Key_type &&key) const
{ return Node(_tree.lower_bound_node(key)); }
/**
* \brief Get the constant forward iterator for the first element in the set.
* \return Constant forward iterator for the first element in the set.
*/
Const_iterator begin() const { return _tree.begin(); }
/**
* \brief Get the end marker for the constant forward iterator.
* \return The end marker for the constant forward iterator.
*/
Const_iterator end() const { return _tree.end(); }
/**
* \brief Get the mutable forward iterator for the first element of the set.
* \return The mutable forward iterator for the first element of the set.
*/
Iterator begin() { return _tree.begin(); }
/**
* \brief Get the end marker for the mutable forward iterator.
* \return The end marker for mutable forward iterator.
*/
Iterator end() { return _tree.end(); }
/**
* \brief Get the constant backward iterator for the last element in the set.
* \return The constant backward iterator for the last element in the set.
*/
Const_rev_iterator rbegin() const { return _tree.rbegin(); }
/**
* \brief Get the end marker for the constant backward iterator.
* \return The end marker for the constant backward iterator.
*/
Const_rev_iterator rend() const { return _tree.rend(); }
/**
* \brief Get the mutable backward iterator for the last element of the set.
* \return The mutable backward iterator for the last element of the set.
*/
Rev_iterator rbegin() { return _tree.rbegin(); }
/**
* \brief Get the end marker for the mutable backward iterator.
* \return The end marker for mutable backward iterator.
*/
Rev_iterator rend() { return _tree.rend(); }
Const_iterator find(Key_type const &item) const
{ return _tree.find(item); }
#ifdef __DEBUG_L4_AVL
bool rec_dump(bool print)
{
return _tree.rec_dump(print);
}
#endif
};
//----------------------------------------------------------------------------
/* Implementation of AVL Tree */
/* Create a copy */
template< typename Item, class Compare, template<typename A> class Alloc, typename KEY_TYPE>
Base_avl_set<Item,Compare,Alloc,KEY_TYPE>::Base_avl_set(Base_avl_set const &o)
: _tree(), _alloc(o._alloc)
{
for (Const_iterator i = o.begin(); i != o.end(); ++i)
insert(*i);
}
/* Insert new _Node. */
template< typename Item, class Compare, template< typename A > class Alloc, typename KEY_TYPE>
Pair<typename Base_avl_set<Item,Compare,Alloc,KEY_TYPE>::Iterator, int>
Base_avl_set<Item,Compare,Alloc,KEY_TYPE>::insert(Item const &item)
{
_Node *n = _alloc.alloc();
if (!n)
return cxx::pair(end(), -E_nomem);
new (n, Nothrow()) _Node(item);
Pair<_Node *, bool> err = _tree.insert(n);
if (!err.second)
{
n->~_Node();
_alloc.free(n);
}
return cxx::pair(Iterator(typename Tree::Iterator(err.first, err.first)), err.second ? 0 : -E_exist);
}
/* In-place insert new _Node. */
template< typename Item, class Compare, template< typename A > class Alloc, typename KEY_TYPE>
template<typename... Args>
Pair<typename Base_avl_set<Item,Compare,Alloc,KEY_TYPE>::Iterator, int>
Base_avl_set<Item,Compare,Alloc,KEY_TYPE>::emplace(Args&&... args)
{
_Node *n = _alloc.alloc();
if (!n)
return cxx::pair(end(), -E_nomem);
new (n, Nothrow()) _Node(cxx::forward<Args>(args)...);
Pair<_Node *, bool> err = _tree.insert(n);
if (!err.second)
{
n->~_Node();
_alloc.free(n);
}
return cxx::pair(Iterator(typename Tree::Iterator(err.first, err.first)), err.second ? 0 : -E_exist);
}
} // namespace Bits
/**
* \brief AVL set for simple comparable items.
*
* The AVL set can store any kind of items where a partial order is defined.
* The default relation is defined by the '<' operator.
*
* \tparam ITEM_TYPE The type of the items to be stored in the set.
* \tparam COMPARE The relation to define the partial order, default is
* to use operator '<'.
* \tparam ALLOC The allocator to use for the nodes of the AVL set.
*/
template< typename ITEM_TYPE, class COMPARE = Lt_functor<ITEM_TYPE>,
template<typename A> class ALLOC = New_allocator>
class Avl_set :
public Bits::Base_avl_set<ITEM_TYPE, COMPARE, ALLOC,
Bits::Avl_set_get_key<ITEM_TYPE> >
{
private:
typedef Bits::Base_avl_set<ITEM_TYPE, COMPARE, ALLOC,
Bits::Avl_set_get_key<ITEM_TYPE> > Base;
public:
typedef typename Base::Node_allocator Node_allocator;
Avl_set() = default;
Avl_set(Node_allocator const &alloc)
: Base(alloc)
{}
};
} // namespace cxx

View File

@@ -0,0 +1,409 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/**
* \file
* \brief AVL tree
*/
/*
* (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>,
* Carsten Weinhold <weinhold@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include "std_ops"
#include "pair"
#include "bits/bst.h"
#include "bits/bst_iter.h"
struct Avl_set_tester;
namespace cxx {
/**
* \brief Node of an AVL tree.
*/
class Avl_tree_node : public Bits::Bst_node
{
friend struct ::Avl_set_tester;
private:
template< typename Node, typename Get_key, typename Compare >
friend class Avl_tree;
/// Shortcut for Balance values (we use Direction for that).
typedef Bits::Direction Bal;
/// Alias for Direction.
typedef Bits::Direction Dir;
// We are a final BST node, hide interior.
/**@{*/
using Bits::Bst_node::next;
using Bits::Bst_node::next_p;
using Bits::Bst_node::rotate;
/**@}*/
/// The balance value (#Direction::N is balanced).
Bal _balance;
protected:
/// Create an uninitialized node, this is what you should do.
Avl_tree_node() = default;
private:
Avl_tree_node(Avl_tree_node const &o) = delete;
Avl_tree_node(Avl_tree_node &&o) = delete;
/// default copy for friend Avl_tree
Avl_tree_node &operator = (Avl_tree_node const &o) = default;
/// default move for friend Avl_tree
Avl_tree_node &operator = (Avl_tree_node &&o) = default;
/// Create an initialized node (for internal stuff).
explicit Avl_tree_node(bool) : Bits::Bst_node(true), _balance(Dir::N) {}
/// Double rotation of \a t.
static Bits::Bst_node *rotate2(Bst_node **t, Bal idir, Bal pre);
/// Is this subtree balanced?
bool balanced() const { return _balance == Bal::N; }
/// What is the balance of this subtree?
Bal balance() const { return _balance; }
/// Set the balance of this subtree to \a b.
void balance(Bal b) { _balance = b; }
};
/**
* \brief A generic AVL tree.
* \tparam Node The data type of the nodes (must inherit from Avl_tree_node).
* \tparam Get_key The meta function to get the key value from a node.
* The implementation uses `Get_key::key_of(ptr_to_node)`. The
* type of the key values must be defined in `Get_key::Key_type`.
* \tparam Compare Binary relation to establish a total order for the
* nodes of the tree. `Compare()(l, r)` must return true if
* the key \a l is smaller than the key \a r.
*
* This implementation does not provide any memory management. It is the
* responsibility of the caller to allocate nodes before inserting them and
* to free them when they are removed or when the tree is destroyed.
* Conversely, the caller must also ensure that nodes are removed
* from the tree before they are destroyed.
*/
template< typename Node, typename Get_key,
typename Compare = Lt_functor<typename Get_key::Key_type> >
class Avl_tree : public Bits::Bst<Node, Get_key, Compare>
{
private:
typedef Bits::Bst<Node, Get_key, Compare> Bst;
/// Hide this from possible descendants.
using Bst::_head;
/// Provide access to keys of nodes.
using Bst::k;
/// Alias type for balance values.
typedef typename Avl_tree_node::Bal Bal;
/// Alias type for Direction values.
typedef typename Avl_tree_node::Bal Dir;
Avl_tree(Avl_tree const &o) = delete;
Avl_tree &operator = (Avl_tree const &o) = delete;
Avl_tree(Avl_tree &&o) = delete;
Avl_tree &operator = (Avl_tree &&o) = delete;
public:
///@{
typedef typename Bst::Key_type Key_type;
typedef typename Bst::Key_param_type Key_param_type;
///@}
// Grab iterator types from Bst
///@{
/// Forward iterator for the tree.
typedef typename Bst::Iterator Iterator;
/// Constant forward iterator for the tree.
typedef typename Bst::Const_iterator Const_iterator;
/// Backward iterator for the tree.
typedef typename Bst::Rev_iterator Rev_iterator;
/// Constant backward iterator for the tree.
typedef typename Bst::Const_rev_iterator Const_rev_iterator;
///@}
/**
* \brief Insert a new node into this AVL tree.
* \param new_node A pointer to the new node.
* \return A pair, with \a second set to `true` and \a first pointing to
* \a new_node, on success. If there is already a node with the
* same key then \a first points to this node and \a second is 'false'.
*/
Pair<Node *, bool> insert(Node *new_node);
/**
* \brief Remove the node with \a key from the tree.
* \param key The key to the node to remove.
* \return The pointer to the removed node on success,
* or 0 if no node with the \a key exists.
*/
Node *remove(Key_param_type key);
/**
* \brief An alias for remove().
*/
Node *erase(Key_param_type key) { return remove(key); }
/// Create an empty AVL tree.
Avl_tree() = default;
/// Destroy the tree.
~Avl_tree() noexcept
{
this->remove_all([](Node *){});
}
#ifdef __DEBUG_L4_AVL
bool rec_dump(Avl_tree_node *n, int depth, int *dp, bool print, char pfx);
bool rec_dump(bool print)
{
int dp=0;
return rec_dump(static_cast<Avl_tree_node *>(_head), 0, &dp, print, '+');
}
#endif
};
//----------------------------------------------------------------------------
/* IMPLEMENTATION: Bits::__Bst_iter_b */
inline
Bits::Bst_node *
Avl_tree_node::rotate2(Bst_node **t, Bal idir, Bal pre)
{
typedef Bits::Bst_node N;
typedef Avl_tree_node A;
N *tmp[2] = { *t, N::next(*t, idir) };
*t = N::next(tmp[1], !idir);
A *n = static_cast<A*>(*t);
N::next(tmp[0], idir, N::next(n, !idir));
N::next(tmp[1], !idir, N::next(n, idir));
N::next(n, !idir, tmp[0]);
N::next(n, idir, tmp[1]);
n->balance(Bal::N);
if (pre == Bal::N)
{
static_cast<A*>(tmp[0])->balance(Bal::N);
static_cast<A*>(tmp[1])->balance(Bal::N);
return 0;
}
static_cast<A*>(tmp[pre != idir])->balance(!pre);
static_cast<A*>(tmp[pre == idir])->balance(Bal::N);
return N::next(tmp[pre == idir], !pre);
}
//----------------------------------------------------------------------------
/* Implementation of AVL Tree */
/* Insert new _Node. */
template< typename Node, typename Get_key, class Compare>
Pair<Node *, bool>
Avl_tree<Node, Get_key, Compare>::insert(Node *new_node)
{
typedef Avl_tree_node A;
typedef Bits::Bst_node N;
N **t = &_head; /* search variable */
N **s = &_head; /* node where rebalancing may occur */
Key_param_type new_key = Get_key::key_of(new_node);
// search insertion point
for (N *p; (p = *t);)
{
Dir b = this->dir(new_key, p);
if (b == Dir::N)
return pair(static_cast<Node*>(p), false);
if (!static_cast<A const *>(p)->balanced())
s = t;
t = A::next_p(p, b);
}
*static_cast<A*>(new_node) = A(true);
*t = new_node;
N *n = *s;
A *a = static_cast<A*>(n);
if (!a->balanced())
{
A::Bal b(this->greater(new_key, n));
if (a->balance() != b)
{
// ok we got in balance the shorter subtree go higher
a->balance(Bal::N);
// propagate the new balance down to the new node
n = A::next(n, b);
}
else if (b == Bal(this->greater(new_key, A::next(n, b))))
{
// left-left or right-right case -> single rotation
A::rotate(s, b);
a->balance(Bal::N);
static_cast<A*>(*s)->balance(Bal::N);
n = A::next(*s, b);
}
else
{
// need a double rotation
n = A::next(A::next(n, b), !b);
n = A::rotate2(s, b, n == new_node ? Bal::N : Bal(this->greater(new_key, n)));
}
}
for (A::Bal b; n && n != new_node; static_cast<A*>(n)->balance(b), n = A::next(n, b))
b = Bal(this->greater(new_key, n));
return pair(new_node, true);
}
/* remove an element */
template< typename Node, typename Get_key, class Compare>
inline
Node *Avl_tree<Node, Get_key, Compare>::remove(Key_param_type key)
{
typedef Avl_tree_node A;
typedef Bits::Bst_node N;
N **q = &_head; /* search variable */
N **s = &_head; /* last ('deepest') node on the search path to q
* with balance 0, at this place the rebalancing
* stops in any case */
N **t = 0;
Dir dir;
// find target node and rebalancing entry
for (N *n; (n = *q); q = A::next_p(n, dir))
{
dir = Dir(this->greater(key, n));
if (dir == Dir::L && !this->greater(k(n), key))
/* found node */
t = q;
if (!A::next(n, dir))
break;
A const *a = static_cast<A const *>(n);
if (a->balanced() || (a->balance() == !dir && A::next<A>(n, !dir)->balanced()))
s = q;
}
// nothing found
if (!t)
return 0;
A *i = static_cast<A*>(*t);
for (N *n; (n = *s); s = A::next_p(n, dir))
{
dir = Dir(this->greater(key, n));
if (!A::next(n, dir))
break;
A *a = static_cast<A*>(n);
// got one out of balance
if (a->balanced())
a->balance(!dir);
else if (a->balance() == dir)
a->balance(Bal::N);
else
{
// we need rotations to get in balance
Bal b = A::next<A>(n, !dir)->balance();
if (b == dir)
A::rotate2(s, !dir, A::next<A>(A::next(n, !dir), dir)->balance());
else
{
A::rotate(s, !dir);
if (b != Bal::N)
{
a->balance(Bal::N);
static_cast<A*>(*s)->balance(Bal::N);
}
else
{
a->balance(!dir);
static_cast<A*>(*s)->balance(dir);
}
}
if (n == i)
t = A::next_p(*s, dir);
}
}
A *n = static_cast<A*>(*q);
*t = n;
*q = A::next(n, !dir);
*n = *i;
return static_cast<Node*>(i);
}
#ifdef __DEBUG_L4_AVL
template< typename Node, typename Get_key, class Compare>
bool Avl_tree<Node, Get_key, Compare>::rec_dump(Avl_tree_node *n, int depth, int *dp, bool print, char pfx)
{
typedef Avl_tree_node A;
if (!n)
return true;
int dpx[2] = {depth,depth};
bool res = true;
res = rec_dump(A::next<A>(n, Dir::R), depth + 1, dpx + 1, print, '/');
if (print)
{
fprintf(stderr, "%2d: [%8p] b=%1d: ", depth, n, (int)n->balance().d);
for (int i = 0; i < depth; ++i)
std::cerr << " ";
std::cerr << pfx << (static_cast<Node*>(n)->item) << std::endl;
}
res = res & rec_dump(A::next<A>(n, Dir::L), depth + 1, dpx, print, '\\');
int b = dpx[1] - dpx[0];
if (b < 0)
*dp = dpx[0];
else
*dp = dpx[1];
Bal x = n->balance();
if ((b < -1 || b > 1) ||
(b == 0 && x != Bal::N) ||
(b == -1 && x != Bal::L) ||
(b == 1 && x != Bal::R))
{
if (print)
fprintf(stderr, "%2d: [%8p] b=%1d: balance error %d\n", depth, n, (int)n->balance().d, b);
return false;
}
return res;
}
#endif
}

View File

@@ -0,0 +1,33 @@
/**
* \file
* \brief Basic vector
*/
/*
* (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/cxx/std_alloc>
namespace cxx {
template< typename T >
class Basic_vector
{
public:
Basic_vector(T *array, unsigned long capacity)
: _array(array), _capacity(capacity)
{
for (unsigned long i = 0; i < capacity; ++i)
new (&_array[i]) T();
}
private:
T *_array;
unsigned long _capacity;
};
};

View File

@@ -0,0 +1,308 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* (c) 2012 Alexander Warg <warg@os.inf.tu-dresden.de>,
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include "type_list"
/** Our C++ library. */
namespace cxx {
/**
* Definition for a member (part) of a bit field.
*
* \param T The underlying type of the bit field.
* \param LSB The least significant bit of our bits.
* \param MSB The most significant bit of our bits.
*/
template<typename T, unsigned LSB, unsigned MSB>
class Bitfield
{
private:
typedef remove_reference_t<T> Base_type;
static_assert(MSB >= LSB, "boundary mismatch in bit-field definition");
static_assert(MSB < sizeof(Base_type) * 8, "MSB outside of bit-field type");
static_assert(LSB < sizeof(Base_type) * 8, "LSB outside of bit-field type");
/**
* Get the best unsigned type for `bits`.
*
* \param BITS Number of bits to cover.
*/
template<unsigned BITS> struct Best_type
{
template< typename TY > struct Cmp { enum { value = (BITS <= sizeof(TY)*8) }; };
typedef cxx::type_list<
unsigned char,
unsigned short,
unsigned int,
unsigned long,
unsigned long long
> Unsigned_types;
typedef cxx::find_type_t<Unsigned_types, Cmp> Type;
};
public:
enum
{
Bits = MSB + 1 - LSB, ///< Number of bits
Lsb = LSB, ///< index of the LSB
Msb = MSB, ///< index of the MSB
};
/// Masks for bitswise operation on internal parts of a bitfield
enum Masks : Base_type
{
/** Mask value to get #Bits bits. */
Low_mask = static_cast<Base_type>(~0ULL) >> (sizeof(Base_type)*8 - Bits),
/** Mask value to the bits out of a `T`. */
Mask = Low_mask << Lsb,
};
/**
* Type to hold at least #Bits bits.
*
* This type can handle all values that can be stored in this part of the bit
* field.
*/
typedef typename Best_type<Bits>::Type Bits_type;
/**
* Type to hold at least #Bits + #Lsb bits.
*
* This type can handle all values that can be stored in this part of the bit
* field when they are at the target location (#Lsb bits shifted to the left).
*/
typedef typename Best_type<Bits + Lsb>::Type Shift_type;
private:
static_assert(sizeof(Bits_type)*8 >= Bits, "error finding the type to store the bits");
static_assert(sizeof(Shift_type)*8 >= Bits + Lsb, "error finding the type to keep the shifted bits");
static_assert(sizeof(Bits_type) <= sizeof(Base_type), "size mismatch for Bits_type");
static_assert(sizeof(Shift_type) <= sizeof(Base_type), "size mismatch for Shift_type");
static_assert(sizeof(Bits_type) <= sizeof(Shift_type), "size mismatch for Shift_type and Bits_type");
public:
/**
* Get the bits out of `val`.
*
* \param val The raw value of the whole bit field.
*
* \return The bits form #Lsb to #Msb shifted to the right.
*/
static constexpr Bits_type get(Shift_type val)
{ return (val >> Lsb) & Low_mask; }
/**
* Get the bits in place out of `val`.
*
* \param val The raw value of the whole bit field.
*
* \return The bits from #Lsb to #Msb (unshifted).
*
* This means other bits are masked out, however the result is not shifted to
* the right.
*/
static constexpr Base_type get_unshifted(Shift_type val)
{ return val & Mask; }
/**
* Set the bits corresponding to `val`.
*
* \param dest The current value of the whole bit field.
* \param val The value to set into the bits.
*
* \return The new value of the whole bit field.
*
* \pre `val` must not contain more than #Bits bits.
*
* \note This function does not mask `val` to the right number of bits.
*/
static constexpr Base_type set_dirty(Base_type dest, Shift_type val)
{
//assert (!(val & ~Low_mask));
return (dest & ~Mask) | (val << Lsb);
}
/**
* Set the bits corresponding to `val`.
*
* \param dest The current value of the whole bit field.
* \param val The value shifted #Lsb bits to the left that shall be set into
* the bits.
*
* \return The new value of the whole bit field.
*
* \pre `val` must not contain more than #Bits bits shifted #Lsb bits to the
* left.
*
* \note This function does not mask `val` to the right number of bits.
*/
static constexpr Base_type set_unshifted_dirty(Base_type dest, Shift_type val)
{
//assert (!(val & ~Mask));
return (dest & ~Mask) | val;
}
/**
* Set the bits corresponding to `val`.
*
* \param dest The current value of the whole bit field.
* \param val The value to set into the bits.
*
* \return The new value of the whole bit field.
*/
static Base_type set(Base_type dest, Bits_type val)
{ return set_dirty(dest, val & Low_mask); }
/**
* Set the bits corresponding to `val`.
*
* \param dest The current value of the whole bit field.
* \param val The value shifted #Lsb bits to the left that shall be set into
* the bit field.
*
* \return the new value of the whole bit field.
*/
static Base_type set_unshifted(Base_type dest, Shift_type val)
{ return set_unshifted_dirty(dest, val & Mask); }
/**
* Get the shifted bits for `val`.
*
* \param val The value to set into the bits.
*
* \return The raw bit field value.
*
* \pre `val` must not contain more than #Bits bits.
*
* \note This function does not mask `val` to the right number of bits.
*/
static constexpr Base_type val_dirty(Shift_type val) { return val << Lsb; }
/**
* Get the shifted bits for `val`.
*
* \param val The value to set into the bits.
*
* \return The raw bit field value.
*/
static constexpr Base_type val(Bits_type val) { return val_dirty(val & Low_mask); }
/**
* Get the shifted bits for `val`.
*
* \param val The value shifted #Lsb bits to the left that shall be set into
* the bits.
*
* \return The raw bit field value.
*/
static constexpr Base_type val_unshifted(Shift_type val) { return val & Mask; }
/** Internal helper type */
template< typename TT >
class Value_base
{
private:
TT v;
public:
constexpr Value_base(TT t) : v(t) {}
constexpr Bits_type get() const { return Bitfield::get(v); }
constexpr Base_type get_unshifted() const { return Bitfield::get_unshifted(v); }
void set(Bits_type val) { v = Bitfield::set(v, val); }
void set_dirty(Bits_type val) { v = Bitfield::set_dirty(v, val); }
void set_unshifted(Shift_type val) { v = Bitfield::set_unshifted(v, val); }
void set_unshifted_dirty(Shift_type val) { v = Bitfield::set_unshifted_dirty(v, val); }
};
/** Internal helper type */
template< typename TT >
class Value : public Value_base<TT>
{
public:
constexpr Value(TT t) : Value_base<TT>(t) {}
constexpr operator Bits_type () const { return this->get(); }
constexpr Value &operator = (Bits_type val) { this->set(val); return *this; }
constexpr Value &operator = (Value const &val)
{ this->set(val.get()); return *this; }
Value(Value const &) = default;
};
/** Internal helper type */
template< typename TT >
class Value_unshifted : public Value_base<TT>
{
public:
constexpr Value_unshifted(TT t) : Value_base<TT>(t) {}
constexpr operator Shift_type () const { return this->get_unshifted(); }
constexpr Value_unshifted &operator = (Shift_type val) { this->set_unshifted(val); return *this; }
constexpr Value_unshifted &operator = (Value_unshifted const &val)
{ this->set_unshifted(val.get_unshifted()); return *this; }
Value_unshifted(Value_unshifted const &) = default;
};
/** Reference type to access the bits inside a raw bit field. */
typedef Value<Base_type &> Ref;
/** Volatile reference type to access the bits inside a raw bit field. */
typedef Value<Base_type volatile &> Ref_volatile;
/** Value type to access the bits inside a raw bit field. */
typedef Value<Base_type const> Val;
/** Reference type to access the bits inside a raw bit field (in place). */
typedef Value_unshifted<Base_type &> Ref_unshifted;
/** Volatile reference type to access the bits inside a raw bit field (in place). */
typedef Value_unshifted<Base_type volatile &> Ref_unshifted_volatile;
/** Value type to access the bits inside a raw bit field (in place). */
typedef Value_unshifted<Base_type const> Val_unshifted;
};
#define CXX_BITFIELD_MEMBER(LSB, MSB, name, data_member) \
/** @{ */ \
/** Type to access the `name` bits (LSB to MSB) of `data_member`. */ \
typedef cxx::Bitfield<decltype(data_member), LSB, MSB> name ## _bfm_t; \
/** Get the `name` bits (LSB to MSB) of `data_member`. */ \
constexpr typename name ## _bfm_t::Val name() const { return data_member; } \
typename name ## _bfm_t::Val name() const volatile { return data_member; } \
/** Get a reference to the `name` bits (LSB to MSB) of `data_member`. */ \
constexpr typename name ## _bfm_t::Ref name() { return data_member; } \
typename name ## _bfm_t::Ref_volatile name() volatile { return data_member; } \
/** @} */
#define CXX_BITFIELD_MEMBER_RO(LSB, MSB, name, data_member) \
/** @{ */ \
/** Type to access the `name` bits (LSB to MSB) of `data_member`. */ \
typedef cxx::Bitfield<decltype(data_member), LSB, MSB> name ## _bfm_t; \
/** Get the `name` bits (LSB to MSB) of `data_member`. */ \
constexpr typename name ## _bfm_t::Val name() const { return data_member; } \
typename name ## _bfm_t::Val name() const volatile { return data_member; } \
/** @} */
#define CXX_BITFIELD_MEMBER_UNSHIFTED(LSB, MSB, name, data_member) \
/** @{ */ \
/** Type to access the `name` bits (LSB to MSB) of `data_member`. */ \
typedef cxx::Bitfield<decltype(data_member), LSB, MSB> name ## _bfm_t; \
/** Get the `name` bits (LSB to MSB) of `data_member`. */ \
constexpr typename name ## _bfm_t::Val_unshifted name() const { return data_member; } \
typename name ## _bfm_t::Val_unshifted name() const volatile { return data_member; } \
/** Get a reference to the `name` bits (LSB to MSB) of `data_member`. */ \
constexpr typename name ## _bfm_t::Ref_unshifted name() { return data_member; } \
typename name ## _bfm_t::Ref_unshifted_volatile name() volatile { return data_member; } \
/** @} */
#define CXX_BITFIELD_MEMBER_UNSHIFTED_RO(LSB, MSB, name, data_member) \
/** @{ */ \
/** Type to access the `name` bits (LSB to MSB) of `data_member`. */ \
typedef cxx::Bitfield<decltype(data_member), LSB, MSB> name ## _bfm_t; \
/** Get the `name` bits (LSB to MSB) of `data_member`. */ \
constexpr typename name ## _bfm_t::Val_unshifted name() const { return data_member; } \
typename name ## _bfm_t::Val_unshifted name() const volatile { return data_member; } \
/** @} */
}

View File

@@ -0,0 +1,370 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* (c) 2008-2014 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
namespace cxx {
/**
* Basic bitmap abstraction.
*
* This abstraction keeps a pointer to a memory area that is used as bitmap.
*/
class Bitmap_base
{
protected:
/**
* Data type for each element of the bit buffer.
*/
typedef unsigned long word_type;
enum
{
W_bits = sizeof(word_type) * 8, ///< number of bits in word_type
C_bits = 8, ///< number of bits in char
};
/**
* Pointer to the buffer storing the bits.
*/
word_type *_bits;
/**
* Get the word index for the given bit.
*
* \param bit The index of the bit in question.
*
* \return the index in Bitmap_base::_bits for the given bit (bit / W_bits).
*/
static unsigned word_index(unsigned bit) { return bit / W_bits; }
/**
* Get the bit index within word_type for the given bit.
*
* \param bit The bit index in the bitmap.
*
* \return the bit index within word_type (bit % W_bits).
*/
static unsigned bit_index(unsigned bit) { return bit % W_bits; }
/**
* A writable bit in a bitmap.
*/
class Bit
{
Bitmap_base *_bm;
long _bit;
public:
Bit(Bitmap_base *bm, long bit) : _bm(bm), _bit(bit) {}
Bit &operator = (bool val) { _bm->bit(_bit, val); return *this; }
operator bool () const { return _bm->bit(_bit); }
};
public:
explicit Bitmap_base(void *bits) noexcept : _bits(reinterpret_cast<word_type *>(bits)) {}
/** Get the number of `Words` that are used for the bitmap. */
static long words(long bits) noexcept { return (bits + W_bits -1) / W_bits; }
static long bit_buffer_bytes(long bits) noexcept
{ return words(bits) * W_bits / 8; }
/** Helper abstraction for a word contained in the bitmap. */
template< long BITS >
class Word
{
public:
typedef unsigned long Type;
enum
{
Size = (BITS + W_bits - 1) / W_bits
};
};
/** Get the number of chars that are used for the bitmap. */
static long chars(long bits) noexcept
{ return (bits + C_bits -1) / C_bits; }
/** Helper abstraction for a byte contained in the bitmap. */
template< long BITS >
class Char
{
public:
typedef unsigned char Type;
enum
{
Size = (BITS + C_bits - 1) / C_bits
};
};
/**
* Set the value of bit `bit` to `on`.
*
* \param bit The number of the bit.
* \param on The boolean value that shall be assigned to the bit.
*/
void bit(long bit, bool on) noexcept;
/**
* Clear bit `bit`.
*
* \param bit The number of the bit to clear.
*/
void clear_bit(long bit) noexcept;
/**
* Clear bit `bit` atomically.
*
* Use this function for multi-threaded access to the bitmap.
*
* \param bit The number of the bit to clear.
*/
void atomic_clear_bit(long bit) noexcept;
/**
* Clear bit `bit` atomically and return old state.
*
* Use this function for multi-threaded access to the bitmap.
*
* \param bit The number of the bit to clear.
*/
word_type atomic_get_and_clear(long bit) noexcept;
/**
* Set bit `bit`.
*
* \param bit The number of the bit to set.
*/
void set_bit(long bit) noexcept;
/**
* Set bit `bit` atomically.
*
* Use this function for multi-threaded access to the bitmap.
*
* \param bit The number of the bit to set.
*/
void atomic_set_bit(long bit) noexcept;
/**
* Set bit `bit` atomically and return old state.
*
* Use this function for multi-threaded access to the bitmap.
*
* \param bit The number of the bit to set.
*/
word_type atomic_get_and_set(long bit) noexcept;
/**
* Get the truth value of a bit.
*
* \param bit The number of the bit to read.
*
* \retval 0 Bit is not set.
* \retval != 0 Bit is set.
*/
word_type bit(long bit) const noexcept;
/**
* Get the bit at index `bit`.
*
* \param bit The number of the bit to read.
*
* \retval 0 Bit is not set.
* \retval != 0 Bit is set.
*/
word_type operator [] (long bit) const noexcept
{ return this->bit(bit); }
/**
* Get the lvalue for the bit at index `bit`.
*
* \param bit The number.
*
* \return lvalue for `bit`
*/
Bit operator [] (long bit) noexcept
{ return Bit(this, bit); }
/**
* Scan for the first zero bit.
*
* \param max_bit Upper bound (exclusive) for the scanning operation.
* \param start_bit Hint at the number of the first bit to look at.
* Zero bits below `start_bit` may or may not be
* taken into account by the implementation.
*
* \retval >= 0 Number of first zero bit found.
* \retval -1 All bits between `start_bit` and `max_bit` are set.
*/
long scan_zero(long max_bit, long start_bit = 0) const noexcept;
void *bit_buffer() const noexcept { return _bits; }
protected:
static int _bzl(unsigned long w) noexcept;
};
/**
* A static bitmap.
*
* \tparam BITS The number of bits that shall be in the bitmap.
*/
template<int BITS>
class Bitmap : public Bitmap_base
{
private:
char _bits[Bitmap_base::Char<BITS>::Size];
public:
/** Create a bitmap with `BITS` bits. */
Bitmap() noexcept : Bitmap_base(_bits) {}
Bitmap(Bitmap<BITS> const &o) noexcept : Bitmap_base(_bits)
{ __builtin_memcpy(_bits, o._bits, sizeof(_bits)); }
/**
* Scan for the first zero bit.
*
* \param start_bit Hint at the number of the first bit to look at.
* Zero bits below `start_bit` may or may not be
* taken into account by the implementation.
*
* \retval >= 0 Number of first zero bit found.
* \retval -1 All bits at `start_bit` or higher are set.
*
* Compared to Bitmap_base::scan_zero(), the upper bound is set to BITS.
*/
long scan_zero(long start_bit = 0) const noexcept;
void clear_all()
{ __builtin_memset(_bits, 0, sizeof(_bits)); }
};
inline
void
Bitmap_base::bit(long bit, bool on) noexcept
{
long idx = word_index(bit);
long b = bit_index(bit);
_bits[idx] = (_bits[idx] & ~(1UL << b)) | (static_cast<unsigned long>(on) << b);
}
inline
void
Bitmap_base::clear_bit(long bit) noexcept
{
long idx = word_index(bit);
long b = bit_index(bit);
_bits[idx] &= ~(1UL << b);
}
inline
void
Bitmap_base::atomic_clear_bit(long bit) noexcept
{
long idx = word_index(bit);
long b = bit_index(bit);
word_type mask = 1UL << b;
__atomic_and_fetch(&_bits[idx], ~mask, __ATOMIC_RELAXED);
}
inline
Bitmap_base::word_type
Bitmap_base::atomic_get_and_clear(long bit) noexcept
{
long idx = word_index(bit);
long b = bit_index(bit);
word_type mask = 1UL << b;
return __atomic_fetch_and(&_bits[idx], ~mask, __ATOMIC_RELAXED) & mask;
}
inline
void
Bitmap_base::set_bit(long bit) noexcept
{
long idx = word_index(bit);
long b = bit_index(bit);
_bits[idx] |= (1UL << b);
}
inline
void
Bitmap_base::atomic_set_bit(long bit) noexcept
{
long idx = word_index(bit);
long b = bit_index(bit);
word_type mask = 1UL << b;
__atomic_or_fetch(&_bits[idx], mask, __ATOMIC_RELAXED);
}
inline
Bitmap_base::word_type
Bitmap_base::atomic_get_and_set(long bit) noexcept
{
long idx = word_index(bit);
long b = bit_index(bit);
word_type mask = 1UL << b;
return __atomic_fetch_or(&_bits[idx], mask, __ATOMIC_RELAXED) & mask;
}
inline
Bitmap_base::word_type
Bitmap_base::bit(long bit) const noexcept
{
long idx = word_index(bit);
long b = bit_index(bit);
return _bits[idx] & (1UL << b);
}
inline
int
Bitmap_base::_bzl(unsigned long w) noexcept
{
for (int i = 0; i < W_bits; ++i, w >>= 1)
{
if ((w & 1) == 0)
return i;
}
return -1;
}
inline
long
Bitmap_base::scan_zero(long max_bit, long start_bit) const noexcept
{
if (!(operator [] (start_bit)))
return start_bit;
long idx = word_index(start_bit);
max_bit -= start_bit & ~(W_bits - 1);
for (; max_bit > 0; max_bit -= W_bits, ++idx)
{
if (_bits[idx] == 0)
return idx * W_bits;
if (_bits[idx] != ~0UL)
{
long zbit = _bzl(_bits[idx]);
return zbit < max_bit ? idx * W_bits + zbit : -1;
}
}
return -1;
}
template<int BITS> inline
long
Bitmap<BITS>::scan_zero(long start_bit) const noexcept
{
return Bitmap_base::scan_zero(BITS, start_bit);
}
};

View File

@@ -0,0 +1,322 @@
// vi:ft=cpp
/**
* \file
* \brief AVL tree
*/
/*
* (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>,
* Carsten Weinhold <weinhold@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include "../type_traits"
#include "bst_base.h"
#include "bst_iter.h"
struct Avl_set_tester;
namespace cxx { namespace Bits {
/**
* \brief Basic binary search tree (BST).
*
* This class is intended as a base class for concrete binary search trees,
* such as an AVL tree. This class already provides the basic lookup methods
* and iterator definitions for a BST.
*/
template< typename Node, typename Get_key, typename Compare >
class Bst
{
friend struct ::Avl_set_tester;
private:
typedef Direction Dir;
/// Ops for forward iterators
struct Fwd
{
static Node *child(Node const *n, Direction d)
{ return Bst_node::next<Node>(n, d); }
static bool cmp(Node const *l, Node const *r)
{ return Compare()(Get_key::key_of(l), Get_key::key_of(r)); }
};
/// Ops for Reverse iterators
struct Rev
{
static Node *child(Node const *n, Direction d)
{ return Bst_node::next<Node>(n, !d); }
static bool cmp(Node const *l, Node const *r)
{ return Compare()(Get_key::key_of(r), Get_key::key_of(l)); }
};
public:
/// The type of key values used to generate the total order of the elements.
typedef typename Get_key::Key_type Key_type;
/// The type for key parameters.
typedef typename Type_traits<Key_type>::Param_type Key_param_type;
/// Helper for building forward iterators for different wrapper classes.
typedef Fwd Fwd_iter_ops;
/// Helper for building reverse iterators for different wrapper classes.
typedef Rev Rev_iter_ops;
/// \name Iterators
/**@{*/
/// Forward iterator.
typedef __Bst_iter<Node, Node, Fwd> Iterator;
/// Constant forward iterator.
typedef __Bst_iter<Node, Node const, Fwd> Const_iterator;
/// Backward iterator.
typedef __Bst_iter<Node, Node, Rev> Rev_iterator;
/// Constant backward.
typedef __Bst_iter<Node, Node const, Rev> Const_rev_iterator;
/**@}*/
protected:
/**
* \name Interior access for descendants.
*
* As this class is an intended base class we provide protected access
* to our interior, use 'using' to make this private in concrete
* implementations.
*/
/**@{*/
/// The head pointer of the tree.
Bst_node *_head;
/// Create an empty tree.
Bst() : _head(0) {}
/// Access the head node as object of type \a Node.
Node *head() const { return static_cast<Node*>(_head); }
/// Get the key value of \a n.
static Key_type k(Bst_node const *n)
{ return Get_key::key_of(static_cast<Node const *>(n)); }
/**
* \brief Get the direction to go from `l` to search for `r`.
* \param l is the key to look for.
* \param r is the key at the current position.
* \retval Direction::L for left
* \retval Direction::R for right
* \retval Direction::N if `l` is equal to `r`.
*/
static Dir dir(Key_param_type l, Key_param_type r)
{
Compare cmp;
Dir d(cmp(r, l));
if (d == Direction::L && !cmp(l, r))
return Direction::N;
return d;
}
/**
* \brief Get the direction to go from `l` to search for `r`.
* \param l is the key to look for.
* \param r is the node at the current position.
* \retval Direction::L For left.
* \retval Direction::R For right.
* \retval Direction::N If `l` is equal to `r`.
*/
static Dir dir(Key_param_type l, Bst_node const *r)
{ return dir(l, k(r)); }
/// Is \a l greater than \a r.
static bool greater(Key_param_type l, Key_param_type r)
{ return Compare()(r, l); }
/// Is \a l greater than \a r.
static bool greater(Key_param_type l, Bst_node const *r)
{ return greater(l, k(r)); }
/// Is \a l greater than \a r.
static bool greater(Bst_node const *l, Bst_node const *r)
{ return greater(k(l), k(r)); }
/**@}*/
/**
* Remove all elements in the subtree of head.
*
* \param head Head of the the subtree to remove
* \param callback Optional function called on each removed element.
*/
template<typename FUNC>
static void remove_tree(Bst_node *head, FUNC &&callback)
{
if (Bst_node *n = Bst_node::next(head, Dir::L))
remove_tree(n, callback);
if (Bst_node *n = Bst_node::next(head, Dir::R))
remove_tree(n, callback);
callback(static_cast<Node *>(head));
}
public:
/**
* \name Get default iterators for the ordered tree.
*/
/**@{*/
/**
* \brief Get the constant forward iterator for the first element in the set.
* \return Constant forward iterator for the first element in the set.
*/
Const_iterator begin() const { return Const_iterator(head()); }
/**
* \brief Get the end marker for the constant forward iterator.
* \return The end marker for the constant forward iterator.
*/
Const_iterator end() const { return Const_iterator(); }
/**
* \brief Get the mutable forward iterator for the first element of the set.
* \return The mutable forward iterator for the first element of the set.
*/
Iterator begin() { return Iterator(head()); }
/**
* \brief Get the end marker for the mutable forward iterator.
* \return The end marker for mutable forward iterator.
*/
Iterator end() { return Iterator(); }
/**
* \brief Get the constant backward iterator for the last element in the set.
* \return The constant backward iterator for the last element in the set.
*/
Const_rev_iterator rbegin() const { return Const_rev_iterator(head()); }
/**
* \brief Get the end marker for the constant backward iterator.
* \return The end marker for the constant backward iterator.
*/
Const_rev_iterator rend() const { return Const_rev_iterator(); }
/**
* \brief Get the mutable backward iterator for the last element of the set.
* \return The mutable backward iterator for the last element of the set.
*/
Rev_iterator rbegin() { return Rev_iterator(head()); }
/**
* \brief Get the end marker for the mutable backward iterator.
* \return The end marker for mutable backward iterator.
*/
Rev_iterator rend() { return Rev_iterator(); }
/**@}*/
/**
* \name Lookup functions.
*/
///@{
/**
* \brief find the node with the given \a key.
* \param key The key value of the element to search.
* \return A pointer to the node with the given \a key, or
* NULL if \a key was not found.
*/
Node *find_node(Key_param_type key) const;
/**
* Find the first node with a key not less than the given `key`.
*
* \param key The key used for the search.
* \return A pointer to the found node, or `NULL` if no node was found.
*/
Node *lower_bound_node(Key_param_type key) const;
/**
* \brief find the node with the given \a key.
* \param key The key value of the element to search.
* \return A valid iterator for the node with the given \a key,
* or an invalid iterator if \a key was not found.
*/
Const_iterator find(Key_param_type key) const;
/**
* Clear the tree.
*
* \param callback Optional function to be called on each removed element.
*
* The callback may delete the elements. The function guarantees that
* the elements are no longer used after the callback has been called.
*/
template<typename FUNC>
void remove_all(FUNC &&callback)
{
if (!_head)
return;
Bst_node *head = _head;
_head = 0;
remove_tree(head, cxx::forward<FUNC>(callback));
}
///@}
};
/* find an element */
template< typename Node, typename Get_key, class Compare>
inline
Node *
Bst<Node, Get_key, Compare>::find_node(Key_param_type key) const
{
Dir d;
for (Bst_node *q = _head; q; q = Bst_node::next(q, d))
{
d = dir(key, q);
if (d == Dir::N)
return static_cast<Node*>(q);
}
return 0;
}
template< typename Node, typename Get_key, class Compare>
inline
Node *
Bst<Node, Get_key, Compare>::lower_bound_node(Key_param_type key) const
{
Dir d;
Bst_node *r = 0;
for (Bst_node *q = _head; q; q = Bst_node::next(q, d))
{
d = dir(key, q);
if (d == Dir::L)
r = q; // found a node greater than key
else if (d == Dir::N)
return static_cast<Node*>(q);
}
return static_cast<Node*>(r);
}
/* find an element */
template< typename Node, typename Get_key, class Compare>
inline
typename Bst<Node, Get_key, Compare>::Const_iterator
Bst<Node, Get_key, Compare>::find(Key_param_type key) const
{
Bst_node *q = _head;
Bst_node *r = q;
for (Dir d; q; q = Bst_node::next(q, d))
{
d = dir(key, q);
if (d == Dir::N)
return Iterator(static_cast<Node*>(q), static_cast<Node *>(r));
if (d != Dir::L && q == r)
r = Bst_node::next(q, d);
}
return Iterator();
}
}}

View File

@@ -0,0 +1,128 @@
// vi:ft=cpp
/**
* \file
* \brief AVL tree
*/
/*
* (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>,
* Carsten Weinhold <weinhold@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
/*
* This file contains very basic bits for implementing binary search trees
*/
namespace cxx {
/**
* \brief Internal helpers for the cxx package.
*/
namespace Bits {
/**
* \brief The direction to go in a binary search tree.
*/
struct Direction
{
/// The literal direction values.
enum Direction_e
{
L = 0, ///< Go to the left child
R = 1, ///< Go to the right child
N = 2 ///< Stop
};
unsigned char d;
/// Uninitialized direction
Direction() = default;
/// Convert a literal direction (#L, #R, #N) to an object
Direction(Direction_e d) : d(d) {}
/// Convert a boolean to a direction (false == #L, true == #R)
explicit Direction(bool b) : d(Direction_e(b)) /*d(b ? R : L)*/ {}
/**
* \brief Negate the direction.
* \note This is only defined for a current value of #L or #R
*/
Direction operator ! () const { return Direction(!d); }
/// \name Comparison operators (equality and inequality)
/**@{*/
/// Compare for equality.
bool operator == (Direction_e o) const { return d == o; }
/// Compare for inequality.
bool operator != (Direction_e o) const { return d != o; }
/// Compare for equality.
bool operator == (Direction o) const { return d == o.d; }
/// Compare for inequality.
bool operator != (Direction o) const { return d != o.d; }
/**@}*/
};
/**
* \brief Basic type of a node in a binary search tree (BST).
*/
class Bst_node
{
// all BSTs are friends
template< typename Node, typename Get_key, typename Compare >
friend class Bst;
protected:
/**
* \name Access to BST linkage.
*
* Provide access to the tree linkage to inherited classes
* Inherited nodes, such as AVL nodes should make these methods
* private via 'using'
*/
/**@{*/
/// Get next node in direction \a d.
static Bst_node *next(Bst_node const *p, Direction d)
{ return p->_c[d.d]; }
/// Set next node of \a p in direction \a d to \a n.
static void next(Bst_node *p, Direction d, Bst_node *n)
{ p->_c[d.d] = n; }
/// Get pointer to link in direction \a d.
static Bst_node **next_p(Bst_node *p, Direction d)
{ return &p->_c[d.d]; }
/// Get next node in direction \a d as type \a Node.
template< typename Node > static
Node *next(Bst_node const *p, Direction d)
{ return static_cast<Node *>(p->_c[d.d]); }
/// Rotate subtree \a t in the opposite direction of \a idir.
static void rotate(Bst_node **t, Direction idir);
/**@}*/
private:
Bst_node *_c[2];
protected:
/// Create uninitialized node
Bst_node() {}
/// Create initialized node
explicit Bst_node(bool) { _c[0] = _c[1] = 0; }
};
inline
void
Bst_node::rotate(Bst_node **t, Direction idir)
{
Bst_node *tmp = *t;
*t = next(tmp, idir);
next(tmp, idir, next(*t, !idir));
next(*t, !idir, tmp);
}
}}

View File

@@ -0,0 +1,177 @@
// vi:ft=cpp
/**
* \file
* \brief AVL tree
*/
/*
* (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>,
* Carsten Weinhold <weinhold@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include "bst_base.h"
namespace cxx { namespace Bits {
/**
* \internal
* \ingroup cxx_api
* \brief Generic iterator for the AVL-tree based set.
* \param Cmp the type of the comparison functor.
* \param Node the type of a node.
* \param Node_op the type used to determine the direction of the iterator.
*/
template< typename Node, typename Node_op >
class __Bst_iter_b
{
protected:
typedef Direction Dir;
Node const *_n; ///< Current node
Node const *_r; ///< Root node of current subtree
/// Create an invalid iterator, used as end marker.
__Bst_iter_b() : _n(0), _r(0) {}
/**
* \brief Create an iterator for the given AVL tree.
* \param t the root node of the tree to iterate.
* \param cmp the comparison functor for tree elements.
*/
__Bst_iter_b(Node const *t)
: _n(t), _r(_n)
{ _downmost(); }
__Bst_iter_b(Node const *t, Node const *r)
: _n(t), _r(r)
{}
/// traverse the subtree down to the leftmost/rightmost leave.
inline void _downmost();
/// Increment to the next element.
inline void inc();
public:
/// Check two iterators for equality.
bool operator == (__Bst_iter_b const &o) const { return _n == o._n; }
/// Check two iterators for non equality.
bool operator != (__Bst_iter_b const &o) const { return _n != o._n; }
};
/**
* \internal
* \ingroup cxx_api
* \brief Generic iterator for the AVL-tree based set.
* \param Node the type of a node.
* \param Node_type the type of the node to return stored in a node.
* \param Node_op the type used to determine the direction of the iterator.
*/
template< typename Node, typename Node_type, typename Node_op >
class __Bst_iter : public __Bst_iter_b<Node, Node_op>
{
private:
/// Super-class type
typedef __Bst_iter_b<Node, Node_op> Base;
using Base::_n;
using Base::_r;
using Base::inc;
public:
/// Create an invalid iterator (end marker)
__Bst_iter() {}
/**
* \brief Create an iterator for the given tree.
* \param t the root node of the tree to iterate.
* \param cmp the comparison functor for tree elements.
*/
__Bst_iter(Node const *t) : Base(t) {}
__Bst_iter(Node const *t, Node const *r) : Base(t, r) {}
// template<typename Key2>
__Bst_iter(Base const &o) : Base(o) {}
/**
* \brief Dereference the iterator and get the item out of the tree.
* \return A reference to the data stored in the AVL tree.
*/
Node_type &operator * () const { return *const_cast<Node *>(_n); }
/**
* \brief Member access to the item the iterator points to.
* \return A pointer to the item in the node.
*/
Node_type *operator -> () const { return const_cast<Node *>(_n); }
/**
* \brief Set the iterator to the next element (pre increment).
*/
__Bst_iter &operator ++ () { inc(); return *this; }
/**
* \brief Set the iterator to the next element (post increment).
*/
__Bst_iter &operator ++ (int)
{ __Bst_iter tmp = *this; inc(); return tmp; }
};
//----------------------------------------------------------------------------
/* IMPLEMENTATION: __Bst_iter_b */
template< typename Node, typename Node_op>
inline
void __Bst_iter_b<Node, Node_op>::_downmost()
{
while (_n)
{
Node *n = Node_op::child(_n, Dir::L);
if (n)
_n = n;
else
return;
}
}
template< typename Node, typename Node_op>
void __Bst_iter_b<Node, Node_op>::inc()
{
if (!_n)
return;
if (_n == _r)
{
_r = _n = Node_op::child(_r, Dir::R);
_downmost();
return;
}
if (Node_op::child(_n, Dir::R))
{
_n = Node_op::child(_n, Dir::R);
_downmost();
return;
}
Node const *q = _r;
Node const *p = _r;
while (1)
{
if (Node_op::cmp(_n, q))
{
p = q;
q = Node_op::child(q, Dir::L);
}
else if (_n == q || Node_op::child(q, Dir::R) == _n)
{
_n = p;
return;
}
else
q = Node_op::child(q, Dir::R);
}
}
}}

View File

@@ -0,0 +1,163 @@
/*
* (c) 2011 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
namespace cxx { namespace Bits {
template< typename T >
class List_iterator_end_ptr
{
private:
template< typename U > friend class Basic_list;
static void *_end;
};
template< typename T >
void *List_iterator_end_ptr<T>::_end;
template< typename VALUE_T, typename TYPE >
struct Basic_list_policy
{
typedef VALUE_T *Value_type;
typedef VALUE_T const *Const_value_type;
typedef TYPE **Type;
typedef TYPE *Const_type;
typedef TYPE *Head_type;
typedef TYPE Item_type;
static Type next(Type c) { return &(*c)->_n; }
static Const_type next(Const_type c) { return c->_n; }
};
/// Internal: Common functions for all head-based list implementations.
template< typename POLICY >
class Basic_list
{
Basic_list(Basic_list const &) = delete;
void operator = (Basic_list const &) = delete;
public:
typedef typename POLICY::Value_type Value_type;
typedef typename POLICY::Const_value_type Const_value_type;
class Iterator
{
private:
typedef typename POLICY::Type Internal_type;
public:
typedef typename POLICY::Value_type value_type;
typedef typename POLICY::Value_type Value_type;
Value_type operator * () const { return static_cast<Value_type>(*_c); }
Value_type operator -> () const { return static_cast<Value_type>(*_c); }
Iterator operator ++ () { _c = POLICY::next(_c); return *this; }
bool operator == (Iterator const &o) const { return *_c == *o._c; }
bool operator != (Iterator const &o) const { return !operator == (o); }
Iterator() : _c(__end()) {}
private:
friend class Basic_list;
static Internal_type __end()
{
union X { Internal_type l; void **v; } z;
z.v = &Bits::List_iterator_end_ptr<void>::_end;
return z.l;
}
explicit Iterator(Internal_type i) : _c(i) {}
Internal_type _c;
};
class Const_iterator
{
private:
typedef typename POLICY::Const_type Internal_type;
public:
typedef typename POLICY::Value_type value_type;
typedef typename POLICY::Value_type Value_type;
Value_type operator * () const { return static_cast<Value_type>(_c); }
Value_type operator -> () const { return static_cast<Value_type>(_c); }
Const_iterator operator ++ () { _c = POLICY::next(_c); return *this; }
friend bool operator == (Const_iterator const &lhs, Const_iterator const &rhs)
{ return lhs._c == rhs._c; }
friend bool operator != (Const_iterator const &lhs, Const_iterator const &rhs)
{ return lhs._c != rhs._c; }
Const_iterator() {}
Const_iterator(Iterator const &o) : _c(*o) {}
private:
friend class Basic_list;
explicit Const_iterator(Internal_type i) : _c(i) {}
Internal_type _c;
};
// BSS allocation
explicit Basic_list(bool) {}
Basic_list() : _f(0) {}
Basic_list(Basic_list &&o) : _f(o._f)
{
o.clear();
}
Basic_list &operator = (Basic_list &&o)
{
_f = o._f;
o.clear();
return *this;
}
/// Check if the list is empty.
bool empty() const { return !_f; }
/// Return the first element in the list.
Value_type front() const { return static_cast<Value_type>(_f); }
/**
* Remove all elements from the list.
*
* After the operation the state of the elements is undefined.
*/
void clear() { _f = 0; }
/// Return an iterator to the beginning of the list.
Iterator begin() { return Iterator(&_f); }
/// Return a const iterator to the beginning of the list.
Const_iterator begin() const { return Const_iterator(_f); }
/**
* Return a const iterator that begins at the given element.
*
* \param c Element where the iterator should start.
*
* \pre The element `c` must already be in a list.
*/
static Const_iterator iter(Const_value_type c) { return Const_iterator(c); }
/// Return a const iterator to the end of the list.
Const_iterator end() const { return Const_iterator(nullptr); }
/// Return an iterator to the end of the list.
Iterator end() { return Iterator(); }
protected:
static typename POLICY::Type __get_internal(Iterator const &i) { return i._c; }
static Iterator __iter(typename POLICY::Type c) { return Iterator(c); }
/// Pointer to front of the list.
typename POLICY::Head_type _f;
};
}}

View File

@@ -0,0 +1,180 @@
/**
* \file
* Implementation of a list of smart-pointer-managed objects.
*/
/*
* Copyright (C) 2018, 2022, 2024 Kernkonzept GmbH.
* Author(s): Sarah Hoffmann <sarah.hoffmann@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include "../type_traits"
namespace cxx { namespace Bits {
/**
* List item for an arbitrary item in a Smart_ptr_list.
*
* \tparam T Type of object to be stored in the list.
* \tparam STORE_T Storage type for pointer to next item. The class must
* implement a get() function that returns a pointer to the
* stored object and destroy the stored object when the item
* goes out of scope.
*/
template <typename T, typename STORE_T>
class Smart_ptr_list_item
{
using Value_type = T;
using Storage_type = STORE_T;
template<typename U> friend class Smart_ptr_list;
Storage_type _n;
};
/**
* List of smart-pointer-managed objects.
*
* \tparam ITEM Type of the list items.
*
* The list is implemented as a single-linked list connected via smart pointers,
* so that they are automatically cleaned up when they are removed from the
* list.
*/
template <typename ITEM>
class Smart_ptr_list
{
using Value_type = typename ITEM::Value_type;
using Next_type = typename ITEM::Storage_type;
public:
class Iterator
{
public:
Iterator() : _c(nullptr) {}
Value_type *operator * () const { return _c; }
Value_type *operator -> () const { return _c; }
Iterator operator ++ ()
{
_c = _c->_n.get();
return *this;
}
bool operator == (Iterator const &o) const { return _c == o._c; }
bool operator != (Iterator const &o) const { return !operator == (o); }
private:
friend class Smart_ptr_list;
explicit Iterator(Value_type *i) : _c(i) {}
Value_type *_c;
};
class Const_iterator
{
public:
Const_iterator() : _c(nullptr) {}
Value_type const *operator * () const { return _c; }
Value_type const *operator -> () const { return _c; }
Const_iterator operator ++ ()
{
_c = _c->_n.get();
return *this;
}
bool operator == (Const_iterator const &o) const { return _c == o._c; }
bool operator != (Const_iterator const &o) const { return !operator == (o); }
private:
friend class Smart_ptr_list;
explicit Const_iterator(Value_type const *i) : _c(i) {}
Value_type const *_c;
};
Smart_ptr_list() : _b(&_f) {}
/// Add an element to the front of the list.
void push_front(Next_type &&e)
{
e->_n = cxx::move(this->_f);
this->_f = cxx::move(e);
if (_b == &_f)
_b = &(_f->_n);
}
/// Add an element to the front of the list.
void push_front(Next_type const &e)
{
e->_n = cxx::move(this->_f);
this->_f = e;
if (_b == &_f)
_b = &(_f->_n);
}
/// Add an element at the end of the list.
void push_back(Next_type &&e)
{
*_b = cxx::move(e);
_b = &((*_b)->_n);
}
/// Add an element at the end of the list.
void push_back(Next_type const &e)
{
*_b = e;
_b = &((*_b)->_n);
}
/// Return a pointer to the first element in the list.
Value_type *front() const
{ return _f.get(); }
/**
* Remove the element in front of the list and return it.
*
* \return The element that was previously in front of the list
* as a managed pointer or a nullptr-equivalent when the
* list was already empty.
*/
Next_type pop_front()
{
Next_type ret = cxx::move(_f);
if (ret)
_f = cxx::move(ret->_n);
if (!_f)
_b = &_f;
return ret;
}
/// Check if the list is empty.
bool empty() const
{ return !_f; }
Iterator begin() { return Iterator(_f.get()); }
Iterator end() { return Iterator(); }
Const_iterator begin() const { return Const_iterator(_f.get()); }
Const_iterator end() const { return Const_iterator(); }
Const_iterator cbegin() const { return const_iterator(_f.get()); }
Const_iterator cend() const { return Const_iterator(); }
private:
Next_type _f;
Next_type *_b;
};
} }

View File

@@ -0,0 +1,220 @@
// vi:ft=cpp
/*
* (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>,
* Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
namespace cxx {
class Null_type;
template< bool flag, typename T, typename F >
class Select
{
public:
typedef T Type;
};
template< typename T, typename F >
class Select< false, T, F >
{
public:
typedef F Type;
};
template< typename T, typename U >
class Conversion
{
typedef char S;
class B { char dummy[2]; };
static S test(U);
static B test(...);
static T make_T();
public:
enum
{
exists = sizeof(test(make_T())) == sizeof(S),
two_way = exists && Conversion<U,T>::exists,
exists_2_way = two_way,
same_type = false
};
};
template< >
class Conversion<void, void>
{
public:
enum { exists = 1, two_way = 1, exists_2_way = two_way, same_type = 1 };
};
template< typename T >
class Conversion<T, T>
{
public:
enum { exists = 1, two_way = 1, exists_2_way = two_way, same_type = 1 };
};
template< typename T >
class Conversion<void, T>
{
public:
enum { exists = 0, two_way = 0, exists_2_way = two_way, same_type = 0 };
};
template< typename T >
class Conversion<T, void>
{
public:
enum { exists = 0, two_way = 0, exists_2_way = two_way, same_type = 0 };
};
template< int I >
class Int_to_type
{
public:
enum { i = I };
};
namespace TT
{
template< typename U > class Pointer_traits
{
public:
typedef Null_type Pointee;
enum { value = false };
};
template< typename U > class Pointer_traits< U* >
{
public:
typedef U Pointee;
enum { value = true };
};
template< typename U > struct Ref_traits
{
enum { value = false };
typedef U Referee;
};
template< typename U > struct Ref_traits<U&>
{
enum { value = true };
typedef U Referee;
};
template< typename U > struct Add_ref { typedef U &Type; };
template< typename U > struct Add_ref<U&> { typedef U Type; };
template< typename U > struct PMF_traits { enum { value = false }; };
template< typename U, typename F > struct PMF_traits<U F::*>
{ enum { value = true }; };
template< typename U > class Is_unsigned { public: enum { value = false }; };
template<> class Is_unsigned<unsigned> { public: enum { value = true }; };
template<> class Is_unsigned<unsigned char> {
public: enum { value = true };
};
template<> class Is_unsigned<unsigned short> {
public: enum { value = true };
};
template<> class Is_unsigned<unsigned long> {
public: enum { value = true };
};
template<> class Is_unsigned<unsigned long long> {
public: enum { value = true };
};
template< typename U > class Is_signed { public: enum { value = false }; };
template<> class Is_signed<signed char> { public: enum { value = true }; };
template<> class Is_signed<signed short> { public: enum { value = true }; };
template<> class Is_signed<signed> { public: enum { value = true }; };
template<> class Is_signed<signed long> { public: enum { value = true }; };
template<> class Is_signed<signed long long> {
public: enum { value = true };
};
template< typename U > class Is_int { public: enum { value = false }; };
template<> class Is_int< char > { public: enum { value = true }; };
template<> class Is_int< bool > { public: enum { value = true }; };
template<> class Is_int< wchar_t > { public: enum { value = true }; };
template< typename U > class Is_float { public: enum { value = false }; };
template<> class Is_float< float > { public: enum { value = true }; };
template<> class Is_float< double > { public: enum { value = true }; };
template<> class Is_float< long double > { public: enum { value = true }; };
template<typename T> class Const_traits
{
public:
enum { value = false };
typedef T Type;
typedef const T Const_type;
};
template<typename T> class Const_traits<const T>
{
public:
enum { value = true };
typedef T Type;
typedef const T Const_type;
};
};
template< typename T >
class Type_traits
{
public:
enum
{
is_unsigned = TT::Is_unsigned<T>::value,
is_signed = TT::Is_signed<T>::value,
is_int = TT::Is_int<T>::value,
is_float = TT::Is_float<T>::value,
is_pointer = TT::Pointer_traits<T>::value,
is_pointer_to_member = TT::PMF_traits<T>::value,
is_reference = TT::Ref_traits<T>::value,
is_scalar = is_unsigned || is_signed || is_int || is_pointer
|| is_pointer_to_member || is_reference,
is_fundamental = is_unsigned || is_signed || is_float
|| Conversion<T, void>::same_type,
is_const = TT::Const_traits<T>::value,
alignment =
(sizeof(T) >= sizeof(unsigned long)
? sizeof(unsigned long)
: (sizeof(T) >= sizeof(unsigned)
? sizeof(unsigned)
: (sizeof(T) >= sizeof(short)
? sizeof(short)
: 1)))
};
typedef typename Select<is_scalar, T, typename TT::Add_ref<typename TT::Const_traits<T>::Const_type>::Type>::Type Param_type;
typedef typename TT::Pointer_traits<T>::Pointee Pointee_type;
typedef typename TT::Ref_traits<T>::Referee Referee_type;
typedef typename TT::Const_traits<T>::Type Non_const_type;
typedef typename TT::Const_traits<T>::Const_type Const_type;
static unsigned long align(unsigned long a)
{
return (a + static_cast<unsigned long>(alignment) - 1UL)
& ~(static_cast<unsigned long>(alignment) - 1UL);
}
};
};

View File

@@ -0,0 +1,439 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* (c) 2011 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
namespace cxx {
class D_list_item
{
public:
constexpr D_list_item() : _dli_next(nullptr), _dli_prev(nullptr) {}
D_list_item(D_list_item const &) = delete;
void operator = (D_list_item const &) = delete;
private:
friend struct D_list_item_policy;
D_list_item *_dli_next, *_dli_prev;
};
struct D_list_item_policy
{
typedef D_list_item Item;
static D_list_item *&prev(D_list_item *e) { return e->_dli_prev; }
static D_list_item *&next(D_list_item *e) { return e->_dli_next; }
static D_list_item *prev(D_list_item const *e) { return e->_dli_prev; }
static D_list_item *next(D_list_item const *e) { return e->_dli_next; }
};
template< typename T >
struct Sd_list_head_policy
{
typedef T *Head_type;
static T *head(Head_type h) { return h; }
static void set_head(Head_type &h, T *v) { h = v; }
};
template<
typename T,
typename C = D_list_item_policy
>
class D_list_cyclic
{
protected:
template< typename VALUE, typename ITEM >
class __Iterator
{
public:
typedef VALUE *Value_type;
typedef VALUE *value_type;
__Iterator() {}
bool operator == (__Iterator const &o) const
{ return _c == o._c; }
bool operator != (__Iterator const &o) const
{ return _c != o._c; }
__Iterator &operator ++ ()
{
_c = C::next(_c);
return *this;
}
__Iterator &operator -- ()
{
_c = C::prev(_c);
return *this;
}
Value_type operator * () const { return static_cast<Value_type>(_c); }
Value_type operator -> () const { return static_cast<Value_type>(_c); }
protected:
friend class D_list_cyclic;
explicit __Iterator(ITEM *s) : _c(s) {}
ITEM *_c;
};
public:
typedef T *Value_type;
typedef T *value_type;
typedef __Iterator<T, typename C::Item> Iterator;
typedef Iterator Const_iterator;
static void remove(T *e)
{
C::next(C::prev(e)) = C::next(e);
C::prev(C::next(e)) = C::prev(e);
C::next(e) = nullptr;
}
static Iterator erase(Iterator const &e)
{
typename C::Item *n = C::next(*e);
remove(*e);
return __iter(n);
}
static Iterator iter(T const *e) { return Iterator(const_cast<T*>(e)); }
static bool in_list(T const *e) { return C::next(const_cast<T*>(e)); }
static bool has_sibling(T const *e) { return C::next(const_cast<T*>(e)) != e; }
static Iterator insert_after(T *e, Iterator const &pos)
{
C::prev(e) = pos._c;
C::next(e) = C::next(pos._c);
C::prev(C::next(pos._c)) = e;
C::next(pos._c) = e;
return pos;
}
static Iterator insert_before(T *e, Iterator const &pos)
{
C::next(e) = pos._c;
C::prev(e) = C::prev(pos._c);
C::next(C::prev(pos._c)) = e;
C::prev(pos._c) = e;
return pos;
}
protected:
static void self_insert(typename C::Item *e)
{ C::next(e) = C::prev(e) = e; }
static void remove_last(T *e)
{ C::next(e) = nullptr; }
/**
* Splice the elements of `other_list` into the list before `pos`.
*
* \pre Must not be called for an empty `other_list`!
* \post Leaves the `other_list` in an invalid state.
*/
static void splice_heads(Const_iterator pos, typename C::Item *other_list)
{
typename C::Item *ins_next = pos._c;
typename C::Item *ins_prev = C::prev(pos._c);
typename C::Item *other_head = C::next(other_list);
typename C::Item *other_tail = C::prev(other_list);
C::next(ins_prev) = other_head;
C::prev(other_head) = ins_prev;
C::prev(ins_next) = other_tail;
C::next(other_tail) = ins_next;
}
static Iterator __iter(typename C::Item *e) { return Iterator(e); }
};
template<
typename T,
typename C = D_list_item_policy,
typename H = Sd_list_head_policy<T>,
bool BSS = false
>
class Sd_list : public D_list_cyclic<T, C>
{
private:
typedef D_list_cyclic<T, C> Base;
public:
class Iterator : public Base::Iterator
{
public:
Iterator &operator ++ ()
{
if (this->_c)
Base::Iterator::operator ++ ();
if (this->_c == _h)
this->_c = nullptr;
return *this;
}
Iterator &operator -- () = delete;
private:
friend class Sd_list;
explicit Iterator(T *h) : Base::Iterator(h), _h(h) {}
typename C::Item *_h;
};
class R_iterator : public Base::Iterator
{
public:
R_iterator &operator ++ ()
{
if (this->_c)
Base::Iterator::operator -- ();
if (this->_c == _h)
this->_c = nullptr;
return *this;
}
R_iterator &operator -- () = delete;
private:
friend class Sd_list;
explicit R_iterator(T *h) : Base::Iterator(h), _h(h) {}
typename C::Item *_h;
};
//typedef typename Base::Iterator Iterator;
enum Pos
{ Back, Front };
Sd_list()
{
if (!BSS)
H::set_head(_f, nullptr);
}
bool empty() const { return !H::head(_f); }
T *front() const { return H::head(_f); }
void remove(T *e)
{
T *h = H::head(_f);
if (e == C::next(e)) // must be the last
{
Base::remove_last(e);
H::set_head(_f, nullptr);
return;
}
if (e == H::head(_f))
H::set_head(_f, static_cast<T*>(C::next(h)));
Base::remove(e);
}
Iterator erase(Iterator const &e)
{
Iterator next = e;
++next;
remove(*e);
return next;
}
void push(T *e, Pos pos)
{
T *h = H::head(_f);
if (!h)
{
Base::self_insert(e);
H::set_head(_f, e);
}
else
{
Base::insert_before(e, this->iter(h));
if (pos == Front)
H::set_head(_f, e);
}
}
void push_back(T *e) { push(e, Back); }
void push_front(T *e) { push(e, Front); }
void rotate_to(T *h) { H::set_head(_f, h); }
typename H::Head_type const &head() const { return _f; }
typename H::Head_type &head() { return _f; }
Iterator begin() { return Iterator(H::head(_f)); }
Iterator end() { return Iterator(nullptr); }
R_iterator rbegin()
{
if (head())
return R_iterator(static_cast<T*>(C::prev(H::head(_f))));
return R_iterator(nullptr);
}
R_iterator rend() { return R_iterator(nullptr); }
private:
Sd_list(Sd_list const &);
void operator = (Sd_list const &);
typename H::Head_type _f;
};
template<
typename T,
typename C = D_list_item_policy,
bool BSS = false
>
class D_list : public D_list_cyclic<T, C>
{
private:
typedef D_list_cyclic<T, C> Base;
typedef typename C::Item Internal_type;
public:
enum Pos
{ Back, Front };
typedef typename Base::Iterator Iterator;
typedef typename Base::Const_iterator Const_iterator;
typedef T* value_type;
typedef T* Value_type;
D_list() { this->self_insert(&_h); }
~D_list() { clear(); }
D_list(D_list &&o)
{
if (o.empty())
{
this->self_insert(&_h);
}
else
{
Internal_type *p = C::prev(&o._h);
Internal_type *n = C::next(&o._h);
C::prev(&_h) = p;
C::next(&_h) = n;
C::next(p) = &_h;
C::prev(n) = &_h;
o.self_insert(&o._h);
}
}
D_list &operator=(D_list &&o)
{
if (&o == this)
return *this;
clear();
if (!o.empty())
{
Internal_type *p = C::prev(&o._h);
Internal_type *n = C::next(&o._h);
C::prev(&_h) = p;
C::next(&_h) = n;
C::next(p) = &_h;
C::prev(n) = &_h;
o.self_insert(&o._h);
}
}
D_list(D_list const &) = delete;
void operator = (D_list const &) = delete;
void splice(Const_iterator pos, D_list &&other)
{
if (other.empty())
return;
Base::splice_heads(pos, &other._h);
other.self_insert(&other._h);
}
bool empty() const { return C::next(&_h) == &_h; }
static void remove(T *e) { Base::remove(e); }
Iterator erase(Iterator const &e) { return Base::erase(e); }
void clear()
{
// Just clear the _dli_next pointers of all elements. It is the indicator
// that an element is not on a list.
Internal_type *i = C::next(&_h);
while (i != &_h)
{
Internal_type *d = i;
i = C::next(i);
C::next(d) = nullptr;
}
this->self_insert(&_h);
}
void push(T *e, Pos pos)
{
if (pos == Front)
Base::insert_after(e, end());
else
Base::insert_before(e, end());
}
void push_back(T *e) { push(e, Back); }
void push_front(T *e) { push(e, Front); }
/**
* Remove element from the end of the list and return it.
*
* \pre The list is not empty.
*/
T *pop_back()
{
T *ret = *(end()--);
remove(ret);
return ret;
}
/**
* Remove element from the beginning of the list and return it.
*
* \pre The list is not empty.
*/
T *pop_front()
{
T *ret = *begin();
remove(ret);
return ret;
}
Iterator begin() const { return this->__iter(C::next(const_cast<Internal_type *>(&_h))); }
Iterator end() const { return this->__iter(const_cast<Internal_type *>(&_h)); }
bool has_sibling(T const *e)
{
return C::next(const_cast<T*>(e)) != &_h
|| C::prev(const_cast<T*>(e)) != &_h;
}
private:
Internal_type _h;
};
}

View File

@@ -0,0 +1,271 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* (c) 2011 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include "bits/list_basics.h"
#include "type_traits"
namespace cxx {
/**
* Basic element type for a double-linked H_list.
*
* \tparam ELEM_TYPE Base class of the list element.
*/
template<typename ELEM_TYPE>
class H_list_item_t
{
public:
/**
* Constructor.
*
* Creates an element that is not in any list.
*/
H_list_item_t() : _n(0), _pn(0) {}
/**
* Destructor.
*
* Automatically removes the element from any list it still might be
* enchained in.
*/
~H_list_item_t() noexcept { l_remove(); }
private:
H_list_item_t(H_list_item_t const &) = delete;
template<typename T, typename P> friend class H_list;
template<typename T, typename X> friend struct Bits::Basic_list_policy;
void l_remove() noexcept
{
if (!_pn)
return;
*_pn = _n;
if (_n)
_n->_pn = _pn;
_pn = 0;
}
H_list_item_t *_n, **_pn;
};
/** Untyped list item. */
typedef H_list_item_t<void> H_list_item;
/**
* General double-linked list of unspecified cxx::H_list_item elements.
*
* Most of the time, you want to use H_list_t.
*/
template< typename T, typename POLICY = Bits::Basic_list_policy< T, H_list_item> >
class H_list : public Bits::Basic_list<POLICY>
{
private:
typedef typename POLICY::Item_type Item;
typedef Bits::Basic_list<POLICY> Base;
H_list(H_list const &);
void operator = (H_list const &);
public:
typedef typename Base::Iterator Iterator;
// BSS allocation
explicit H_list(bool x) : Base(x) {}
H_list() : Base() {}
/**
* Return an iterator for an arbitrary list element
*
* \param c List element to start the iteration.
*
* \return A mutable forward iterator.
*
* \pre The element must be in a list.
*/
static Iterator iter(T *c) { return Base::__iter(c->Item::_pn); }
/// Check if the given element is currently part of a list.
static bool in_list(T const *e) { return e->Item::_pn; }
/// Add element to the front of the list.
void add(T *e)
{
if (this->_f)
this->_f->_pn = &e->Item::_n;
e->Item::_n = this->_f;
e->Item::_pn = &this->_f;
this->_f = static_cast<Item*>(e);
}
/// Add element to the front of the list.
void push_front(T *e) { add(e); }
/**
* Remove and return the head element of the list.
*
* \pre The list must not be empty or the behaviour will be undefined.
*/
T *pop_front()
{
T *r = this->front();
remove(r);
return r;
}
/**
* Insert an element at the iterator position.
*
* \param e New Element to be inserted
* \param pred Iterator pointing to the element after which the
* element will be inserted. If end() is given, the
* element will be inserted at the beginning of the queue.
*
* \return Iterator pointing to the newly inserted element.
*/
Iterator insert(T *e, Iterator const &pred)
{
Item **x = &this->_f;
if (pred != Base::end())
x = &(*pred)->_n;
e->Item::_n = *x;
if (*x)
(*x)->_pn = &(e->Item::_n);
e->Item::_pn = x;
*x = static_cast<Item*>(e);
return iter(e);
}
/**
* Insert an element after the iterator position.
*
* \param e New element to be inserted.
* \param pred Iterator pointing to the element after which the
* element will be inserted. Must not be end().
*
* \return Iterator pointing to the newly inserted element.
*
* \pre The list must not be empty.
*/
static Iterator insert_after(T *e, Iterator const &pred)
{
Item **x = &(*pred)->_n;
e->Item::_n = *x;
if (*x)
(*x)->_pn = &(e->Item::_n);
e->Item::_pn = x;
*x = static_cast<Item*>(e);
return iter(e);
}
/**
* Insert an element before the iterator position.
*
* \param e New element to be inserted.
* \param succ Iterator pointing to the element before which the
* element will be inserted. Must not be end().
*/
static void insert_before(T *e, Iterator const &succ)
{
Item **x = Base::__get_internal(succ);
e->Item::_n = *x;
e->Item::_pn = x;
if (*x)
(*x)->_pn = &e->Item::_n;
*x = static_cast<Item*>(e);
}
/**
* Replace an element in a list with a new element.
*
* \param p Element in list to be replaced.
* \param e Replacement element, must not yet be in a list.
*
* \pre `p` and `e` must not be NULL.
*
* After the operation the p element is no longer in the
* list and may be reused.
*/
static void replace(T *p, T *e)
{
e->Item::_n = p->Item::_n;
e->Item::_pn = p->Item::_pn;
*(p->Item::_pn) = static_cast<Item*>(e);
if (e->Item::_n)
e->Item::_n->_pn = &(e->Item::_n);
p->Item::_pn = 0;
}
/**
* Remove the given element from its list.
*
* \param e Element to be removed. Must be in a list.
*/
static void remove(T *e)
{ e->Item::l_remove(); }
/**
* Remove the element at the given iterator position.
*
* \param e Iterator pointing to the element to be removed. Must not
* point to end().
*
* \return New iterator pointing to the element after the removed one.
*
* \note The hlist implementation guarantees that the original iterator
* is still valid after the element has been removed. In fact, the
* iterator returned is the same as the one supplied in the `e`
* parameter.
*/
static Iterator erase(Iterator const &e)
{ e->Item::l_remove(); return e; }
};
/**
* Double-linked list of typed H_list_item_t elements.
*
* \note H_lists are not self-cleaning. Elements that are still chained
* during destruction are not removed and will therefore be in an
* undefined state after the destruction.
*/
template< typename T >
struct H_list_t : H_list<T, Bits::Basic_list_policy< T, H_list_item_t<T> > >
{
H_list_t() = default;
H_list_t(bool b)
: H_list<T, Bits::Basic_list_policy< T, H_list_item_t<T> > >(b)
{};
};
template< typename T >
class H_list_bss : public H_list<T>
{
public:
H_list_bss() : H_list<T>(true) {}
};
template< typename T >
class H_list_t_bss : public H_list_t<T>
{
public:
H_list_t_bss() : H_list_t<T>(true) {}
};
}

View File

@@ -0,0 +1,411 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/cxx/type_traits>
#include <l4/cxx/std_alloc>
#include <l4/cxx/std_ops>
namespace cxx {
/*
* Classes: List_item, List<D, Alloc>
*/
/**
* \ingroup cxx_api
* \brief Basic list item.
*
* Basic item that can be member of a doubly linked, cyclic list.
*/
class List_item
{
public:
/**
* \brief Iterator for a list of ListItem-s.
*
* The Iterator iterates till it finds the first element again.
*/
class Iter
{
public:
Iter(List_item *c, List_item *f) noexcept : _c(c), _f(f) {}
Iter(List_item *f = 0) noexcept : _c(f), _f(f) {}
List_item *operator * () const noexcept { return _c; }
List_item *operator -> () const noexcept { return _c; }
Iter &operator ++ () noexcept
{
if (!_f)
_c = 0;
else
_c = _c->get_next_item();
if (_c == _f)
_c = 0;
return *this;
}
Iter operator ++ (int) noexcept
{ Iter o = *this; operator ++ (); return o; }
Iter &operator -- () noexcept
{
if (!_f)
_c = 0;
else
_c = _c->get_prev_item();
if (_c == _f)
_c = 0;
return *this;
}
Iter operator -- (int) noexcept
{ Iter o = *this; operator -- (); return o; }
/** Remove item pointed to by iterator, and return pointer to element. */
List_item *remove_me() noexcept
{
if (!_c)
return 0;
List_item *l = _c;
operator ++ ();
l->remove_me();
if (_f == l)
_f = _c;
return l;
}
private:
List_item *_c, *_f;
};
/**
* \brief Iterator for derived classes from ListItem.
*
* Allows direct access to derived classes by * operator.
*
* Example:
* class Foo : public ListItem
* {
* public:
* typedef T_iter<Foo> Iter;
* ...
* };
*/
template< typename T, bool Poly = false>
class T_iter : public Iter
{
private:
static bool const P = !Conversion<const T*, const List_item *>::exists
|| Poly;
static List_item *cast_to_li(T *i, Int_to_type<true>) noexcept
{ return dynamic_cast<List_item*>(i); }
static List_item *cast_to_li(T *i, Int_to_type<false>) noexcept
{ return i; }
static T *cast_to_type(List_item *i, Int_to_type<true>) noexcept
{ return dynamic_cast<T*>(i); }
static T *cast_to_type(List_item *i, Int_to_type<false>) noexcept
{ return static_cast<T*>(i); }
public:
template< typename O >
explicit T_iter(T_iter<O> const &o) noexcept
: Iter(o) { dynamic_cast<T*>(*o); }
//TIter(CListItem *f) : Iter(f) {}
T_iter(T *f = 0) noexcept : Iter(cast_to_li(f, Int_to_type<P>())) {}
T_iter(T *c, T *f) noexcept
: Iter(cast_to_li(c, Int_to_type<P>()),
cast_to_li(f, Int_to_type<P>()))
{}
inline T *operator * () const noexcept
{ return cast_to_type(Iter::operator * (),Int_to_type<P>()); }
inline T *operator -> () const noexcept
{ return operator * (); }
T_iter<T, Poly> operator ++ (int) noexcept
{ T_iter<T, Poly> o = *this; Iter::operator ++ (); return o; }
T_iter<T, Poly> operator -- (int) noexcept
{ T_iter<T, Poly> o = *this; Iter::operator -- (); return o; }
T_iter<T, Poly> &operator ++ () noexcept
{ Iter::operator ++ (); return *this; }
T_iter<T, Poly> &operator -- () noexcept
{ Iter::operator -- (); return *this; }
inline T *remove_me() noexcept;
};
List_item() noexcept : _n(this), _p(this) {}
protected:
List_item(List_item const &) noexcept : _n(this), _p(this) {}
public:
/** Get previous item. */
List_item *get_prev_item() const noexcept { return _p; }
/** Get next item. */
List_item *get_next_item() const noexcept { return _n; }
/** Insert item p before this item. */
void insert_prev_item(List_item *p) noexcept
{
p->_p->_n = this;
List_item *pr = p->_p;
p->_p = _p;
_p->_n = p;
_p = pr;
}
/** Insert item p after this item. */
void insert_next_item(List_item *p) noexcept
{
p->_p->_n = _n;
p->_p = this;
_n->_p = p;
_n = p;
}
/** Remove this item from the list. */
void remove_me() noexcept
{
if (_p != this)
{
_p->_n = _n;
_n->_p = _p;
}
_p = _n = this;
}
/**
* \brief Append item to a list.
*
* Convenience function for empty-head corner case.
* \param head Pointer to the current list head.
* \param p Pointer to new item.
* \return the pointer to the new head.
*/
template< typename C, typename N >
static inline C *push_back(C *head, N *p) noexcept;
/**
* \brief Prepend item to a list.
*
* Convenience function for empty-head corner case.
* \param head pointer to the current list head.
* \param p pointer to new item.
* \return the pointer to the new head.
*/
template< typename C, typename N >
static inline C *push_front(C *head, N *p) noexcept;
/**
* \brief Remove item from a list.
*
* Convenience function for remove-head corner case.
* \param head pointer to the current list head.
* \param p pointer to the item to remove.
* \return the pointer to the new head.
*/
template< typename C, typename N >
static inline C *remove(C *head, N *p) noexcept;
private:
List_item *_n, *_p;
};
/* IMPLEMENTATION -----------------------------------------------------------*/
template< typename C, typename N >
C *List_item::push_back(C *h, N *p) noexcept
{
if (!p)
return h;
if (!h)
return p;
h->insert_prev_item(p);
return h;
}
template< typename C, typename N >
C *List_item::push_front(C *h, N *p) noexcept
{
if (!p)
return h;
if (h)
h->insert_prev_item(p);
return p;
}
template< typename C, typename N >
C *List_item::remove(C *h, N *p) noexcept
{
if (!p)
return h;
if (!h)
return 0;
if (h == p)
{
if (p == p->_n)
h = 0;
else
h = static_cast<C*>(p->_n);
}
p->remove_me();
return h;
}
template< typename T, bool Poly >
inline
T *List_item::T_iter<T, Poly>::remove_me() noexcept
{ return cast_to_type(Iter::remove_me(), Int_to_type<P>()); }
template< typename T >
class T_list_item : public List_item
{
public:
T *next() const { return static_cast<T*>(List_item::get_next_item()); }
T *prev() const { return static_cast<T*>(List_item::get_prev_item()); }
};
template< typename LI >
class L_list
{
private:
LI *_h;
public:
L_list() : _h(0) {}
void push_front(LI *e) { _h = LI::push_front(_h, e); }
void push_back(LI *e) { _h = LI::push_back(_h, e); }
void insert_before(LI *e, LI *p)
{
p->insert_prev_item(e);
if (_h == p)
_h = e;
}
void insert_after(LI *e, LI *p) { p->insert_next_item(e); }
void remove(LI *e)
{ _h = LI::remove(_h, e); }
LI *head() const { return _h; }
};
/**
* Doubly linked list, with internal allocation.
* Container for items of type D, implemented by a doubly linked list.
* Alloc defines the allocator policy.
*/
template< typename D, template<typename A> class Alloc = New_allocator >
class List
{
private:
class E : public List_item
{
public:
E(D const &d) noexcept : data(d) {}
D data;
};
public:
class Node : private E
{};
typedef Alloc<Node> Node_alloc;
/**
* Iterator.
* Forward and backward iteratable.
*/
class Iter
{
private:
List_item::T_iter<E> _i;
public:
Iter(E *e) noexcept : _i(e) {}
D &operator * () const noexcept { return (*_i)->data; }
D &operator -> () const noexcept { return (*_i)->data; }
Iter operator ++ (int) noexcept
{ Iter o = *this; operator ++ (); return o; }
Iter operator -- (int) noexcept
{ Iter o = *this; operator -- (); return o; }
Iter &operator ++ () noexcept { ++_i; return *this; }
Iter &operator -- () noexcept { --_i; return *this; }
/** operator for testing validity (syntactically equal to pointers) */
operator E* () const noexcept { return *_i; }
};
List(Alloc<Node> const &a = Alloc<Node>()) noexcept : _h(0), _l(0), _a(a) {}
/** Add element at the end of the list. */
void push_back(D const &d) noexcept
{
void *n = _a.alloc();
if (!n) return;
_h = E::push_back(_h, new (n) E(d));
++_l;
}
/** Add element at the beginning of the list. */
void push_front(D const &d) noexcept
{
void *n = _a.alloc();
if (!n) return;
_h = E::push_front(_h, new (n) E(d));
++_l;
}
/** Remove element pointed to by the iterator. */
void remove(Iter const &i) noexcept
{ E *e = i; _h = E::remove(_h, e); --_l; _a.free(e); }
/** Get the length of the list. */
unsigned long size() const noexcept { return _l; }
/** Random access. Complexity is O(n). */
D const &operator [] (unsigned long idx) const noexcept
{ Iter i = _h; for (; idx && *i; ++i, --idx) { } return *i; }
/** Random access. Complexity is O(n). */
D &operator [] (unsigned long idx) noexcept
{ Iter i = _h; for (; idx && *i; ++i, --idx) { } return *i; }
/** Get iterator for the list elements. */
Iter items() noexcept { return Iter(_h); }
private:
E *_h;
unsigned _l;
Alloc<Node> _a;
};
};

View File

@@ -0,0 +1,524 @@
// vim:set ft=cpp: -*- Mode: C++ -*-
/*
* (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>,
* Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/cxx/arith>
#include <l4/cxx/minmax>
#include <l4/sys/consts.h>
namespace cxx {
/**
* Standard list-based allocator.
*/
class List_alloc
{
private:
friend class List_alloc_sanity_guard;
struct Mem_block
{
Mem_block *next;
unsigned long size;
};
Mem_block *_first;
inline void check_overlap(void *, unsigned long );
inline void sanity_check_list(char const *, char const *);
inline void merge();
public:
/**
* Initializes an empty list allocator.
*
* \note To initialize the allocator with available memory
* use the #free() function.
*/
List_alloc() : _first(0) {}
/**
* Return a free memory block to the allocator.
*
* \param block Pointer to memory block.
* \param size Size of memory block.
* \param initial_free Set to true for putting fresh memory
* to the allocator. This will enforce alignment on that
* memory.
*
* \pre `block` must not be NULL.
* \pre `2 * sizeof(void *)` <= `size` <= `~0UL - 32`.
*/
inline void free(void *block, unsigned long size, bool initial_free = false);
/**
* Allocate a memory block.
*
* \param size Size of the memory block.
* \param align Alignment constraint.
* \param lower Lower bound of the physical region the memory block should be
* allocated from.
* \param upper Upper bound of the physical region the memory block should be
* allocated from, value is inclusive.
*
* \return Pointer to memory block
*
* \pre 0 < `size` <= `~0UL - 32`.
*/
inline void *alloc(unsigned long size, unsigned long align,
unsigned long lower = 0, unsigned long upper = ~0UL);
/**
* Allocate a memory block of `min` <= size <= `max`.
*
* \param min Minimal size to allocate (in bytes).
* \param[in,out] max Maximum size to allocate (in bytes). The actual
* allocated size is returned here.
* \param align Alignment constraint.
* \param granularity Granularity to use for the allocation (power
* of 2).
* \param lower Lower bound of the physical region the memory
* block should be allocated from.
* \param upper Upper bound of the physical region the memory
* block should be allocated from, value is
* inclusive.
*
* \return Pointer to memory block
*
* \pre 0 < `min` <= `~0UL - 32`.
* \pre 0 < `max`.
*/
inline void *alloc_max(unsigned long min, unsigned long *max,
unsigned long align, unsigned granularity,
unsigned long lower = 0, unsigned long upper = ~0UL);
/**
* Get the amount of available memory.
*
* \return Available memory in bytes
*/
inline unsigned long avail();
template <typename DBG>
void dump_free_list(DBG &out);
};
#if !defined (CXX_LIST_ALLOC_SANITY)
class List_alloc_sanity_guard
{
public:
List_alloc_sanity_guard(List_alloc *, char const *)
{}
};
void
List_alloc::check_overlap(void *, unsigned long )
{}
void
List_alloc::sanity_check_list(char const *, char const *)
{}
#else
class List_alloc_sanity_guard
{
private:
List_alloc *a;
char const *func;
public:
List_alloc_sanity_guard(List_alloc *a, char const *func)
: a(a), func(func)
{ a->sanity_check_list(func, "entry"); }
~List_alloc_sanity_guard()
{ a->sanity_check_list(func, "exit"); }
};
void
List_alloc::check_overlap(void *b, unsigned long s)
{
unsigned long const mb_align = (1UL << arith::Ld<sizeof(Mem_block)>::value) - 1;
if ((unsigned long)b & mb_align)
{
L4::cerr << "List_alloc(FATAL): trying to free unaligned memory: "
<< b << " align=" << arith::Ld<sizeof(Mem_block)>::value << "\n";
}
Mem_block *c = _first;
for (;c ; c = c->next)
{
unsigned long x_s = (unsigned long)b;
unsigned long x_e = x_s + s;
unsigned long b_s = (unsigned long)c;
unsigned long b_e = b_s + c->size;
if ((x_s >= b_s && x_s < b_e)
|| (x_e > b_s && x_e <= b_e)
|| (b_s >= x_s && b_s < x_e)
|| (b_e > x_s && b_e <= x_e))
{
L4::cerr << "List_alloc(FATAL): trying to free memory that "
"is already free: \n ["
<< (void*)x_s << '-' << (void*)x_e << ") overlaps ["
<< (void*)b_s << '-' << (void*)b_e << ")\n";
}
}
}
void
List_alloc::sanity_check_list(char const *func, char const *info)
{
Mem_block *c = _first;
for (;c ; c = c->next)
{
if (c->next)
{
if (c >= c->next)
{
L4::cerr << "List_alloc(FATAL): " << func << '(' << info
<< "): list order violation\n";
}
if (((unsigned long)c) + c->size > (unsigned long)c->next)
{
L4::cerr << "List_alloc(FATAL): " << func << '(' << info
<< "): list order violation\n";
}
}
}
}
#endif
void
List_alloc::merge()
{
List_alloc_sanity_guard __attribute__((unused)) guard(this, __func__);
Mem_block *c = _first;
while (c && c->next)
{
unsigned long f_start = reinterpret_cast<unsigned long>(c);
unsigned long f_end = f_start + c->size;
unsigned long n_start = reinterpret_cast<unsigned long>(c->next);
if (f_end == n_start)
{
c->size += c->next->size;
c->next = c->next->next;
continue;
}
c = c->next;
}
}
void
List_alloc::free(void *block, unsigned long size, bool initial_free)
{
List_alloc_sanity_guard __attribute__((unused)) guard(this, __func__);
unsigned long const mb_align = (1UL << arith::Ld<sizeof(Mem_block)>::value) - 1;
if (initial_free)
{
// enforce alignment constraint on initial memory
unsigned long nblock = (reinterpret_cast<unsigned long>(block) + mb_align)
& ~mb_align;
size = (size - (nblock - reinterpret_cast<unsigned long>(block)))
& ~mb_align;
block = reinterpret_cast<void*>(nblock);
}
else
// blow up size to the minimum aligned size
size = (size + mb_align) & ~mb_align;
check_overlap(block, size);
Mem_block **c = &_first;
Mem_block *next = 0;
if (*c)
{
while (*c && *c < block)
c = &(*c)->next;
next = *c;
}
*c = reinterpret_cast<Mem_block*>(block);
(*c)->next = next;
(*c)->size = size;
merge();
}
void *
List_alloc::alloc_max(unsigned long min, unsigned long *max, unsigned long align,
unsigned granularity, unsigned long lower,
unsigned long upper)
{
List_alloc_sanity_guard __attribute__((unused)) guard(this, __func__);
unsigned char const mb_bits = arith::Ld<sizeof(Mem_block)>::value;
unsigned long const mb_align = (1UL << mb_bits) - 1;
// blow minimum up to at least the minimum aligned size of a Mem_block
min = l4_round_size(min, mb_bits);
// truncate maximum to at least the size of a Mem_block
*max = l4_trunc_size(*max, mb_bits);
// truncate maximum size according to granularity
*max = *max & ~(granularity - 1UL);
if (min > *max)
return 0;
unsigned long almask = align ? (align - 1UL) : 0;
// minimum alignment is given by the size of a Mem_block
if (almask < mb_align)
almask = mb_align;
Mem_block **c = &_first;
Mem_block **fit = 0;
unsigned long max_fit = 0;
unsigned long a_lower = (lower + almask) & ~almask;
for (; *c; c = &(*c)->next)
{
// address of free memory block
unsigned long n_start = reinterpret_cast<unsigned long>(*c);
// block too small, next
// XXX: maybe we can skip this and just do the test below
if ((*c)->size < min)
continue;
// block outside region, next
if (upper < n_start || a_lower > n_start + (*c)->size)
continue;
// aligned start address within the free block
unsigned long a_start = (n_start + almask) & ~almask;
// check if aligned start address is behind the block, next
if (a_start - n_start >= (*c)->size)
continue;
a_start = a_start < a_lower ? a_lower : a_start;
// end address would overflow, next
if (min > ~0UL - a_start)
continue;
// block outside region, next
if (a_start + min - 1UL > upper)
continue;
// remaining size after subtracting the padding for the alignment
unsigned long r_size = (*c)->size - a_start + n_start;
// upper limit can limit maximum size
if (a_start + r_size - 1UL > upper)
r_size = upper - a_start + 1UL;
// round down according to granularity
r_size &= ~(granularity - 1UL);
// block too small
if (r_size < min)
continue;
if (r_size >= *max)
{
fit = c;
max_fit = *max;
break;
}
if (r_size > max_fit)
{
max_fit = r_size;
fit = c;
}
}
if (fit)
{
unsigned long n_start = reinterpret_cast<unsigned long>(*fit);
unsigned long a_lower = (lower + almask) & ~almask;
unsigned long a_start = (n_start + almask) & ~almask;
a_start = a_start < a_lower ? a_lower : a_start;
unsigned long r_size = (*fit)->size - a_start + n_start;
if (a_start > n_start)
{
(*fit)->size -= r_size;
fit = &(*fit)->next;
}
else
*fit = (*fit)->next;
*max = max_fit;
if (r_size == max_fit)
return reinterpret_cast<void *>(a_start);
Mem_block *m = reinterpret_cast<Mem_block*>(a_start + max_fit);
m->next = *fit;
m->size = r_size - max_fit;
*fit = m;
return reinterpret_cast<void *>(a_start);
}
return 0;
}
void *
List_alloc::alloc(unsigned long size, unsigned long align, unsigned long lower,
unsigned long upper)
{
List_alloc_sanity_guard __attribute__((unused)) guard(this, __func__);
unsigned long const mb_align
= (1UL << arith::Ld<sizeof(Mem_block)>::value) - 1;
// blow up size to the minimum aligned size
size = (size + mb_align) & ~mb_align;
unsigned long almask = align ? (align - 1UL) : 0;
// minimum alignment is given by the size of a Mem_block
if (almask < mb_align)
almask = mb_align;
Mem_block **c = &_first;
unsigned long a_lower = (lower + almask) & ~almask;
for (; *c; c=&(*c)->next)
{
// address of free memory block
unsigned long n_start = reinterpret_cast<unsigned long>(*c);
// block too small, next
// XXX: maybe we can skip this and just do the test below
if ((*c)->size < size)
continue;
// block outside region, next
if (upper < n_start || a_lower > n_start + (*c)->size)
continue;
// aligned start address within the free block
unsigned long a_start = (n_start + almask) & ~almask;
// block too small after alignment, next
if (a_start - n_start >= (*c)->size)
continue;
a_start = a_start < a_lower ? a_lower : a_start;
// end address would overflow, next
if (size > ~0UL - a_start)
continue;
// block outside region, next
if (a_start + size - 1UL > upper)
continue;
// remaining size after subtracting the padding
// for the alignment
unsigned long r_size = (*c)->size - a_start + n_start;
// block too small
if (r_size < size)
continue;
if (a_start > n_start)
{
// have free space before the allocated block
// shrink the block and set c to the next pointer of that
// block
(*c)->size -= r_size;
c = &(*c)->next;
}
else
// drop the block, c remains the next pointer of the
// previous block
*c = (*c)->next;
// allocated the whole remaining space
if (r_size == size)
return reinterpret_cast<void*>(a_start);
// add a new free block behind the allocated block
Mem_block *m = reinterpret_cast<Mem_block*>(a_start + size);
m->next = *c;
m->size = r_size - size;
*c = m;
return reinterpret_cast<void *>(a_start);
}
return 0;
}
unsigned long
List_alloc::avail()
{
List_alloc_sanity_guard __attribute__((unused)) guard(this, __FUNCTION__);
Mem_block *c = _first;
unsigned long a = 0;
while (c)
{
a += c->size;
c = c->next;
}
return a;
}
template <typename DBG>
void
List_alloc::dump_free_list(DBG &out)
{
Mem_block *c = _first;
while (c)
{
unsigned sz;
const char *unit;
if (c->size < 1024)
{
sz = c->size;
unit = "Byte";
}
else if (c->size < 1 << 20)
{
sz = c->size >> 10;
unit = "KB";
}
else
{
sz = c->size >> 20;
unit = "MB";
}
out.printf("%12p - %12p (%u %s)\n", c,
reinterpret_cast<char *>(c) + c->size - 1, sz, unit);
c = c->next;
}
}
}

View File

@@ -0,0 +1,111 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include "type_traits"
/**
* \ingroup cxx_api
* \brief Various kinds of C++ utilities.
*/
namespace cxx
{
// trivial, used to terminate the variadic recursion
template<typename A>
constexpr A const &
min(A const &a)
{ return a; }
/**
* \ingroup cxx_api
* Get the minimum of `a1` and `a2` upt to `aN`.
*
* \param a1 The first value.
* \param a2 The second value.
* \param ...a Arbitrary number of additional parameters.
*
* Matches with automatic argument type deduction.
*/
template<typename A, typename ...ARGS>
constexpr A const &
min(A const &a1, A const &a2, ARGS const &...a)
{
return min((a1 <= a2) ? a1 : a2, a...);
}
/**
* \ingroup cxx_api
* Get the minimum of `a1` and `a2` upt to `aN`.
*
* \param a1 The first value.
* \param a2 The second value.
* \param ...a Arbitrary number of additional parameters.
*
* Matches with explicit template type A.
*/
template<typename A, typename ...ARGS>
constexpr A const &
min(cxx::identity_t<A> const &a1,
cxx::identity_t<A> const &a2,
ARGS const &...a)
{
return min<A>((a1 <= a2) ? a1 : a2, a...);
}
// trivial, used to terminate the variadic recursion
template<typename A>
constexpr A const &
max(A const &a)
{ return a; }
/**
* \ingroup cxx_api
* Get the maximum of `a1` and `a2` upt to `aN`.
*
* \param a1 The first value.
* \param a2 The second value.
* \param ...a Arbitrary number of additional parameters.
*
* Matches with automatic argument type deduction.
*/
template<typename A, typename ...ARGS>
constexpr A const &
max(A const &a1, A const &a2, ARGS const &...a)
{ return max((a1 >= a2) ? a1 : a2, a...); }
/**
* \ingroup cxx_api
* Get the maximum of `a1` and `a2` upt to `aN`.
*
* \param a1 The first value.
* \param a2 The second value.
* \param ...a Arbitrary number of additional parameters.
*
* Matches with explicit template type A.
*/
template<typename A, typename ...ARGS>
constexpr A const &
max(cxx::identity_t<A> const &a1,
cxx::identity_t<A> const &a2,
ARGS const &...a)
{
return max<A>((a1 >= a2) ? a1 : a2, a...);
}
/**
* \ingroup cxx_api
* \brief Limit \a v to the range given by \a lo and \a hi.
* \param v The value to clamp.
* \param lo The lower boundary to clamp \a v to.
* \param hi The upper boundary to clamp \a v to.
*/
template< typename T1 >
inline
T1 clamp(T1 v, T1 lo, T1 hi)
{ return min(hi, max(lo, v)); }
};

View File

@@ -0,0 +1,78 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* Copyright (C) 2025 Kernkonzept GmbH.
* Author(s): Martin Decky <martin.decky@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/cxx/type_traits>
namespace cxx {
/**
* Compute the greatest common divisor of two unsigned values.
*
* This uses the Euclidean modulo algorithm.
*
* \note Contrary to the C++17 specification, this implementation requires the
* same unsigned type of both arguments and returns the same type (not
* a common type). This should be fine for most practical use cases.
*
* \note Contrary to the C++17 specification, this implementation does not
* accept signed arguments and negative literals.
*
* \tparam T Unsigned integer type of the values.
* \param a First input.
* \param b Second input.
*
* \return Greatest common divisor of the input values.
*/
template <typename T>
constexpr T gcd(T a, T b)
{
static_assert(Type_traits<T>::is_unsigned, "Type must be unsigned");
while (b != 0)
{
T remainder = a % b;
a = b;
b = remainder;
}
return a;
}
/**
* Compute the least common multiple of two unsigned values.
*
* This uses the greatest common divisor to compute the least common
* multiple.
*
* \note Contrary to the C++17 specification, this implementation requires the
* same unsigned type of both arguments and returns the same type (not
* a common type). This should be fine for most practical use cases.
*
* \note Contrary to the C++17 specification, this implementation does not
* accept signed arguments and negative literals.
*
* \tparam T Unsigned integer type of the values.
* \param a First input.
* \param b Second input.
*
* \return Least common multiple of the input values.
*/
template <typename T>
constexpr T lcm(T a, T b)
{
static_assert(Type_traits<T>::is_unsigned, "Type must be unsigned");
if (a == 0 || b == 0)
return 0;
return (a / gcd(a, b)) * b;
}
}

View File

@@ -0,0 +1,32 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/cxx/hlist>
namespace cxx {
class Observer : public H_list_item
{
public:
virtual void notify() = 0;
};
class Notifier : public H_list<Observer>
{
public:
void notify()
{
for (Iterator i = begin(); i != end(); ++i)
i->notify();
}
};
}

View File

@@ -0,0 +1,104 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/**
* \file
* \brief Pair implementation
*/
/*
* (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/cxx/type_traits>
namespace cxx {
/**
* \ingroup cxx_api
* \brief Pair of two values.
*
* Standard container for a pair of values.
* \param First Type of the first value.
* \param Second Type of the second value.
*/
template< typename First, typename Second >
struct Pair
{
/// Type of first value.
typedef First First_type;
/// Type of second value.
typedef Second Second_type;
/// First value.
First first;
/// Second value.
Second second;
/**
* \brief Create a pair from the two values.
* \param first The first value.
* \param second The second value.
*/
template<typename A1, typename A2>
Pair(A1 &&first, A2 &&second)
: first(cxx::forward<A1>(first)), second(cxx::forward<A2>(second)) {}
/**
* \brief Create a pair, default constructing the second value.
* \param first The first value.
*/
template<typename A1>
Pair(A1 &&first)
: first(cxx::forward<A1>(first)), second() {}
/// Default construction.
Pair() = default;
};
template< typename F, typename S >
Pair<F,S> pair(F const &f, S const &s)
{ return cxx::Pair<F,S>(f,s); }
/**
* \brief Comparison functor for Pair.
* \param Cmp Comparison functor for the first value of the pair.
* \param Typ The pair type.
*
* This functor can be used to compare Pair values with respect to the
* first value.
*/
template< typename Cmp, typename Typ >
class Pair_first_compare
{
private:
Cmp const &_cmp;
public:
/**
* \brief Construction.
* \param cmp The comparison functor used for the first value.
*/
Pair_first_compare(Cmp const &cmp = Cmp()) : _cmp(cmp) {}
/**
* \brief Do the comparison based on the first value.
* \param l The lefthand value.
* \param r The righthand value.
*/
bool operator () (Typ const &l, Typ const &r) const
{ return _cmp(l.first,r.first); }
};
}
template< typename OS, typename A, typename B >
inline
OS &operator << (OS &os, cxx::Pair<A,B> const &p)
{
os << p.first << ';' << p.second;
return os;
}

View File

@@ -0,0 +1,345 @@
// vim:set ft=cpp: -*- Mode: C++ -*-
/*
* (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include "type_traits"
#include <stddef.h>
#include <l4/sys/compiler.h>
namespace cxx {
template< typename T >
struct Default_ref_counter
{
void h_drop_ref(T *p) noexcept
{
if (p->remove_ref() == 0)
delete p;
}
void h_take_ref(T *p) noexcept
{
p->add_ref();
}
};
struct Ref_ptr_base
{
enum Default_value
{ Nil = 0 };
};
template<typename T, template< typename X > class CNT = Default_ref_counter>
class Weak_ptr;
/**
* A reference-counting pointer with automatic cleanup.
*
* \tparam T Type of object the pointer points to.
* \tparam CNT Type of management class that manages the life time of
* the object.
*
* This pointer is similar to the standard C++-11 shared_ptr but it does
* the reference counting directly in the object being pointed to, so that
* no additional management structures need to be allocated from the heap.
*
* Classes that use this pointer type must implement two functions:
*
* int remove_ref()
*
* is called when a reference is removed and must return 0 when there are no
* further references to the object.
*
* void add_ref()
*
* is called when another ref_ptr to the object is created.
*
* Ref_obj provides a simple implementation of this interface from which
* classes may inherit.
*/
template <
typename T = void,
template< typename X > class CNT = Default_ref_counter
>
class Ref_ptr : public Ref_ptr_base, private CNT<T>
{
private:
typedef decltype(nullptr) Null_type;
typedef Weak_ptr<T, CNT> Wp;
public:
/// Default constructor creates a pointer with no managed object.
Ref_ptr() noexcept : _p(0) {}
Ref_ptr(Ref_ptr_base::Default_value v)
: _p(reinterpret_cast<T*>(static_cast<unsigned long>(v))) {}
/**
* Create a shared pointer from a weak pointer.
*
* Increases references.
*/
Ref_ptr(Wp const &o) noexcept : _p(o.ptr())
{ __take_ref(); }
/// allow creation from `nullptr`
Ref_ptr(decltype(nullptr) n) noexcept : _p(n) {}
/**
* Create a shared pointer from a raw pointer.
*
* In contrast to C++11 shared_ptr it is safe to use this constructor
* multiple times and have the same reference counter.
*/
template<typename X>
explicit Ref_ptr(X *o) noexcept : _p(o)
{ __take_ref(); }
/**
* Create a shared pointer from a raw pointer without creating a new
* reference.
*
* \param o Pointer to the object.
* \param d Dummy parameter to select this constructor at compile time.
* The value may be true or false.
*
* This is the counterpart to release().
*/
Ref_ptr(T *o, [[maybe_unused]] bool d) noexcept : _p(o) { }
/**
* Return a raw pointer to the object this shared pointer points to.
*
* This does not release the pointer or decrease the reference count.
*/
T *get() const noexcept
{
return _p;
}
/** \copydoc get() */
T *ptr() const noexcept
{
return _p;
}
/**
* Release the shared pointer without removing the reference.
*
* \return A raw pointer to the managed object.
*
*/
T *release() noexcept
{
T *p = _p;
_p = 0;
return p;
}
~Ref_ptr() noexcept
{ __drop_ref(); }
template<typename OT>
Ref_ptr(Ref_ptr<OT, CNT> const &o) noexcept
{
_p = o.ptr();
__take_ref();
}
Ref_ptr(Ref_ptr<T> const &o) noexcept
{
_p = o._p;
__take_ref();
}
template< typename OT >
void operator = (Ref_ptr<OT> const &o) noexcept
{
__drop_ref();
_p = o.ptr();
__take_ref();
}
void operator = (Ref_ptr<T> const &o) noexcept
{
if (&o == this)
return;
__drop_ref();
_p = o._p;
__take_ref();
}
void operator = (Null_type) noexcept
{
__drop_ref();
_p = 0;
}
template<typename OT>
Ref_ptr(Ref_ptr<OT, CNT> &&o) noexcept
{ _p = o.release(); }
Ref_ptr(Ref_ptr<T> &&o) noexcept
{ _p = o.release(); }
template< typename OT >
void operator = (Ref_ptr<OT> &&o) noexcept
{
__drop_ref();
_p = o.release();
}
void operator = (Ref_ptr<T> &&o) noexcept
{
if (&o == this)
return;
__drop_ref();
_p = o.release();
}
[[nodiscard]] explicit operator bool () const noexcept { return _p; }
T *operator -> () const noexcept
{ return _p; }
[[nodiscard]] bool operator == (Ref_ptr const &o) const noexcept
{ return _p == o._p; }
[[nodiscard]] bool operator != (Ref_ptr const &o) const noexcept
{ return _p != o._p; }
[[nodiscard]] bool operator < (Ref_ptr const &o) const noexcept
{ return _p < o._p; }
[[nodiscard]] bool operator <= (Ref_ptr const &o) const noexcept
{ return _p <= o._p; }
[[nodiscard]] bool operator > (Ref_ptr const &o) const noexcept
{ return _p > o._p; }
[[nodiscard]] bool operator >= (Ref_ptr const &o) const noexcept
{ return _p >= o._p; }
[[nodiscard]] bool operator == (T const *o) const noexcept
{ return _p == o; }
[[nodiscard]] bool operator < (T const *o) const noexcept
{ return _p < o; }
[[nodiscard]] bool operator <= (T const *o) const noexcept
{ return _p <= o; }
[[nodiscard]] bool operator > (T const *o) const noexcept
{ return _p > o; }
[[nodiscard]] bool operator >= (T const *o) const noexcept
{ return _p >= o; }
private:
void __drop_ref() noexcept
{
if (_p)
static_cast<CNT<T>*>(this)->h_drop_ref(_p);
}
void __take_ref() noexcept
{
if (_p)
static_cast<CNT<T>*>(this)->h_take_ref(_p);
}
T *_p;
};
template<typename T, template< typename X > class CNT>
class Weak_ptr
{
private:
struct Null_type;
typedef Ref_ptr<T, CNT> Rp;
public:
Weak_ptr() = default;
Weak_ptr(decltype(nullptr)) : _p(nullptr) {}
// backwards 0 ctor
explicit Weak_ptr(int x) noexcept
L4_DEPRECATED("Use initialization from 'nullptr'")
: _p(nullptr)
{ if (x != 0) __builtin_trap(); }
Weak_ptr(Rp const &o) noexcept : _p(o.ptr()) {}
explicit Weak_ptr(T *o) noexcept : _p(o) {}
template<typename OT>
Weak_ptr(Weak_ptr<OT, CNT> const &o) noexcept : _p(o.ptr()) {}
Weak_ptr(Weak_ptr<T, CNT> const &o) noexcept : _p(o._p) {}
Weak_ptr<T, CNT> &operator = (const Weak_ptr<T, CNT> &o) = default;
T *get() const noexcept { return _p; }
T *ptr() const noexcept { return _p; }
T *operator -> () const noexcept { return _p; }
operator Null_type const * () const noexcept
{ return reinterpret_cast<Null_type const*>(_p); }
private:
T *_p;
};
template<typename OT, typename T> inline
Ref_ptr<OT> ref_ptr_static_cast(Ref_ptr<T> const &o)
{ return ref_ptr(static_cast<OT*>(o.ptr())); }
template< typename T >
inline Ref_ptr<T> ref_ptr(T *t)
{ return Ref_ptr<T>(t); }
template< typename T >
inline Weak_ptr<T> weak_ptr(T *t)
{ return Weak_ptr<T>(t); }
class Ref_obj
{
private:
mutable int _ref_cnt;
public:
Ref_obj() : _ref_cnt(0) {}
void add_ref() const noexcept { ++_ref_cnt; }
int remove_ref() const noexcept { return --_ref_cnt; }
};
template< typename T, typename... Args >
Ref_ptr<T>
make_ref_obj(Args &&... args)
{ return cxx::Ref_ptr<T>(new T(cxx::forward<Args>(args)...)); }
template<typename T, typename U>
Ref_ptr<T>
dynamic_pointer_cast(Ref_ptr<U> const &p) noexcept
{
// our constructor from a naked pointer increments the counter
return Ref_ptr<T>(dynamic_cast<T *>(p.get()));
}
template<typename T, typename U>
Ref_ptr<T>
static_pointer_cast(Ref_ptr<U> const &p) noexcept
{
// our constructor from a naked pointer increments the counter
return Ref_ptr<T>(static_cast<T *>(p.get()));
}
}

View File

@@ -0,0 +1,34 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/**
* \file
* Implementation of a list of ref-ptr-managed objects.
*/
/*
* Copyright (C) 2018, 2022, 2024 Kernkonzept GmbH.
* Author(s): Sarah Hoffmann <sarah.hoffmann@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/cxx/ref_ptr>
#include "bits/smart_ptr_list.h"
namespace cxx {
/// Item for list linked with cxx::Ref_ptr.
template <typename T>
using Ref_ptr_list_item = Bits::Smart_ptr_list_item<T, cxx::Ref_ptr<T> >;
/// Item for list linked via cxx::Ref_ptr with default refence counting.
template <typename T>
struct Ref_obj_list_item : public Ref_ptr_list_item<T>, public cxx::Ref_obj {};
/**
* Single-linked list where elements are connected via a cxx::Ref_ptr.
*/
template <typename T>
using Ref_ptr_list = Bits::Smart_ptr_list<Ref_ptr_list_item<T> >;
}

View File

@@ -0,0 +1,485 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/cxx/std_alloc>
#include <l4/cxx/hlist>
#include <l4/sys/consts.h>
namespace cxx {
/**
* \ingroup cxx_api
* Basic slab allocator.
*
* \tparam Obj_size The size of the objects managed by the allocator (in bytes).
* \tparam Slab_size The size of a slab (in bytes).
* \tparam Max_free The maximum number of free slabs. When this limit is reached
* slabs are freed, provided that the backend allocator
* supports allocated memory to be freed.
* \tparam Alloc The backend allocator used to allocate slabs.
*/
template< int Obj_size, int Slab_size = L4_PAGESIZE,
int Max_free = 2, template<typename A> class Alloc = New_allocator >
class Base_slab
{
private:
struct Free_o
{
Free_o *next;
};
protected:
struct Slab_i;
private:
struct Slab_head : public H_list_item
{
/// Number of free objects in the slab.
unsigned num_free;
/// Pointer to the first free object in the slab.
Free_o *free;
/// Pointer to the slab cache (instance of the slab allocator).
Base_slab<Obj_size, Slab_size, Max_free, Alloc> *cache;
inline Slab_head() noexcept : num_free(0), free(0), cache(0)
{}
};
// In an empty or partially filled slab, each free object stores a pointer to
// the next free object. Thus, the size of an object needs to be at least the
// size of a pointer.
static_assert(Obj_size >= sizeof(void *),
"Object size must be at least the size of a pointer.");
static_assert(Obj_size <= Slab_size - sizeof(Slab_head),
"Object_size exceeds slab capability.");
public:
enum
{
/// Size of an object.
object_size = Obj_size,
/// Size of a slab.
slab_size = Slab_size,
/// Objects per slab.
objects_per_slab = (Slab_size - sizeof(Slab_head)) / object_size,
/// Maximum number of free slabs.
max_free_slabs = Max_free,
};
protected:
struct Slab_store
{
char _o[slab_size - sizeof(Slab_head)];
Free_o *object(unsigned obj) noexcept
{ return reinterpret_cast<Free_o*>(_o + object_size * obj); }
};
/// Type of a slab
struct Slab_i : public Slab_store, public Slab_head
{};
public:
/// Type of the backend allocator.
typedef Alloc<Slab_i> Slab_alloc;
typedef void Obj_type;
private:
/// Allocator used for slabs.
Slab_alloc _alloc;
/// Number of empty slabs.
unsigned _num_free;
/// Total number of slabs.
unsigned _num_slabs;
/// List of full slabs.
H_list<Slab_i> _full_slabs;
/// List of partial slabs.
H_list<Slab_i> _partial_slabs;
/// List of empty slabs.
H_list<Slab_i> _empty_slabs;
/// Add a new slab.
void add_slab(Slab_i *s) noexcept
{
s->num_free = objects_per_slab;
s->cache = this;
//L4::cerr << "Slab: " << this << "->add_slab(" << s << ", size="
// << slab_size << "):" << " f=" << s->object(0) << '\n';
// initialize free list
Free_o *f = s->free = s->object(0);
for (unsigned i = 1; i < objects_per_slab; ++i)
{
f->next = s->object(i);
f = f->next;
}
f->next = 0;
// insert slab into cache's list
_empty_slabs.push_front(s);
++_num_slabs;
++_num_free;
}
/// Grow the slab cache, by adding a new slab.
bool grow() noexcept
{
Slab_i *s = _alloc.alloc();
if (!s)
return false;
new (s, cxx::Nothrow()) Slab_i();
add_slab(s);
return true;
}
/**
* Shrink the slab cache by freeing empty slabs.
*
* The flow of memory from the slab cache back to the system is regulated via
* the backend allocator's flag `can_free`. If this flag is set to true, the
* slab cache retains at maximum Max_free empty slabs; empty slabs exceeding
* this limit are freed. If `can_free` is set to false, the shrink operation
* does nothing.
*/
void shrink() noexcept
{
if (!_alloc.can_free)
return;
while (!_empty_slabs.empty() && _num_free > max_free_slabs)
{
Slab_i *s = _empty_slabs.front();
_empty_slabs.remove(s);
--_num_free;
--_num_slabs;
_alloc.free(s);
}
}
public:
Base_slab(Slab_alloc const &alloc = Slab_alloc()) noexcept
: _alloc(alloc), _num_free(0), _num_slabs(0), _full_slabs(),
_partial_slabs(), _empty_slabs()
{}
~Base_slab() noexcept
{
while (!_empty_slabs.empty())
{
Slab_i *o = _empty_slabs.front();
_empty_slabs.remove(o);
_alloc.free(o);
}
while (!_partial_slabs.empty())
{
Slab_i *o = _partial_slabs.front();
_partial_slabs.remove(o);
_alloc.free(o);
}
while (!_full_slabs.empty())
{
Slab_i *o = _full_slabs.front();
_full_slabs.remove(o);
_alloc.free(o);
}
}
/**
* Allocate a new object.
*
* \return A pointer to the new object if the allocation succeeds, or 0 on
* failure to acquire memory from the backend allocator when the slab
* cache memory is already exhausted.
*
* \note The user is responsible for initializing the object.
*/
void *alloc() noexcept
{
H_list<Slab_i> *free = &_partial_slabs;
if (free->empty())
free = &_empty_slabs;
if (free->empty() && !grow())
return 0;
Slab_i *s = free->front();
Free_o *o = s->free;
s->free = o->next;
if (free == &_empty_slabs)
{
_empty_slabs.remove(s);
--_num_free;
}
--(s->num_free);
if (!s->free)
{
_partial_slabs.remove(s);
_full_slabs.push_front(s);
}
else if (free == &_empty_slabs)
_partial_slabs.push_front(s);
//L4::cerr << this << "->alloc(): " << o << ", of " << s << '\n';
return o;
}
/**
* Free the given object (`_o`).
*
* \pre The object must have been allocated with this allocator.
*/
void free(void *_o) noexcept
{
if (!_o)
return;
unsigned long addr = reinterpret_cast<unsigned long>(_o);
// find out the slab the object is in
addr = (addr / slab_size) * slab_size;
Slab_i *s = reinterpret_cast<Slab_i*>(addr);
if (s->cache != this)
return;
Free_o *o = reinterpret_cast<Free_o*>(_o);
o->next = s->free;
s->free = o;
bool was_full = false;
if (!s->num_free)
{
_full_slabs.remove(s);
was_full = true;
}
++(s->num_free);
if (s->num_free == objects_per_slab)
{
if (!was_full)
_partial_slabs.remove(s);
_empty_slabs.push_front(s);
++_num_free;
if (_num_free > max_free_slabs)
shrink();
was_full = false;
}
else if (was_full)
_partial_slabs.push_front(s);
//L4::cerr << this << "->free(" << _o << "): of " << s << '\n';
}
/**
* Get the total number of objects managed by the slab allocator.
*
* \return The number of objects managed by the allocator (including the
* free objects).
*/
unsigned total_objects() const noexcept
{ return _num_slabs * objects_per_slab; }
/**
* Get the number of objects which can be allocated before a new empty slab
* needs to be added to the slab allocator.
*
* \return The number of free objects in the slab allocator.
*/
unsigned free_objects() const noexcept
{
unsigned count = 0;
/* count partial slabs first */
for (typename H_list<Slab_i>::Const_iterator s = _partial_slabs.begin();
s != _partial_slabs.end(); ++s)
count += s->num_free;
/* add empty slabs */
count += _num_free * objects_per_slab;
return count;
}
};
/**
* \ingroup cxx_api
* Slab allocator for object of type `Type`.
*
* \tparam Type The type of the objects to manage.
* \tparam Slab_size Size of a slab.
* \tparam Max_free The maximum number of free slabs.
* \tparam Alloc The allocator for the slabs.
*/
template<typename Type, int Slab_size = L4_PAGESIZE,
int Max_free = 2, template<typename A> class Alloc = New_allocator >
class Slab : public Base_slab<sizeof(Type), Slab_size, Max_free, Alloc>
{
private:
typedef Base_slab<sizeof(Type), Slab_size, Max_free, Alloc> Base_type;
public:
typedef Type Obj_type;
Slab(typename Base_type::Slab_alloc const &alloc
= typename Base_type::Slab_alloc()) noexcept
: Base_slab<sizeof(Type), Slab_size, Max_free, Alloc>(alloc) {}
/**
* Allocate an object of type `Type`.
*
* \return A pointer to the object just allocated, or 0 on failure.
*
* \note The user is responsible for initializing the object.
*/
Type *alloc() noexcept
{
return reinterpret_cast<Type *>(Base_type::alloc());
}
/**
* Free the object addressed by `o`.
*
* \param o The pointer to the object to free.
* \pre The object must have been allocated with this allocator.
*/
void free(Type *o) noexcept
{ Base_slab<sizeof(Type), Slab_size, Max_free, Alloc>::free(o); }
};
/**
* \ingroup cxx_api
* Merged slab allocator (allocators for objects of the same size are merged
* together).
*
* \tparam Obj_size The size of an object managed by the slab allocator.
* \tparam Slab_size The size of a slab.
* \tparam Max_free The maximum number of free slabs.
* \tparam Alloc The allocator for the slabs.
*
* This slab allocator class is useful for merging slab allocators with the
* same parameters (equal `Obj_size`, `Slab_size`, `Max_free`, and
* `Alloc` parameters) together and share the overhead for the slab caches
* among all equal-sized objects.
*/
template< int Obj_size, int Slab_size = L4_PAGESIZE,
int Max_free = 2, template<typename A> class Alloc = New_allocator >
class Base_slab_static
{
private:
typedef Base_slab<Obj_size, Slab_size, Max_free, Alloc> _A;
static _A _a;
public:
typedef void Obj_type;
enum
{
/// Size of an object.
object_size = Obj_size,
/// Size of a slab.
slab_size = Slab_size,
/// Number of objects per slab.
objects_per_slab = _A::objects_per_slab,
/// Maximum number of free slabs.
max_free_slabs = Max_free,
};
/**
* Allocate an object.
*
* \note The user is responsible for initializing the object.
*/
void *alloc() noexcept { return _a.alloc(); }
/**
* Free the given object (`p`).
*
* \param p The pointer to the object to free.
* \pre `p` must be a pointer to an object allocated by this allocator.
*/
void free(void *p) noexcept { _a.free(p); }
/**
* Get the total number of objects managed by the slab allocator.
*
* \return The number of objects managed by the allocator (including the
* free objects).
* \note The value is the merged value for all equal parameterized
* Base_slab_static instances.
*/
unsigned total_objects() const noexcept { return _a.total_objects(); }
/**
* Get the number of free objects in the slab allocator.
*
* \return The number of free objects in all free and partially used
* slabs managed by this allocator.
* \note The value is the merged value for all equal parameterized
* Base_slab_static instances.
*/
unsigned free_objects() const noexcept { return _a.free_objects(); }
};
template< int _O, int _S, int _M, template<typename A> class Alloc >
typename Base_slab_static<_O,_S,_M,Alloc>::_A
Base_slab_static<_O,_S,_M,Alloc>::_a;
/**
* \ingroup cxx_api
* Merged slab allocator (allocators for objects of the same size are merged
* together).
*
* \tparam Type The type of the objects to manage.
* \tparam Slab_size The size of a slab.
* \tparam Max_free The maximum number of free slabs.
* \tparam Alloc The allocator for the slabs.
*
* This slab allocator class is useful for merging slab allocators with the
* same parameters (equal `sizeof(Type)`, `Slab_size`, `Max_free`, and
* `Alloc` parameters) together and share the overhead for the slab caches
* among all equal-sized objects.
*/
template<typename Type, int Slab_size = L4_PAGESIZE,
int Max_free = 2, template<typename A> class Alloc = New_allocator >
class Slab_static
: public Base_slab_static<sizeof(Type), Slab_size, Max_free, Alloc>
{
public:
typedef Type Obj_type;
/**
* Allocate an object of type `Type`.
*
* \return A pointer to the just allocated object, or 0 on failure.
*
* \note The object is not zeroed out by the slab allocator.
*/
Type *alloc() noexcept
{
return reinterpret_cast<Type *>(
Base_slab_static<sizeof(Type), Slab_size, Max_free, Alloc>::alloc());
}
};
}

View File

@@ -0,0 +1,212 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* (c) 2011 Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include "bits/list_basics.h"
namespace cxx {
class S_list_item
{
public:
S_list_item() : _n(0) {}
// BSS allocation
explicit S_list_item(bool) {}
private:
template<typename T, typename P> friend class S_list;
template<typename T, typename P> friend class S_list_tail;
template<typename T, typename X> friend struct Bits::Basic_list_policy;
S_list_item(S_list_item const &);
void operator = (S_list_item const &);
S_list_item *_n;
};
/**
* Simple single-linked list.
*
* \tparam T Type of elements saved in the list. Must inherit from
* cxx::S_list_item
*/
template< typename T, typename POLICY = Bits::Basic_list_policy< T, S_list_item > >
class S_list : public Bits::Basic_list<POLICY>
{
S_list(S_list const &) = delete;
void operator = (S_list const &) = delete;
private:
typedef typename Bits::Basic_list<POLICY> Base;
public:
typedef typename Base::Iterator Iterator;
S_list(S_list &&o) : Base(static_cast<Base&&>(o)) {}
S_list &operator = (S_list &&o)
{
Base::operator = (static_cast<Base&&>(o));
return *this;
}
// BSS allocation
explicit S_list(bool x) : Base(x) {}
S_list() : Base() {}
/// Add an element to the front of the list.
void add(T *e)
{
e->_n = this->_f;
this->_f = e;
}
template< typename CAS >
void add(T *e, CAS const &c)
{
do
{
e->_n = this->_f;
}
while (!c(&this->_f, e->_n, e));
}
/// Add an element to the front of the list.
void push_front(T *e) { add(e); }
/**
* Remove and return the head element of the list.
*
* \pre The list must not be empty or the behaviour will be undefined.
*/
T *pop_front()
{
T *r = this->front();
if (this->_f)
this->_f = this->_f->_n;
return r;
}
void insert(T *e, Iterator const &pred)
{
S_list_item *p = *pred;
e->_n = p->_n;
p->_n = e;
}
static void insert_before(T *e, Iterator const &succ)
{
S_list_item **x = Base::__get_internal(succ);
e->_n = *x;
*x = e;
}
static void replace(Iterator const &p, T*e)
{
S_list_item **x = Base::__get_internal(p);
e->_n = (*x)->_n;
*x = e;
}
static Iterator erase(Iterator const &e)
{
S_list_item **x = Base::__get_internal(e);
*x = (*x)->_n;
return e;
}
};
template< typename T >
class S_list_bss : public S_list<T>
{
public:
S_list_bss() : S_list<T>(true) {}
};
template< typename T, typename POLICY = Bits::Basic_list_policy< T, S_list_item > >
class S_list_tail : public S_list<T, POLICY>
{
private:
typedef S_list<T, POLICY> Base;
void add(T *e) = delete;
public:
using Iterator = typename Base::Iterator;
S_list_tail() : Base(), _tail(&this->_f) {}
S_list_tail(S_list_tail &&t)
: Base(static_cast<Base&&>(t)), _tail(t.empty() ? &this->_f : t._tail)
{
t._tail = &t._f;
}
S_list_tail &operator = (S_list_tail &&t)
{
if (&t == this)
return *this;
Base::operator = (static_cast<Base &&>(t));
_tail = t.empty() ? &this->_f : t._tail;
t._tail = &t._f;
return *this;
}
void push_front(T *e)
{
if (Base::empty())
_tail = &e->_n;
Base::push_front(e);
}
void push_back(T *e)
{
e->_n = 0;
*_tail = e;
_tail = &e->_n;
}
void clear()
{
Base::clear();
_tail = &this->_f;
}
void append(S_list_tail &o)
{
T *x = o.front();
*_tail = x;
if (x)
_tail = o._tail;
o.clear();
}
T *pop_front()
{
T *t = Base::pop_front();
if (t && Base::empty())
_tail = &this->_f;
return t;
}
private:
static void insert(T *e, Iterator const &pred);
static void insert_before(T *e, Iterator const &succ);
static void replace(Iterator const &p, T*e);
static Iterator erase(Iterator const &e);
private:
S_list_item **_tail;
};
}

View File

@@ -0,0 +1,52 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* Copyright (C) 2012-2013 Technische Universität Dresden.
* Copyright (C) 2016-2017, 2020, 2023-2024 Kernkonzept GmbH.
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/cxx/type_traits>
#include <stddef.h>
namespace cxx {
template< typename T >
class Static_container
{
private:
struct X : T
{
void *operator new (size_t, void *p) noexcept { return p; }
void operator delete (void *) {}
X() = default;
template<typename ...Args>
X(Args && ...a) : T(cxx::forward<Args>(a)...) {}
};
public:
void operator = (Static_container const &) = delete;
Static_container(Static_container const &) = delete;
Static_container() = default;
T *get() { return reinterpret_cast<X*>(_s); }
T *operator -> () { return get(); }
T &operator * () { return *get(); }
operator T* () { return get(); }
void construct()
{ new (reinterpret_cast<void*>(_s)) X; }
template< typename ...Args >
void construct(Args && ...args)
{ new (reinterpret_cast<void*>(_s)) X(cxx::forward<Args>(args)...); }
private:
char _s[sizeof(X)] __attribute__((aligned(__alignof(X))));
};
}

View File

@@ -0,0 +1,58 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
#pragma once
#include "type_traits"
namespace cxx {
/**
* Simple encapsulation for a dynamically allocated array.
*
* The main purpose of this class is to support C++11 range for
* for simple dynamically allocated array with static size.
*/
template<typename T, typename IDX = unsigned>
class static_vector
{
private:
template<typename X, typename IDX2> friend class static_vector;
T *_v;
IDX _l;
public:
typedef T value_type;
typedef IDX index_type;
static_vector() = default;
static_vector(value_type *v, index_type length) : _v(v), _l(length) {}
template<typename Z,
typename = enable_if_t<is_same<remove_extent_t<Z>, T>::value>>
constexpr static_vector(Z &v) : _v(v), _l(array_size(v))
{}
/// Conversion from compatible arrays
template<typename X,
typename = enable_if_t<is_convertible<X, T>::value>>
static_vector(static_vector<X, IDX> const &o) : _v(o._v), _l(o._l) {}
index_type size() const { return _l; }
bool empty() const { return _l == 0; }
value_type &operator [] (index_type idx) { return _v[idx]; }
value_type const &operator [] (index_type idx) const { return _v[idx]; }
value_type *begin() { return _v; }
value_type *end() { return _v + _l; }
value_type const *begin() const { return _v; }
value_type const *end() const { return _v + _l; }
value_type const *cbegin() const { return _v; }
value_type const *cend() const { return _v + _l; }
/// Get the index of the given element of the array
index_type index(value_type const *o) const { return o - _v; }
index_type index(value_type const &o) const { return &o - _v; }
};
}

View File

@@ -0,0 +1,74 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <stddef.h>
namespace cxx {
/**
* \ingroup cxx_api
* \brief Helper type to distinguish the <c> operator new </c> version
* that does not throw exceptions.
*/
class Nothrow {};
}
/**
* \ingroup cxx_api
* \brief Simple placement new operator.
* \param mem the address of the memory block to place the new object.
* \return the address given by \a mem.
*/
inline void *operator new (size_t, void *mem, cxx::Nothrow const &) noexcept
{ return mem; }
/**
* \ingroup cxx_api
* \brief New operator that does not throw exceptions.
*/
void *operator new (size_t, cxx::Nothrow const &) noexcept;
/**
* \ingroup cxx_api
* \brief Delete operator complementing the new operator not throwing
* exceptions.
*/
void operator delete (void *, cxx::Nothrow const &) noexcept;
namespace cxx {
/**
* \ingroup cxx_api
* \brief Standard allocator based on <c>operator new () </c>.
*
* This allocator is the default allocator used for the \em cxx
* \em Containers, such as cxx::Avl_set and cxx::Avl_map, to allocate
* the internal data structures.
*/
template< typename _Type >
class New_allocator
{
public:
enum { can_free = true };
New_allocator() noexcept {}
New_allocator(New_allocator const &) noexcept {}
~New_allocator() noexcept {}
_Type *alloc() noexcept
{ return static_cast<_Type*>(::operator new(sizeof (_Type), cxx::Nothrow())); }
void free(_Type *t) noexcept
{ ::operator delete(t, cxx::Nothrow()); }
};
}

View File

@@ -0,0 +1,25 @@
// vim:set ft=cpp: -*- Mode: C++ -*-
/*
* (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>,
* Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
namespace cxx {
/**
* \brief Generic comparator class that defaults to the less-than operator.
*/
template< typename Obj >
struct Lt_functor
{
bool operator () (Obj const &l, Obj const &r) const
{ return l < r; }
};
};

View File

@@ -0,0 +1,54 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
#pragma once
/*
* (c) 2012 Alexander Warg <warg@os.inf.tu-dresden.de>,
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#include "type_traits"
namespace cxx {
template< typename ...T >
struct type_list;
template<>
struct type_list<>
{
typedef false_type head;
typedef false_type tail;
};
template<typename HEAD, typename ...TAIL>
struct type_list<HEAD, TAIL...>
{
typedef HEAD head;
typedef type_list<TAIL...> tail;
};
template<typename TYPELIST, template <typename T> class PREDICATE>
struct find_type;
template<template <typename T> class PREDICATE>
struct find_type<type_list<>, PREDICATE>
{
typedef false_type type;
};
template<typename TYPELIST, template <typename T> class PREDICATE>
struct find_type
{
typedef typename conditional<PREDICATE<typename TYPELIST::head>::value,
typename TYPELIST::head,
typename find_type<typename TYPELIST::tail, PREDICATE>::type>::type type;
};
template<typename TYPELIST, template <typename T> class PREDICATE>
using find_type_t = typename find_type<TYPELIST, PREDICATE>::type;
}

View File

@@ -0,0 +1,378 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>,
* Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#pragma GCC system_header
#include <l4/sys/compiler.h>
#include "bits/type_traits.h"
namespace cxx {
template< typename T, T V >
struct integral_constant
{
static T const value = V;
typedef T value_type;
typedef integral_constant<T, V> type;
};
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;
template< typename T > struct remove_reference;
template< typename T > struct identity { typedef T type; };
template< typename T > using identity_t = typename identity<T>::type;
template< typename T1, typename T2 > struct is_same;
template< typename T > struct remove_const;
template< typename T > struct remove_volatile;
template< typename T > struct remove_cv;
template< typename T > struct remove_pointer;
template< typename T > struct remove_extent;
template< typename T > struct remove_all_extents;
template< typename, typename >
struct is_same : false_type {};
template< typename T >
struct is_same<T, T> : true_type {};
template< typename T1, typename T2 >
inline constexpr bool is_same_v = is_same<T1, T2>::value;
template< typename T >
struct remove_reference { typedef T type; };
template< typename T >
struct remove_reference<T &> { typedef T type; };
template< typename T >
struct remove_reference<T &&> { typedef T type; };
template< typename T >
using remove_reference_t = typename remove_reference<T>::type;
template< typename T > struct remove_const { typedef T type; };
template< typename T > struct remove_const<T const> { typedef T type; };
template< typename T > using remove_const_t = typename remove_const<T>::type;
template< typename T > struct remove_volatile { typedef T type; };
template< typename T > struct remove_volatile<T volatile> { typedef T type; };
template< typename T > using remove_volatile_t = typename remove_volatile<T>::type;
template< typename T >
struct remove_cv { typedef remove_const_t<remove_volatile_t<T>> type; };
template< typename T >
using remove_cv_t = typename remove_cv<T>::type;
template<class T>
struct remove_cvref { using type = remove_cv_t<remove_reference_t<T>>; };
template< typename T >
using remove_cvref_t = typename remove_cvref<T>::type;
template< typename T, typename >
struct __remove_pointer_h { typedef T type; };
template< typename T, typename I >
struct __remove_pointer_h<T, I*> { typedef I type; };
template< typename T >
struct remove_pointer : __remove_pointer_h<T, remove_cv_t<T>> {};
template< typename T >
using remove_pointer_t = typename remove_pointer<T>::type;
template< typename T >
struct remove_extent { typedef T type; };
template< typename T >
struct remove_extent<T[]> { typedef T type; };
template< typename T, unsigned long N >
struct remove_extent<T[N]> { typedef T type; };
template< typename T >
using remove_extent_t = typename remove_extent<T>::type;
template< typename T >
struct remove_all_extents { typedef T type; };
template< typename T >
struct remove_all_extents<T[]> { typedef typename remove_all_extents<T>::type type; };
template< typename T, unsigned long N >
struct remove_all_extents<T[N]> { typedef typename remove_all_extents<T>::type type; };
template< typename T >
using remove_all_extents_t = typename remove_all_extents<T>::type;
template< typename T >
constexpr T &&
forward(cxx::remove_reference_t<T> &t)
{ return static_cast<T &&>(t); }
template< typename T >
constexpr T &&
forward(cxx::remove_reference_t<T> &&t)
{ return static_cast<T &&>(t); }
template< typename T >
constexpr cxx::remove_reference_t<T> &&
move(T &&t) { return static_cast<cxx::remove_reference_t<T> &&>(t); }
template< bool, typename T = void >
struct enable_if {};
template< typename T >
struct enable_if<true, T> { typedef T type; };
template< bool C, typename T = void >
using enable_if_t = typename enable_if<C, T>::type;
template< typename T >
struct is_const : false_type {};
template< typename T >
struct is_const<T const> : true_type {};
template< typename T >
inline constexpr bool is_const_v = is_const<T>::value;
template< typename T >
struct is_volatile : false_type {};
template< typename T >
struct is_volatile<T volatile> : true_type {};
template< typename T >
inline constexpr bool is_volatile_v = is_volatile<T>::value;
template< typename T >
struct is_pointer : false_type {};
template< typename T >
struct is_pointer<T *> : true_type {};
template< typename T >
inline constexpr bool is_pointer_v = is_pointer<T>::value;
template<class T>
inline constexpr bool is_null_pointer_v = is_same_v<decltype(nullptr), remove_cv_t<T>>;
template< typename T >
struct is_reference : false_type {};
template< typename T >
struct is_reference<T &> : true_type {};
template< typename T >
struct is_reference<T &&> : true_type {};
template< typename T >
inline constexpr bool is_reference_v = is_reference<T>::value;
template< bool, typename, typename >
struct conditional;
template< bool C, typename T_TRUE, typename T_FALSE >
struct conditional { typedef T_TRUE type; };
template< typename T_TRUE, typename T_FALSE >
struct conditional< false, T_TRUE, T_FALSE > { typedef T_FALSE type; };
template< bool C, typename T_TRUE, typename T_FALSE >
using conditional_t = typename conditional<C, T_TRUE, T_FALSE>::type;
template<typename T>
struct is_enum : integral_constant<bool, __is_enum(T)> {};
template< typename T >
inline constexpr bool is_enum_v = is_enum<T>::value;
template<typename T>
struct is_polymorphic : cxx::integral_constant<bool, __is_polymorphic(T)> {};
template< typename T > struct is_integral : false_type {};
template<> struct is_integral<bool> : true_type {};
template<> struct is_integral<char> : true_type {};
template<> struct is_integral<signed char> : true_type {};
template<> struct is_integral<unsigned char> : true_type {};
template<> struct is_integral<short> : true_type {};
template<> struct is_integral<unsigned short> : true_type {};
template<> struct is_integral<int> : true_type {};
template<> struct is_integral<unsigned int> : true_type {};
template<> struct is_integral<long> : true_type {};
template<> struct is_integral<unsigned long> : true_type {};
template<> struct is_integral<long long> : true_type {};
template<> struct is_integral<unsigned long long> : true_type {};
template< typename T >
inline constexpr bool is_integral_v = is_integral<T>::value;
template< typename T, bool = is_integral_v<T> || is_enum_v<T> >
struct __is_signed_helper : integral_constant<bool, static_cast<bool>(T(-1) < T(0))> {};
template< typename T >
struct __is_signed_helper<T, false> : integral_constant<bool, false> {};
template< typename T >
struct is_signed : __is_signed_helper<T> {};
template< typename T >
inline constexpr bool is_signed_v = is_signed<T>::value;
template< typename >
struct is_array : false_type {};
template< typename T >
struct is_array<T[]> : true_type {};
template< typename T, unsigned long N >
struct is_array<T[N]> : true_type {};
template< typename T >
inline constexpr bool is_array_v = is_array<T>::value;
template< typename T, unsigned N >
constexpr unsigned array_size(T const (&)[N]) { return N; }
template< int SIZE, bool SIGN = false, bool = true > struct int_type_for_size;
template<> struct int_type_for_size<sizeof(char), true, true>
{ typedef signed char type; };
template<> struct int_type_for_size<sizeof(char), false, true>
{ typedef unsigned char type; };
template<> struct int_type_for_size<sizeof(short), true, (sizeof(short) > sizeof(char))>
{ typedef short type; };
template<> struct int_type_for_size<sizeof(short), false, (sizeof(short) > sizeof(char))>
{ typedef unsigned short type; };
template<> struct int_type_for_size<sizeof(int), true, (sizeof(int) > sizeof(short))>
{ typedef int type; };
template<> struct int_type_for_size<sizeof(int), false, (sizeof(int) > sizeof(short))>
{ typedef unsigned int type; };
template<> struct int_type_for_size<sizeof(long), true, (sizeof(long) > sizeof(int))>
{ typedef long type; };
template<> struct int_type_for_size<sizeof(long), false, (sizeof(long) > sizeof(int))>
{ typedef unsigned long type; };
template<> struct int_type_for_size<sizeof(long long), true, (sizeof(long long) > sizeof(long))>
{ typedef long long type; };
template<> struct int_type_for_size<sizeof(long long), false, (sizeof(long long) > sizeof(long))>
{ typedef unsigned long long type; };
template< int SIZE, bool SIGN = false>
using int_type_for_size_t = typename int_type_for_size<SIZE, SIGN>::type;
template< typename T, class Enable = void > struct underlying_type {};
template< typename T >
struct underlying_type<T, typename enable_if<is_enum_v<T>>::type >
{
typedef int_type_for_size_t<sizeof(T), is_signed_v<T>> type;
};
template< typename T >
using underlying_type_t = typename underlying_type<T>::type;
template< typename T > struct make_signed;
template<> struct make_signed<char> { typedef signed char type; };
template<> struct make_signed<unsigned char> { typedef signed char type; };
template<> struct make_signed<signed char> { typedef signed char type; };
template<> struct make_signed<unsigned int> { typedef signed int type; };
template<> struct make_signed<signed int> { typedef signed int type; };
template<> struct make_signed<unsigned long int> { typedef signed long int type; };
template<> struct make_signed<signed long int> { typedef signed long int type; };
template<> struct make_signed<unsigned long long int> { typedef signed long long int type; };
template<> struct make_signed<signed long long int> { typedef signed long long int type; };
template< typename T > using make_signed_t = typename make_signed<T>::type;
template< typename T > struct make_unsigned;
template<> struct make_unsigned<char> { typedef unsigned char type; };
template<> struct make_unsigned<unsigned char> { typedef unsigned char type; };
template<> struct make_unsigned<signed char> { typedef unsigned char type; };
template<> struct make_unsigned<unsigned int> { typedef unsigned int type; };
template<> struct make_unsigned<signed int> { typedef unsigned int type; };
template<> struct make_unsigned<unsigned long int> { typedef unsigned long int type; };
template<> struct make_unsigned<signed long int> { typedef unsigned long int type; };
template<> struct make_unsigned<unsigned long long int> { typedef unsigned long long int type; };
template<> struct make_unsigned<signed long long int> { typedef unsigned long long int type; };
template< typename T > using make_unsigned_t = typename make_unsigned<T>::type;
template<typename From, typename To>
struct is_convertible
{
private:
struct _true { char x[2]; };
struct _false {};
static _true _helper(To const *);
static _false _helper(...);
public:
enum
{
value = sizeof(_true) == sizeof(_helper(static_cast<From*>(0)))
? true : false
};
typedef bool value_type;
};
template<typename From, typename To>
inline constexpr bool is_convertible_v = is_convertible<From, To>::value;
template< typename T >
struct is_empty : integral_constant<bool, __is_empty(T)> {};
template< typename T >
inline constexpr bool is_empty_v = is_empty<T>::value;
#if L4_HAS_BUILTIN(__is_function)
template < typename T >
struct is_function : integral_constant<bool, __is_function(T)> {};
#else
template < typename T >
struct is_function : integral_constant<bool, !is_reference_v<T>
&& !is_const_v<const T>> {};
#endif
template< typename T >
inline constexpr bool is_function_v = is_function<T>::value;
}

View File

@@ -0,0 +1,127 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* Copyright (C) 2013 Technische Universität Dresden.
* Copyright (C) 2014-2017, 2020, 2023-2024 Kernkonzept GmbH.
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include "type_traits"
namespace cxx
{
template< typename T >
struct default_delete
{
default_delete() {}
template< typename U >
default_delete(default_delete<U> const &) {}
void operator () (T *p) const
{ delete p; }
};
template< typename T >
struct default_delete<T[]>
{
default_delete() {}
void operator () (T *p)
{ delete [] p; }
};
template< typename T, typename C >
struct unique_ptr_index_op {};
template< typename T, typename C >
struct unique_ptr_index_op<T[], C>
{
typedef T &reference;
reference operator [] (int idx) const
{ return static_cast<C const *>(this)->get()[idx]; }
};
template< typename T, typename T_Del = default_delete<T> >
class unique_ptr : public unique_ptr_index_op<T, unique_ptr<T, T_Del> >
{
private:
struct _unspec;
typedef _unspec* _unspec_ptr_type;
public:
typedef cxx::remove_extent_t<T> element_type;
typedef element_type *pointer;
typedef element_type &reference;
typedef T_Del deleter_type;
unique_ptr() : _ptr(pointer()) {}
explicit unique_ptr(pointer p) : _ptr(p) {}
unique_ptr(unique_ptr &&o) : _ptr(o.release()) {}
~unique_ptr() { reset(); }
unique_ptr &operator = (unique_ptr &&o)
{
reset(o.release());
return *this;
}
unique_ptr &operator = (_unspec_ptr_type)
{
reset();
return *this;
}
element_type &operator * () const { return *get(); }
pointer operator -> () const { return get(); }
pointer get() const { return _ptr; }
operator _unspec_ptr_type () const
{ return reinterpret_cast<_unspec_ptr_type>(get()); }
pointer release()
{
pointer r = _ptr;
_ptr = 0;
return r;
}
void reset(pointer p = pointer())
{
if (p != get())
{
deleter_type()(get());
_ptr = p;
}
}
unique_ptr(unique_ptr const &) = delete;
unique_ptr &operator = (unique_ptr const &) = delete;
private:
pointer _ptr;
};
template< typename T >
unique_ptr<T>
make_unique_ptr(T *p)
{ return unique_ptr<T>(p); }
template< typename T >
cxx::enable_if_t<cxx::is_array<T>::value, unique_ptr<T>>
make_unique(unsigned long size)
{ return cxx::unique_ptr<T>(new cxx::remove_extent_t<T>[size]()); }
template< typename T, typename... Args >
cxx::enable_if_t<!cxx::is_array<T>::value, unique_ptr<T>>
make_unique(Args &&... args)
{ return cxx::unique_ptr<T>(new T(cxx::forward<Args>(args)...)); }
}

View File

@@ -0,0 +1,30 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/**
* \file
* Implementation of a list of unique-ptr-managed objects.
*/
/*
* Copyright (C) 2018-2019, 2022, 2024 Kernkonzept GmbH.
* Author(s): Sarah Hoffmann <sarah.hoffmann@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/cxx/unique_ptr>
#include "bits/smart_ptr_list.h"
namespace cxx {
/// Item for list linked with cxx::unique_ptr.
template <typename T>
using Unique_ptr_list_item = Bits::Smart_ptr_list_item<T, cxx::unique_ptr<T> >;
/**
* Single-linked list where elements are connected with a cxx::unique_ptr.
*/
template <typename T>
using Unique_ptr_list = Bits::Smart_ptr_list<Unique_ptr_list_item<T> >;
}

View File

@@ -0,0 +1,80 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* Copyright (C) 2013 Technische Universität Dresden.
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
namespace cxx {
/**
* Read the value at an address at most once.
*
* The read might be omitted if the result is not used by any code unless
* `typename` contains `volatile`. If the read operation has side effects and
* must not be omitted, use different means like L4drivers::Mmio_register_block
* or similar.
*
* The compiler is disallowed to reuse a previous read at the same address, for
* example:
* ```
* val1 = *a;
* val2 = access_once(a); // compiler may not replace this by val2 = val1;
* ```
*
* The compiler is also disallowed to repeat the read, for example:
* ```
* val1 = access_once(a);
* val2 = val1; // compiler may not replace this by val2 = *a;
* ```
*
* The above implies that the compiler is also disallowed to move the read out
* of or into loops.
*
* \note The read might still be moved relative to other code.
* \note The value might be read from a hardware cache, not from RAM.
*/
template< typename T > inline
T access_once(T const *a)
{
#if 1
__asm__ __volatile__ ( "" : "=m"(*const_cast<T*>(a)));
T tmp = *a;
__asm__ __volatile__ ( "" : "=m"(*const_cast<T*>(a)));
return tmp;
#else
return *static_cast<T const volatile *>(a);
#endif
}
/**
* Write a value at an address exactly once.
*
* The compiler is disallowed to skip the write, for example:
* ```
* *a = val;
* write_now(a, val); // compiler may not skip this line
* ```
*
* The compiler is also disallowed to repeat the write.
*
* The above implies that the compiler is also disallowed to move the write out
* of or into loops.
*
* \note The write might still be moved relative to other code.
* \note The value might be written just to a hardware cache for the moment, not
* immediately to RAM.
*/
template< typename T, typename VAL > inline
void write_now(T *a, VAL &&val)
{
__asm__ __volatile__ ( "" : "=m"(*a));
*a = val;
__asm__ __volatile__ ( "" : : "m"(*a));
}
}

View File

@@ -0,0 +1,157 @@
// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* Copyright (C) 2015, 2017, 2024 Kernkonzept GmbH.
* Author(s): Sarah Hoffmann <sarah.hoffmann@kernkonzept.com>
* Alexander Warg <alexander.warg@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include "hlist"
namespace cxx {
/**
* Generic (base) weak reference to some object.
*
* A weak reference is a reference that gets reset to NULL when the object
* shall be deleted. All weak references to the same object are kept in a
* linked list of weak references.
*
* For typed weak references see `cxx::Weak_ref`.
*/
class Weak_ref_base : public H_list_item_t<Weak_ref_base>
{
protected:
Weak_ref_base(void const *ptr = nullptr) : _obj(ptr) {}
void reset_hard() { _obj = nullptr; }
void const *_obj;
public:
/**
* The list type for keeping all weak references to an object.
*
* On destruction of a list, all weak references to the respective object are
* set to `nullptr`.
*/
struct List : H_list_t<Weak_ref_base>
{
void reset()
{
while (!empty())
pop_front()->reset_hard();
}
~List()
{ reset(); }
};
explicit operator bool () const
{ return _obj ? true : false; }
};
/**
* Typed weak reference to an object of type `T`.
*
* \tparam T The type of the referenced object.
*
* A weak reference is a reference that is invalidated when the referenced
* object is about to be deleted. All weak references to an object are kept in
* a linked list (see Weak_ref_base::List) and all the weak references are
* iterated and reset by the Weak_ref_base::List destructor or
* Weak_ref_base::List::reset().
*
* The type `T` must provide two methods that handle the housekeeping of weak
* references: `remove_weak_ref(Weak_ref_base *)` and
* `add_weak_ref(Weak_ref_base *)`. These functions must handle the insertion
* and removal of the weak reference into the respective Weak_ref_base::List
* object. For convenience one can use the cxx::Weak_ref_obj as a base class
* that handles weak references for you.
*
* For example:
* ```{.cpp}
* class C : public cxx::Weak_ref_obj {};
*
* int main()
* {
* cxx::Weak_ref<C> r; // r is nullptr
* {
* C c;
* r = &c; // now r points to c
* } // c is destructed, which implies resetting all weak references to c
* // now r is nullptr
* return 0;
* }
* ```
*
* \note Weak references have no effect on the lifetime of the referenced
* object. Hence, a referenced object is *not* deleted when all weak
* references for it are gone. If automatic deletion is needed, see
* cxx::Ref_ptr.
*/
template <typename T>
class Weak_ref : public Weak_ref_base
{
public:
T *get() const
{ return reinterpret_cast<T*>(const_cast<void *>(_obj)); }
T *reset(T *n)
{
T *r = get();
if (r)
r->remove_weak_ref(this);
_obj = n;
if (n)
n->add_weak_ref(this);
return r;
}
Weak_ref(T *s = nullptr) : Weak_ref_base(s)
{
if (s)
s->add_weak_ref(this);
}
~Weak_ref() { reset(0); }
void operator = (T *n)
{ reset(n); }
Weak_ref(Weak_ref const &o) : Weak_ref_base(o._obj)
{
if (T *x = get())
x->add_weak_ref(this);
}
Weak_ref &operator = (Weak_ref const &o)
{
if (&o == this)
return *this;
reset(o.get());
return *this;
}
T &operator * () const { return get(); }
T *operator -> () const { return get(); }
};
class Weak_ref_obj
{
protected:
template <typename T> friend class Weak_ref;
mutable Weak_ref_base::List weak_references;
void add_weak_ref(Weak_ref_base *ref) const
{ weak_references.push_front(ref); }
void remove_weak_ref(Weak_ref_base *ref) const
{ weak_references.remove(ref); }
};
}

View File

@@ -0,0 +1,8 @@
PKGDIR = ../..
L4DIR ?= $(PKGDIR)/../../..
TARGET := include src
include $(L4DIR)/mk/subdir.mk
src: include

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