merge
This commit is contained in:
1
.hgtags
1
.hgtags
@@ -1 +1,2 @@
|
||||
56928998e05c9c11f5f3aefe79be8d2843e0db88 release ns-3.0.1
|
||||
7ac5a4b0969b255c4824c926c2b37ef450136ce9 release ns-3.0.2
|
||||
|
||||
35
INSTALL
35
INSTALL
@@ -1,35 +0,0 @@
|
||||
ns-3.0.1 snapshot release, March 2007
|
||||
|
||||
1. Tested platforms:
|
||||
|
||||
- Windows XP 32-bit Cygwin
|
||||
|
||||
- Linux Fedora Core 5 x86
|
||||
|
||||
- OS X 10.4.7 or later with XCode 2.4 or later
|
||||
|
||||
2. Prerequisites:
|
||||
|
||||
- The SCons build system (http://www.scons.org) version 0.96.1 or later
|
||||
|
||||
- gcc (version 3.4 or later)
|
||||
|
||||
3. Installing into your current directory:
|
||||
|
||||
tar xvfz ns-3.0.1.tar.gz
|
||||
cd ns-3.0.1
|
||||
scons
|
||||
cd build-dir/dbg-shared/bin/
|
||||
./simple-p2p
|
||||
|
||||
The above steps will run a simple program whose source is found in
|
||||
ns-3.0.1/examples/simple-p2p.cc
|
||||
Some minimal trace output is found in simple-p2p.tr.
|
||||
|
||||
Note: OS X users may need to set the following env. variable from
|
||||
the bin/ directory above:
|
||||
setenv DYLD_LIBRARY_PATH `pwd`/../lib
|
||||
|
||||
4. For more information, read
|
||||
ns-3.0.1-documentation.pdf
|
||||
|
||||
52
README
52
README
@@ -1,9 +1,9 @@
|
||||
|
||||
The Network Simulator Version 3
|
||||
-------------------------------
|
||||
The Network Simulator, Version 3
|
||||
--------------------------------
|
||||
|
||||
Table of Content:
|
||||
-----------------
|
||||
Table of Contents:
|
||||
------------------
|
||||
|
||||
1) An Open Source project
|
||||
2) An overview of the ns-3 project
|
||||
@@ -16,7 +16,7 @@ Table of Content:
|
||||
1) An Open Source project
|
||||
-------------------------
|
||||
|
||||
ns-3 is an Open Source project and we intend to make this
|
||||
ns-3 is an Open Source project. We intend to make this
|
||||
project a successful collaborative project: we hope that
|
||||
the missing pieces of the models we have not yet implemented
|
||||
will be contributed by the community in an open collaboration
|
||||
@@ -25,11 +25,11 @@ process.
|
||||
Contributing to the ns-3 project is still a very informal
|
||||
process because that process depends heavily on the personality
|
||||
of the people involved, the amount of time they can invest
|
||||
and the type of model they want to work on.
|
||||
and the type of model they want to work on.
|
||||
|
||||
Despite this lack of a formal process, there are a number of
|
||||
steps which naturally stem from the open-source roots of the
|
||||
project. These steps are described in doc/contributing.txt
|
||||
project. These steps are described in doc/contributing.txt
|
||||
|
||||
2) An overview of the ns-3 project
|
||||
----------------------------------
|
||||
@@ -42,8 +42,9 @@ number of very simple network simulation models:
|
||||
- point-to-point physical-layer links
|
||||
- OnOff traffic generator
|
||||
|
||||
However, the framework is there to make adding new models as
|
||||
simple as possible:
|
||||
Our focus to date has been on getting an overall software
|
||||
framework in place. The framework is there to make adding
|
||||
new models as simple as possible:
|
||||
- an extensive tracing system can be used to connect
|
||||
any number of arbitrary trace sources to any number
|
||||
of trace sinks. This tracing system is decoupled
|
||||
@@ -65,7 +66,7 @@ simple as possible:
|
||||
|
||||
The code for the framework and the default models provided
|
||||
by ns-3 is built as a set of libraries. User simulations
|
||||
are expected to be written as simple programs which make
|
||||
are expected to be written as simple programs that make
|
||||
use of these ns-3 libraries.
|
||||
|
||||
To build the set of default libraries and the example
|
||||
@@ -84,7 +85,8 @@ found in the 'examples' directory.
|
||||
|
||||
The current codebase is expected to build and run on the
|
||||
following set of platforms:
|
||||
- linux x86 gcc 4.1, gcc 3.4.
|
||||
- linux x86 gcc 4.2, 4.1, and, 3.4.
|
||||
- linux x86_64 gcc 4.0
|
||||
- MacOS X ppc and x86
|
||||
|
||||
The current codebase is expected to fail to build on
|
||||
@@ -92,14 +94,14 @@ the following platforms:
|
||||
- gcc 3.3 and earlier
|
||||
- optimized builds on linux x86 gcc 4.0
|
||||
|
||||
Other platforms might or might not work: we welcome
|
||||
Other platforms may or may not work: we welcome
|
||||
patches to improve the portability of the code to these
|
||||
other platforms.
|
||||
|
||||
4) Running ns-3
|
||||
---------------
|
||||
|
||||
On Recent Linux systems, once you have built ns-3, it
|
||||
On recent Linux systems, once you have built ns-3, it
|
||||
should be easy to run the sample programs with the
|
||||
following command:
|
||||
|
||||
@@ -112,7 +114,7 @@ cd build-dir/dbg-shared/bin
|
||||
|
||||
That program should generate a simple-p2p.tr text
|
||||
trace file and a set of simple-p2p-xx-xx.pcap binary
|
||||
pcap trace files.
|
||||
pcap trace files, which can be read by tcpdump.
|
||||
|
||||
5) Getting access to the ns-3 documentation
|
||||
-------------------------------------------
|
||||
@@ -123,18 +125,17 @@ quite likely that you will want to get started on reading
|
||||
some ns-3 documentation.
|
||||
|
||||
All of that documentation should always be available from
|
||||
the ns-3 website: http:://www.nsnam.org/
|
||||
the ns-3 website: http:://www.nsnam.org/ but we
|
||||
include some of it in this release for ease of use.
|
||||
|
||||
It includes:
|
||||
This documentation includes:
|
||||
|
||||
- an architecture document which describes a very
|
||||
high-level view of ns-3: it tries to explain the
|
||||
use-cases the ns-3 developers really focused on when
|
||||
doing the initial design and then goes on to explain
|
||||
the structure of the resulting framework.
|
||||
XXX introduce url link
|
||||
|
||||
- a user manual: XXX
|
||||
See the file doc/architecture.pdf
|
||||
|
||||
- a wiki for user-contributed tips: http://www.nsnam.org/wiki/
|
||||
|
||||
@@ -143,6 +144,17 @@ It includes:
|
||||
as introductory text:
|
||||
http://www.nsnam.org/doxygen/index.html
|
||||
|
||||
If you want to re-generate this documentation, you can
|
||||
easily do so:
|
||||
|
||||
- doc/architecture.pdf is generated from the architecture.tex
|
||||
file in http://code.nsnam.org/docs
|
||||
|
||||
- the doxygen documentation is generated from the doc/doxygen.conf
|
||||
configuration file. The command "scons doc" will generate it
|
||||
as doc/html/index.html if you have installed the doxygen tools
|
||||
(see http://www.doxygen.org)
|
||||
|
||||
6) Working with the development version of ns-3
|
||||
-----------------------------------------------
|
||||
|
||||
@@ -156,4 +168,4 @@ familiar with it.
|
||||
If you have successfully installed mercurial, you can get
|
||||
a copy of the development version with the following
|
||||
command:
|
||||
"hg clone http://code.nsnam.org/ns-3-dev"
|
||||
"hg clone http://code.nsnam.org/ns-3-dev"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
|
||||
ns-3 RELEASE NOTES
|
||||
|
||||
This file contains ns-3 release notes (most recent releases first).
|
||||
This file contains ns-3 release notes (most recent releases first).
|
||||
|
||||
Release 0.2 (2007/05/XX)
|
||||
Release 3.0.2 (2007/05/18)
|
||||
========================
|
||||
|
||||
- Implement a new memory management infrastructure based
|
||||
@@ -15,7 +15,7 @@ Release 0.2 (2007/05/XX)
|
||||
|
||||
- Add support for a BSD-style socket API for user applications
|
||||
|
||||
Release 0.1 (2007/03/31)
|
||||
Release 3.0.1 (2007/03/31)
|
||||
========================
|
||||
|
||||
- First public release; not yet pre-alpha.
|
||||
|
||||
16
SConstruct
16
SConstruct
@@ -2,19 +2,27 @@
|
||||
import os.path
|
||||
import build
|
||||
|
||||
version_file = open ('VERSION', 'r')
|
||||
version = version_file.readline ()
|
||||
version_file.close ()
|
||||
version = version.strip ()
|
||||
|
||||
ns3 = build.Ns3()
|
||||
ns3.build_dir = 'build-dir'
|
||||
ns3.version = '0.2'
|
||||
ns3.version = version
|
||||
ns3.name = 'ns3'
|
||||
ns3.distname = 'ns-3'
|
||||
ns3.distname = 'ns'
|
||||
ns3.doxygen_config = os.path.join('doc', 'doxygen.conf')
|
||||
ns3.add_extra_dist(os.path.join('doc', 'main.txt'))
|
||||
ns3.add_extra_dist ('doc/architecture.pdf')
|
||||
ns3.add_extra_dist ('doc/contributing.txt')
|
||||
ns3.add_extra_dist ('doc/build.txt')
|
||||
ns3.add_extra_dist ('doc/codingstd.txt')
|
||||
ns3.add_extra_dist ('doc/mercurial.txt')
|
||||
ns3.add_extra_dist ('README')
|
||||
ns3.add_extra_dist ('RELEASE_NOTES')
|
||||
ns3.add_extra_dist ('AUTHORS')
|
||||
ns3.add_extra_dist ('VERSION')
|
||||
|
||||
|
||||
#
|
||||
@@ -23,7 +31,6 @@ ns3.add_extra_dist ('AUTHORS')
|
||||
core = build.Ns3Module('core', 'src/core')
|
||||
ns3.add(core)
|
||||
core.add_sources([
|
||||
'reference-list-test.cc',
|
||||
'callback-test.cc',
|
||||
'debug.cc',
|
||||
'assert.cc',
|
||||
@@ -56,7 +63,6 @@ core.add_headers ([
|
||||
])
|
||||
core.add_inst_headers([
|
||||
'system-wall-clock-ms.h',
|
||||
'reference-list.h',
|
||||
'callback.h',
|
||||
'ptr.h',
|
||||
'object.h',
|
||||
@@ -196,8 +202,6 @@ common.add_inst_headers([
|
||||
'array-trace-resolver.h',
|
||||
'trace-root.h',
|
||||
'terminal-trace-resolver.h',
|
||||
'smartvector.h',
|
||||
'smartset.h',
|
||||
'data-rate.h',
|
||||
])
|
||||
|
||||
|
||||
2
build.py
2
build.py
@@ -504,7 +504,7 @@ class Ns3:
|
||||
|
||||
# dist support
|
||||
dist_env = env.Copy()
|
||||
if dist_env['PLATFORM'] == 'posix':
|
||||
if dist_env['PLATFORM'] == 'posix' or dist_env['PLATFORM'] == 'darwin':
|
||||
dist_list = []
|
||||
for module in self.__modules:
|
||||
for f in module.sources:
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
WAF is an alternative build system, similar to SCons. NS-3 now is
|
||||
able to build with WAF, in parallel to SCons.
|
||||
The main ns-3 build system is SCons. Read the file build.txt
|
||||
for SCons instructions.
|
||||
|
||||
Note: the WAF build scripts are experimental at this stage.
|
||||
Waf is an alternative build system, similar to SCons. ns-3 now is
|
||||
able to build with Waf, in parallel to SCons.
|
||||
|
||||
(http://www.freehackers.org/~tnagy/waf.html)
|
||||
|
||||
=== Building with WAF ===
|
||||
Note: the Waf build scripts are experimental at this stage.
|
||||
Gustavo Carneiro (gjcarneiro@gmail.com) is the maintainer.
|
||||
|
||||
To build NS-3 with waf type the commands:
|
||||
=== Building with Waf ===
|
||||
|
||||
To build ns-3 with waf type the commands:
|
||||
1. ./waf configure [options]
|
||||
2. ./waf
|
||||
|
||||
@@ -30,7 +35,18 @@ Other waf usages include:
|
||||
Run code coverage analysis (assuming the project was configured
|
||||
with --enable-gcov)
|
||||
|
||||
=== Extending NS-3 ===
|
||||
4. ./waf --run "program [args]"
|
||||
Run a ns3 program, given its target name, with the given
|
||||
arguments. This takes care of automatically modifying the the
|
||||
path for finding the ns3 dynamic libraries in the environment
|
||||
before running the program. Note: the "program [args]" string is
|
||||
parsed using POSIX shell rules.
|
||||
|
||||
5. ./waf --shell
|
||||
Starts a nested system shell with modified environment to run ns3 programs.
|
||||
|
||||
|
||||
=== Extending ns-3 ===
|
||||
|
||||
To add new modules:
|
||||
1. Create the module directory under src (or src/devices, or whatever);
|
||||
@@ -38,7 +54,7 @@ To add new modules:
|
||||
3. Add a 'wscript' describing it;
|
||||
4. Add the module subdirectory name to the all_modules list in src/wscript.
|
||||
|
||||
A module's wscript file is basically a regular WAF script. A NS-3
|
||||
A module's wscript file is basically a regular Waf script. A ns-3
|
||||
module is created as a cpp/shlib object, like this:
|
||||
|
||||
def build(bld):
|
||||
@@ -65,7 +81,7 @@ def build(bld):
|
||||
|
||||
=== Note for developers ===
|
||||
|
||||
The NS-3 code repository does not contain the waf script. Instead,
|
||||
The ns-3 code repository does not contain the waf script. Instead,
|
||||
developers should check it out from a subversion repository:
|
||||
|
||||
svn checkout http://waf.googlecode.com/svn/tags/ns3/ waf
|
||||
@@ -77,8 +93,8 @@ tested to work correctly with ns3, although 'trunk' will likely work
|
||||
Then it can be installed system-wide with 'sudo ./waf-light install'.
|
||||
When preparing a distribution, the resulting 'waf' script, which is
|
||||
self contained (no external files needed), can be easily included in
|
||||
the tarball so that users downloading NS-3 can easily build it without
|
||||
having WAF installed (although Python >= 2.3 is still needed).
|
||||
the tarball so that users downloading ns-3 can easily build it without
|
||||
having Waf installed (although Python >= 2.3 is still needed).
|
||||
|
||||
The command 'waf dist' can be used to create a distribution tarball.
|
||||
It includes all files in the source directory, except some particular
|
||||
|
||||
@@ -16,6 +16,10 @@ the executable binaries generated link explicitely against
|
||||
the right libraries. This saves you the pain of having to
|
||||
setup environment variables to point to the right libraries.
|
||||
|
||||
(Note: An alternative build system (Waf) is being
|
||||
evaluated in the development branch of ns-3-dev on our server
|
||||
only (i.e., not in the release tarballs)-- see doc/build-waf.txt)
|
||||
|
||||
1) Options
|
||||
----------
|
||||
|
||||
|
||||
@@ -1,592 +0,0 @@
|
||||
\documentclass[11pt]{article}
|
||||
\usepackage{times}
|
||||
\setlength{\textwidth}{6.5in}
|
||||
\setlength{\textheight}{9in}
|
||||
\setlength{\oddsidemargin}{0.0in}
|
||||
\setlength{\evensidemargin}{0.0in}
|
||||
\setlength{\topmargin}{-0.5in}
|
||||
\def\nst{{\em ns--3}}
|
||||
\newcommand{\code}[1]{\texttt{#1}}
|
||||
|
||||
\begin{document}
|
||||
\begin{center}
|
||||
{\Large Coding Standard for ns--3}\\
|
||||
August 22, 2005
|
||||
|
||||
\end{center}
|
||||
\section{Introduction}
|
||||
|
||||
The purpose of the \nst\ project is to build software which will last
|
||||
many years: making sure that the code is readable and stays so is
|
||||
one of the most important items required to achieve this goal. This
|
||||
document thus outlines guidelines we plan to enforce on each component
|
||||
integrated in \nst to ensure uniformity of the codebase which is
|
||||
a first step towards readable code.
|
||||
|
||||
\section{Recommendations}
|
||||
|
||||
The following recommendations are not strict rules and some of them
|
||||
are conflicting but the point here is to outline the fact that we
|
||||
value more common-sense than strict adherence to the coding style
|
||||
defined in this document.
|
||||
|
||||
\subsection{naming}
|
||||
|
||||
Types, methods, functions and variable names should be self-descriptive.
|
||||
Avoid using acronyms, expand them, do not hesitate to use long names,
|
||||
Avoid shortcuts such as \code{sz} for \code{size}. Long names sometimes get in the
|
||||
way of being able to read the code:
|
||||
\begin{verbatim}
|
||||
for (int loopCount = 0; loopCount < max; loopCount++)
|
||||
{
|
||||
// code
|
||||
}
|
||||
\end{verbatim}
|
||||
loopCount should be renamed to something shorter such as
|
||||
\code{i}, \code{j}, \code{k}, \code{l}, \code{m}, and \code{n}
|
||||
which are widely used names which identify loop counters:
|
||||
\begin{verbatim}
|
||||
for (int i = 0; i < max; i++)
|
||||
{
|
||||
// code
|
||||
}
|
||||
\end{verbatim}
|
||||
Similarly, \code{tmp} is a common way to denote temporary variables. On
|
||||
the other hand, \code{foo} is not an appropriate name: it says nothing
|
||||
about the purpose of the variable.
|
||||
|
||||
If you use predicates (that is, functions, variables or methods
|
||||
which return a single boolean value), prefix the
|
||||
name with \code{is} or \code{has}.
|
||||
|
||||
\subsection{Memory management}
|
||||
|
||||
As much as possible, try to pass around objects
|
||||
by value and allocate them on the stack. If you need to allocate
|
||||
objects on the heap with new, make sure that the corresponding
|
||||
call to delete happens where the new took place. i.e., avoid
|
||||
passing around pointer ownership.
|
||||
Avoid the use of reference counting and, more generaly, strive to
|
||||
keep the memory-management model simple.
|
||||
|
||||
\subsection{Templates}
|
||||
|
||||
For now, templates are defined only in the simulator
|
||||
core and are used everywhere else. Try to keep it that way by
|
||||
avoiding defining new templates in model-specific code.
|
||||
|
||||
|
||||
\section{Standards}
|
||||
\subsection{General}
|
||||
\begin{enumerate}
|
||||
\item There will be no {\em tab} characters in the code. Rather, repeated
|
||||
spaces are used to separate the characters as needed.
|
||||
\item No line of code will be longer than 80 characters in length, to
|
||||
prevent lines wrapping in the {\tt emacs} or {\tt vi} editors. For both
|
||||
of these linux text editing tools, the default is a window that is
|
||||
exactly 80 characters wide, so if none of the lines wrap when editing
|
||||
in {\tt emacs} or {\tt vi} this requirement is met.
|
||||
|
||||
\item Each C++ statement will be on a separate line. The only exception
|
||||
is when an {\tt if}, {\tt else}, {\tt for} or {\tt while}
|
||||
statement has a single
|
||||
statement sub--block these can be on the same line.
|
||||
|
||||
Examples:
|
||||
|
||||
\begin{tt}
|
||||
int i = 0; // Right\\
|
||||
i = 10; j = 20; // Wrong. Two statements same line\\
|
||||
Sub1(k); Sub2(k); // Wrong. Two statements same line\\
|
||||
if (done) break; // Right. If statement with single statement sub-block
|
||||
\end{tt}
|
||||
|
||||
\item Each variable declaration will be on a separate line.
|
||||
|
||||
Examples:
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
int c, d; \=// Wrong. c and d defined on same line.\\
|
||||
int a = 0; \\
|
||||
int b = 0; \>// Right. a and b on different lines\\
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\item Variables should be declared at the point in the code
|
||||
where they are needed, and should be assigned an initial value
|
||||
at the time of declaration.
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
int a = 0; \=// Right, a is assigned in initial value.\\
|
||||
int b; \> Wrong, b is not assigned an initial value.\\
|
||||
int c = 0; \\
|
||||
int d = Sub1(a, b);\\
|
||||
c = Sub2(d); \> // Wrong, c should be declared here, not above
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\item Excepting when used in a {\tt switch} statement, the open
|
||||
and close curly braces (\{ and \}) are always on a separate line.
|
||||
|
||||
Examples:
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
aa\=aa\=aa\= \kill
|
||||
for (int i = 0; i < MAX\_COUNT; ++i) \\
|
||||
\>\{ // Right. Open brace on separate line \\
|
||||
\>\>sum += i; \\
|
||||
\>\>prod *= i; \\
|
||||
\>\} // Right. Close brace on separate line
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
aa\=aa\=aa\= \kill
|
||||
for (int i = 0; i < 10; ++i) \{ // Wrong. Open brace on same line\\
|
||||
\>sum += i; \\
|
||||
\>prod *= i; \} // Wrong. Close brace on same line
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\item The C++ {\tt goto} statement is not to be used.
|
||||
\end{enumerate}
|
||||
\subsection{Commenting}
|
||||
In general, comments should be use liberally throughout the program to
|
||||
increase readability. Specifically:
|
||||
|
||||
\begin{enumerate}
|
||||
\item C++ style comments using the {\tt //} delimeter
|
||||
are to be used, rather than C style comments with the {\tt /*}
|
||||
and {\tt */} delimieters.
|
||||
|
||||
\item Variable declaration should have a short, one or two line comment
|
||||
describing the purpose of the variable, unless it is a
|
||||
local variable whose use is obvious from the context. The short
|
||||
comment should be on the same line as the variable declaration, unless it
|
||||
is too long, in which case it should be on the preceding lines.
|
||||
|
||||
Example:
|
||||
|
||||
\begin{tt}
|
||||
int averageGrade; // Computed average grade for this project \\
|
||||
// Note. The above comment likely qualifies as \\
|
||||
// obvious from context, and could be omitted.
|
||||
\\
|
||||
// Counts the total number of students completing the project, but\\
|
||||
// does not include those not turning in the project. \\
|
||||
int projectCount = 0;
|
||||
\end{tt}
|
||||
\item Every function should be preceded by a detailed comment block
|
||||
describing what the function does, what the formal parameters are, and
|
||||
what the return value is (if any).
|
||||
|
||||
\item Every class declaration should be preceded by a comment block
|
||||
describing what the class is to be used for.
|
||||
|
||||
\item Unless obvious from context, each {\tt if} statement should
|
||||
include a one--line comment on the open curly brace following describing
|
||||
the {\tt TRUE} condition and the {\tt FALSE} condition.
|
||||
|
||||
Example:
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
aa\=aa\=aa\= \kill
|
||||
if (iter == students.end()) \\
|
||||
\>\{ // Student not found, add him \\
|
||||
\>\>students.push\_back(thisStudent); \\
|
||||
\>\} \\
|
||||
else \\
|
||||
\>\{ // Student exists, modify existing data \\
|
||||
\>\>iter->grade += thisGrade; \\
|
||||
\>\}
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
\item Class and function comments should adhere to the Doxygen standard
|
||||
format, for automated extraction by the Doxygen tool. {\em Note from
|
||||
GFR. We need a bit more here, as Doxygen has several possible methods
|
||||
for commenting. I'll look them over and suggest an approach, for later
|
||||
discussion}
|
||||
|
||||
\end{enumerate}
|
||||
\subsection{Naming Conventions}
|
||||
\begin{enumerate}
|
||||
\item {\bf Variable Names}. All variables, including global variables,
|
||||
local variables, formal parameters,
|
||||
and member variables in classes will start with a
|
||||
lower case letter, and consist of only alphabetic characters and numeric
|
||||
digits. Capital letters are to be used when appropriate between words
|
||||
in a variable name for increased readability.
|
||||
Variable names should not contain the underscore character.
|
||||
|
||||
Examples:
|
||||
|
||||
{\tt int i;}\\
|
||||
{\tt int nextIndexValue;}\\
|
||||
{\tt int sum1;}\\
|
||||
{\tt int loopCount10;}
|
||||
|
||||
\item {\bf Class Member and Global Variables}. To be able to distinguish
|
||||
local variables from class member and global variables, prepend the
|
||||
\code{m\_} prefix to class member variables and the \code{g\_} prefix
|
||||
to global variables.
|
||||
|
||||
Examples:
|
||||
\begin{verbatim}
|
||||
class Foo {
|
||||
private:
|
||||
int m_myPrivateVar;
|
||||
};
|
||||
static int g_myGlobalVar;
|
||||
\end{verbatim}
|
||||
|
||||
\item {\bf Subroutine Names}. All subroutine names, including global
|
||||
routines and member functions in classes, will start with an upper case
|
||||
letter, and consist of only alphabetic characters and numeric digits
|
||||
(although digits should be rarely needed).
|
||||
As in variable names, upper case letters are to be used between words as needed
|
||||
to increase readability.
|
||||
|
||||
Examples:
|
||||
|
||||
{\tt int ComputeNextIterator()}\\
|
||||
{\tt int Calculate()}\\
|
||||
{\tt int TransmitPacket()}\\
|
||||
{\tt int Dummy()}
|
||||
|
||||
\item {\bf Defined Constants}. All defined constants will be all upper
|
||||
case letters or numeric digits, with the underscore character separating
|
||||
words.
|
||||
|
||||
Examples:
|
||||
|
||||
{\tt typedef enum \{ PACKET\_RX, PACKET\_FIRST\_BIT\_RX, PACKET\_TX\} }\\
|
||||
{\tt \#define NUMBER\_ELEMENTS 10}\\
|
||||
{\tt const int LOOP\_COUNT = 100}
|
||||
|
||||
\item {\bf Defined Types}. All user defined types will end start with
|
||||
an upper case letter, consist of upper and lower case letters only, and
|
||||
end in {\tt \_t}.
|
||||
|
||||
Examples:
|
||||
|
||||
{\tt typedef double Time\_t; // Simulation time}\\
|
||||
{\tt typedef unsigned long SimulatorUid\_t; // Unique ID for each event}\\
|
||||
{\tt typedef unsigned long Event\_t; // Idenifies events in handler}\\
|
||||
|
||||
\item {\bf Class Names}. Class names will start with an upper case letter,
|
||||
consist of only alphabetic characters, and include capital letters as
|
||||
needed to increase readability.
|
||||
|
||||
Examples:
|
||||
|
||||
{\tt class DropTailQueue \{}\\
|
||||
{\tt class Ferrari \{}\\
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
%\newpage % Adjust as needed
|
||||
\subsection{Statement Formatting}
|
||||
\begin{enumerate}
|
||||
\item {\bf Indention}. The basic indention level for all code
|
||||
is two character positions.
|
||||
\item {\bf Continuation statements}. Frequently a single statement
|
||||
is too long to fit within a single 80 column line. In this case, the
|
||||
statement is simply continued on the next one or more lines. Each
|
||||
continuation line must be indented at least one--half indention level,
|
||||
and more as necessary to increase readability.
|
||||
|
||||
Examples:
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
longVariableName = \=(anotherLongName * shorterName) + (loopIndex2 * i) + \\
|
||||
\>(k * j); // Correct, indented for neatness
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
a\=a\=a\= \kill
|
||||
for (LongTypeName\_t longLoopIndexName = aLongExpression; \\
|
||||
\>longLoopIndexName < MAX\_VALUE; \\
|
||||
\>longLoopIndexName++) // Wrong, continuations not indented far enough
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
for (\=LongTypeName\_t longLoopIndexName = aLongExpression; \\
|
||||
\>longLoopIndexName < MAX\_VALUE; \\
|
||||
\>longLoopIndexName++) // Right, indented for readability
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\item {\bf {\tt IF} Statements}.
|
||||
The open curly brace following an {\tt IF} statement must be on the
|
||||
following line, indented by one indention level.
|
||||
The subsequent lines must be
|
||||
indented by an additional one indention level.
|
||||
The {\tt ELSE} statement (if present)
|
||||
must be on a line by itself.
|
||||
|
||||
Examples:
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
aa\=aa\=aa\= \kill
|
||||
if (someCondition) \\
|
||||
\>\{ // Describe TRUE condition here\\
|
||||
\>\>i = k;\\
|
||||
\>\>k = i + 2;\\
|
||||
\>\} // Right, curly block indented one indent level, statements one indent more
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
aa\=aa\=aa\= \kill
|
||||
if (someCondition) \\
|
||||
\>\{ // Describe TRUE condition here\\
|
||||
\>\>i = k;\\
|
||||
\>\>k = i + 2;\\
|
||||
\>\} \\
|
||||
else // Right, ELSE statement on separate line, same indent as IF \\
|
||||
\>\{ // Describe FALSE condition here\\
|
||||
\>\>i = k * 2; \\
|
||||
\>\>k = i + 4; \\
|
||||
\>\} // Right, closing curly brace lined up with open brace
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
aa\=aa\=aa\= \kill
|
||||
if (someCondition) // Describe TRUE condition here\\
|
||||
\>i = k; // Right, single line block need not have curly braces \\
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
|
||||
\item {\bf {\tt FOR} Statements}.
|
||||
The open brace following a {\tt for} statement is indented
|
||||
one level from the {\tt for} statement itself. Each statement
|
||||
in the sub--block is indented one level from the curly brace.
|
||||
If the sub--block is a single statement, the curly braces can be
|
||||
omitted and the statement indented one level, or optionally appear
|
||||
on the same line as the {\tt for} statement.
|
||||
|
||||
Example:
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
aa\=aa\=aa\= \kill
|
||||
for (int i = 0; i < MAX\_COUNT; ++i) \\
|
||||
\>\{ // Curly brace indented one level \\
|
||||
\>\>sum += i; // Statements indented another one level \\
|
||||
\>\>prod *= i; \\
|
||||
\>\} // Close brace on same column as open brace \\
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\item {\bf {\tt WHILE} Statements}.
|
||||
{\tt While} statements are formatted similarly to {\tt IF} statements,
|
||||
with curly braces indented one level on separate lines, and the
|
||||
inner statements indented another level. If the sub--block has only
|
||||
a single line, the curly braces can be omitted, and the statement may
|
||||
appear on the same line as the {\tt WHILE} statement.
|
||||
|
||||
Examples:
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
aa\=aa\=aa\= \kill
|
||||
while (someCondition) \\
|
||||
\>\{ // Right, open brace indented one level \\
|
||||
\>\>i = k; // Right, statements indented one level from open brace \\
|
||||
\>\>k = i + 2;\\
|
||||
\>\} // Right, close brace lines up with open brace
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\item {\bf Infinite Loops}.
|
||||
Any loop intended to be infinite (of course with a {\tt break} statement
|
||||
somewhere) should be of the form:
|
||||
|
||||
\begin{tt}
|
||||
while(true) \\
|
||||
{ // Loop until sentinel found\\
|
||||
...code here \\
|
||||
}
|
||||
\end{tt}
|
||||
|
||||
\item {\bf {\tt SWITCH} Statements}.
|
||||
The open curly brace for a {\tt switch} statement will be on the same
|
||||
line as the {\tt switch} statement itself. Each {\tt case} statement
|
||||
following is indented two columns from the switch statement. Each
|
||||
statement in the {\tt case} block is indented two column from the
|
||||
{\tt case} statement. The closing curly brace is on a separate line
|
||||
by itself, indented two columns from the {\tt switch} statement.
|
||||
|
||||
Example:
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
aa\=aa\=aa\= \kill
|
||||
switch(someCondition) \{ Right, open brace on same line as switch\\
|
||||
\>case 0 : // Right, case indented two columns from switch\\
|
||||
\>\>i = k; // Right, statements indented two columns from case \\
|
||||
\>\>k = i + 2;\\
|
||||
\>\>break;\\
|
||||
\>case 1 : // Right, case indented two columns from switch\\
|
||||
\>\>i = k + 2; // Right, statements indented two columns from case \\
|
||||
\>\>k = i + 4;\\
|
||||
\>\>break;\\
|
||||
\>\} // Right, close brace lines up with case statements
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\item {\bf Functions}. Since C and C++ do not allow nested functions,
|
||||
all functions start with no indentation at column 0. The open curly
|
||||
brace is on a line by itself immediately following the function header
|
||||
and formal parameters, also in column 0.
|
||||
|
||||
Example:
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
aa\=aa\=aa\=aa\= \kill
|
||||
void Function1(int arg1, double arg2)\\
|
||||
\{ // Right, curly brace at column 0\\
|
||||
\>int local1 = 0; // Right, local variable at column 2\\
|
||||
\>int local2;\\
|
||||
\>\\
|
||||
\>local2 = local1 + arg1 + arg2; // Right, indented two columns\\
|
||||
\>int local3; // Right, variable at same level\\
|
||||
\>local3 = Function2(local2);\\
|
||||
\>if (someCondition)\\
|
||||
\>\>\{\\
|
||||
\>\>\>local3 = 0;\\
|
||||
\>\>\>local2 = local1;\\
|
||||
\>\>\>int local4 = local1 + 1; // Right, variable at same level\\
|
||||
\>\>\>Function3(local4);\\
|
||||
\>\>\}\\
|
||||
\} // Right, close brace at column 0
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\item {\bf Expressions}. Spaces should be used liberally in expressions
|
||||
to increase readability. One space before and after each operator,
|
||||
excepting the increment and decrement operators, leads to easy--to--read
|
||||
expressions. Continued expressions should be indented as far as needed
|
||||
for neatness and readability.
|
||||
|
||||
Examples:
|
||||
|
||||
\begin{tt}
|
||||
i = k * 2 + 3 / var1++; // Right, spacing separating terms \\
|
||||
\end{tt}
|
||||
|
||||
\begin{tt}
|
||||
i = k*2+2/var1++; // Wrong, crowded together and hard to read
|
||||
\end{tt}
|
||||
|
||||
\begin{tt}
|
||||
\begin{tabbing}
|
||||
someLongVariableName = \=anotherLongVariableName * shorterName + \\
|
||||
\>anotherName; // Right, indented to line up
|
||||
\end{tabbing}
|
||||
\end{tt}
|
||||
|
||||
\end{enumerate}
|
||||
\subsection{Header Files}
|
||||
\begin{enumerate}
|
||||
\item All header files will have a file name ending with {\tt .h}.
|
||||
\item All header files should have a one line comment describing
|
||||
the purpose of the header, and comments identifying the
|
||||
author and the (approximate) date the file was created.
|
||||
|
||||
Example:
|
||||
|
||||
\begin{tt}
|
||||
// ns3 Network Simulator - TCP Base Class Declaration \\
|
||||
// George F. Riley. riley@ece.gatech.edu. \\
|
||||
// Georgia Tech, Fall 2006
|
||||
\end{tt}
|
||||
|
||||
\item All header files should have an ``include guard'' to prevent accidental
|
||||
inclusion of the file multiple times in a single compilation unit. The include
|
||||
guard should be named after the file name. If the file name is \code{foo-bar.h}, then the
|
||||
include guard should be named \code{FOO\_BAR\_H}
|
||||
|
||||
Example:
|
||||
|
||||
\begin{tt}
|
||||
\#ifndef FOO\_BAR\_H \\
|
||||
\#define FOO\_BAR\_H \\
|
||||
|
||||
// (Contents of foo-bar.h here
|
||||
|
||||
\#endif
|
||||
\end{tt}
|
||||
\item Header files should avoid including other files whenever possible.
|
||||
This can often be avoided with judicious use of the
|
||||
{\tt class ClassName;} forward declaration.
|
||||
|
||||
Example:
|
||||
|
||||
\begin{tt}
|
||||
// excerpt from application.h \\
|
||||
class L4Protocol; \\
|
||||
|
||||
class Application \{ \\
|
||||
.... \\
|
||||
AddL4Proto(const L4Protocol\&); \\
|
||||
.... \\
|
||||
L4Protocol* l4Proto; \\
|
||||
\};
|
||||
\end{tt}
|
||||
|
||||
In the above example, the use of the forward declaration for {\tt L4Protocol}
|
||||
obviates the need to include {\tt l4proto.h} in the application header
|
||||
file.
|
||||
|
||||
\end{enumerate}
|
||||
\subsection{Source Code Files}
|
||||
\begin{enumerate}
|
||||
\item All souce code files will have a file name ending with {\tt .cc}.
|
||||
\item All source code files should have a one line comment describing
|
||||
the purpose of the code, and comments identifying the
|
||||
author and the (approximate) date the file was created.
|
||||
|
||||
Example:
|
||||
|
||||
\begin{tt}
|
||||
// ns3 Network Simulator - TCP Base Class Implementation \\
|
||||
// George F. Riley. riley@ece.gatech.edu. \\
|
||||
// Georgia Tech, Fall 2006
|
||||
\end{tt}
|
||||
|
||||
\item All {\tt \#include} directives should be grouped with {\em system}
|
||||
files listed first (eg. {\tt \#include <iostream>}), followed by
|
||||
\nst\ defined files (eg. {\tt \#include "tcp.h"}). Within a group,
|
||||
the includes should be sorted in alphabetical order.
|
||||
|
||||
Example:
|
||||
|
||||
\begin{tt}
|
||||
\#include <iostream> \\
|
||||
\#include <list> \\
|
||||
\#include <vector> \\
|
||||
|
||||
\#include "application.h" \\
|
||||
\#include "dumbbell.h" \\
|
||||
\#include "simulator.h" \\
|
||||
\#include "tcp.h.h"
|
||||
|
||||
\end{tt}
|
||||
\end{enumerate}
|
||||
\end{document}
|
||||
210
doc/codingstd.txt
Normal file
210
doc/codingstd.txt
Normal file
@@ -0,0 +1,210 @@
|
||||
The Ns-3 Coding Style
|
||||
|
||||
/*
|
||||
* Note: This file is incomplete and will be converted to non-text (html,pdf)
|
||||
* formats at a future date
|
||||
*/
|
||||
|
||||
1) Code layout
|
||||
-----------
|
||||
|
||||
The code layout follows the GNU coding standard layout for C and extends
|
||||
it to C++. Do not use tabs for indentation. Indentation spacing is 2
|
||||
spaces as outlined below:
|
||||
|
||||
void
|
||||
Foo (void)
|
||||
{
|
||||
if (test)
|
||||
{
|
||||
// do stuff here
|
||||
}
|
||||
else
|
||||
{
|
||||
// do other stuff here
|
||||
}
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
// do loop
|
||||
}
|
||||
|
||||
while (test)
|
||||
{
|
||||
// do while
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
// do stuff
|
||||
} while ();
|
||||
}
|
||||
|
||||
The following is not recommended:
|
||||
|
||||
if (test) statement
|
||||
|
||||
if (test)
|
||||
statement
|
||||
|
||||
for (...) statement
|
||||
|
||||
Each statement should be put on a separate line to increase readability.
|
||||
Short one-line comments can use the C++ comment style, that is, '//'
|
||||
but longer comments should use C-style comments:
|
||||
/*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
2) Naming Patterns
|
||||
---------------
|
||||
|
||||
2.1) Name encoding
|
||||
-------------
|
||||
Function, Method, and Type names should follow the CamelCase convention:
|
||||
words are joined without spaces and are capitalized. For example,
|
||||
"my computer" is transformed into MyComputer. Do not use all capital
|
||||
letters such as MAC or, PHY, but choose instead Mac or Phy. Do not use
|
||||
all capital letters, even for acronyms such as EDCA: use Edca instead.
|
||||
The goal of the CamelCase convention is to ensure that the words which
|
||||
make up a name can be separated by the eye: the initial Caps fills
|
||||
that role.
|
||||
|
||||
Variable names should follow a slight variation on the base CamelCase
|
||||
convention: camelBack. For example, the variable "user name" would be
|
||||
named "userName". This variation on the basic naming pattern is used to
|
||||
allow a reader to distinguish a variable name from its type. For example,
|
||||
"UserName userName;" would be used to declare a variable named userName
|
||||
of type UserName.
|
||||
|
||||
Global variables should be prefixed with a "g_" and member variables
|
||||
(including static member variables) should be prefixed with a "m_". The
|
||||
goal of that prefix is to give a reader a sense of where a variable of
|
||||
a given name is declared to allow the reader to locate the variable
|
||||
declaration and infer the variable type from that declaration. For example
|
||||
you could declare in your class header my-class.h:
|
||||
|
||||
class MyClass
|
||||
{
|
||||
void MyMethod (int aVar);
|
||||
int m_aVar;
|
||||
static int m_anotherVar;
|
||||
};
|
||||
|
||||
and implement in your class file my-class.cc:
|
||||
|
||||
int MyClass::m_anotherVar = 10;
|
||||
static int g_aStaticVar = 100;
|
||||
int g_aGlobalVar = 1000;
|
||||
|
||||
void
|
||||
MyClass::MyMethod (int aVar)
|
||||
{
|
||||
m_aVar = aVar;
|
||||
}
|
||||
|
||||
2.2) Choosing names
|
||||
|
||||
Variable, function, method, and type names should be based on the
|
||||
english language. Furthermore, always try to choose descriptive
|
||||
names for them. Types are often english names such as: Packet,
|
||||
Buffer, Mac, or Phy. Functions and Methods are often named
|
||||
based on verbs and adjectives: GetX, DoDispose, ClearArray, etc.
|
||||
|
||||
A long descriptive name which requires a lot of typing is always
|
||||
better than a short name which is hard to decipher. Do not use
|
||||
abbreviations in names unless the abbreviation is really unambiguous
|
||||
and obvious to everyone. Do not use short inapropriate names such
|
||||
as foo, bar, or baz. The name of an item should always match its
|
||||
purpose. As such, names such as tmp to identify a temporary
|
||||
variable or such as 'i' to identify a loop index are ok.
|
||||
|
||||
3) File layout and code organization
|
||||
---------------------------------
|
||||
|
||||
A class named MyClass should be declared in a header named my-class.h
|
||||
and implemented in a source file named my-class.cc. The goal of this
|
||||
naming pattern is to allow a reader to quickly navigate through
|
||||
the ns-3 codebase to locate the source file relevant to a specific
|
||||
type.
|
||||
|
||||
Each my-class.h header should start with the following comments: the
|
||||
first line ensures that developers who use the emacs editor will be
|
||||
able to indent your code correctly. The following lines ensure that
|
||||
your code is licensed under the GPL, that the copyright holders
|
||||
are properly identified (typically, you or your employer), and
|
||||
that the actual author of the code is identified. The latter is
|
||||
purely informational and we use it to try to track the most
|
||||
appropriate person to review a patch or fix a bug.
|
||||
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) YEAR COPYRIGHTHOLDER
|
||||
*
|
||||
* 3-paragran GPL blurb
|
||||
*
|
||||
* Author: MyName <myemail@foo.com>
|
||||
*/
|
||||
|
||||
Below these C-style comments, always include the following which
|
||||
defines a set of header guards (MY_CLASS_H) used to avoid multiple
|
||||
header includes, which ensures that your code is included
|
||||
in the "ns3" namespace and which provides a set of doxygen comments
|
||||
for the public part of your class API. Detailed information
|
||||
on the set of tags available for doxygen documentation is described
|
||||
in the doxygen website: http://www.doxygen.org.
|
||||
|
||||
#ifndef MY_CLASS_H
|
||||
#define MY_CLASS_H
|
||||
|
||||
namespace n3 {
|
||||
|
||||
/**
|
||||
* \brief short one-line description of the purpose of your class
|
||||
*
|
||||
* A longer description of the purpose of your class after a blank
|
||||
* empty line.
|
||||
*/
|
||||
class MyClass
|
||||
{
|
||||
public:
|
||||
MyClass ();
|
||||
/**
|
||||
* \param firstParam a short description of the purpose of this parameter
|
||||
* \returns a short description of what is returned from this function.
|
||||
*
|
||||
* A detailed description of the purpose of the method.
|
||||
*/
|
||||
int DoFoo (int firstParam);
|
||||
private:
|
||||
void MyPrivateMethod (void);
|
||||
int m_myPrivateMemberVariable;
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* MY_CLASS_H */
|
||||
|
||||
The my-class.cc file is structured similarly:
|
||||
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) YEAR COPYRIGHTHOLDER
|
||||
*
|
||||
* 3-paragran GPL blurb
|
||||
*
|
||||
* Author: MyName <myemail@foo.com>
|
||||
*/
|
||||
#include "my-class.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
MyClass::MyClass ()
|
||||
{}
|
||||
|
||||
...
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
|
||||
Contributing to the ns-3 project
|
||||
--------------------------------
|
||||
|
||||
ns-3 is an open source project backed by an NSF CISE CRI grant.
|
||||
Although the NSF PIs have specific aims to fulfill, we want others to
|
||||
contribute, and we'd like to have a broad community of users and
|
||||
developers, with the goal of a self-sustaining project downstream.
|
||||
The project is currently in a bootstrapping phase, but we welcome
|
||||
ambitious developers who might want to help shape the early design.
|
||||
|
||||
Despite the lack of a formal contribution process to the ns-3
|
||||
project, there are a number of steps which we expect every
|
||||
potential contributor to follow. These naturally stem from
|
||||
@@ -46,8 +52,12 @@ the open-source roots of the project:
|
||||
also expect model authors to act as responsible maintainers
|
||||
and be reactive to bug reports concerning their models.
|
||||
|
||||
- you should make sure that you understand that contributed
|
||||
models should be licensed under the GPLv2. You do not have
|
||||
to assign your copyright to the ns-3 project but you must
|
||||
accept the terms of the GPLv2. See the following link:
|
||||
- The project has decided upon GNU GPLv2 as the licensing structure.
|
||||
All simulation software in the ns-3 repositories will be GNU GPLv2
|
||||
or GNU GPLv2-compatible (with non-GPLv2 licensing reserved for
|
||||
ports of pre-existing code under a different license, such as BSD).
|
||||
You do not have to assign your copyright to the ns-3 project but
|
||||
you must accept the terms of the GPLv2 and attest that your
|
||||
contributions can be licensed under those terms. See the
|
||||
following link:
|
||||
http://www.fsf.org/licensing/licenses/info/GPLv2.html
|
||||
|
||||
@@ -3,7 +3,7 @@ Introduction
|
||||
|
||||
ns-3 uses the Mercurial software revision control system which
|
||||
is a replacement for tools liks cvs or subversion. Thus, to get
|
||||
access to the developement versions of ns-3, you need to install
|
||||
access to the development versions of ns-3, you need to install
|
||||
mercurial first. See http://www.selenic.com/mercurial/wiki/
|
||||
|
||||
Mercurial cheat sheet
|
||||
@@ -38,6 +38,7 @@ push upwards (developers access only):
|
||||
--------------------------------------
|
||||
To the main repository:
|
||||
hg push ssh://code@code.nsnam.org/repos/ns-3-dev
|
||||
|
||||
To your private repository:
|
||||
hg push ssh://username@code.nsnam.org//home/username/repositories/username/repository
|
||||
|
||||
|
||||
@@ -147,6 +147,36 @@ uint64_t DataRate::Parse(const std::string s)
|
||||
return v;
|
||||
}
|
||||
|
||||
bool DataRate::operator < (const DataRate& rhs)
|
||||
{
|
||||
return m_bps<rhs.m_bps;
|
||||
}
|
||||
|
||||
bool DataRate::operator <= (const DataRate& rhs)
|
||||
{
|
||||
return m_bps<=rhs.m_bps;
|
||||
}
|
||||
|
||||
bool DataRate::operator > (const DataRate& rhs)
|
||||
{
|
||||
return m_bps>rhs.m_bps;
|
||||
}
|
||||
|
||||
bool DataRate::operator >= (const DataRate& rhs)
|
||||
{
|
||||
return m_bps>=rhs.m_bps;
|
||||
}
|
||||
|
||||
bool DataRate::operator == (const DataRate& rhs)
|
||||
{
|
||||
return m_bps==rhs.m_bps;
|
||||
}
|
||||
|
||||
bool DataRate::operator != (const DataRate& rhs)
|
||||
{
|
||||
return m_bps!=rhs.m_bps;
|
||||
}
|
||||
|
||||
double DataRate::CalculateTxTime(uint32_t bytes) const
|
||||
{
|
||||
return static_cast<double>(bytes)*8/m_bps;
|
||||
|
||||
@@ -41,6 +41,8 @@ namespace ns3 {
|
||||
* uint32_t nBytes = 20;
|
||||
* double txtime = x.CalclulateTxTime(nBytes);
|
||||
* \endcode
|
||||
* This class also supports the regular comparison operators <, >, <=, >=, ==,
|
||||
* and !=
|
||||
*/
|
||||
class DataRate
|
||||
{
|
||||
@@ -70,6 +72,13 @@ class DataRate
|
||||
*/
|
||||
DataRate (const std::string s);
|
||||
|
||||
bool operator < (const DataRate& rhs);
|
||||
bool operator <= (const DataRate& rhs);
|
||||
bool operator > (const DataRate& rhs);
|
||||
bool operator >= (const DataRate& rhs);
|
||||
bool operator == (const DataRate& rhs);
|
||||
bool operator != (const DataRate& rhs);
|
||||
|
||||
/**
|
||||
* \brief Calculate transmission time
|
||||
*
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
//
|
||||
// Copyright (c) 2006 Georgia Tech Research Corporation
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation;
|
||||
//
|
||||
// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// Author: George F. Riley<riley@ece.gatech.edu>
|
||||
//
|
||||
|
||||
#ifndef __SMART_SET_H__
|
||||
#define __SMART_SET_H__
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
// Define a "smart" set container to be used by any ns3 object
|
||||
// maintaining a collection of pointers, which must be freed at
|
||||
// a later time. The template parameter T must be a pointer, or an
|
||||
// object supporting the delete operator, and the dereferenced object
|
||||
// must support a Copy() function. The set implementation
|
||||
// has a O(1) "Remove" operation, that removes and deletes
|
||||
// a single element in the container. However, additions to the
|
||||
// set are O(n) due to the sorted nature of the underlying STL set.
|
||||
|
||||
// Define a "smart" set container
|
||||
template <typename T> class SmartSet {
|
||||
public:
|
||||
typedef typename std::set<T>::const_iterator const_iterator;
|
||||
typedef typename std::set<T>::iterator iterator;
|
||||
typedef typename std::set<T>::size_type size_type;
|
||||
SmartSet()
|
||||
{ // Nothing needed for default constructor
|
||||
}
|
||||
|
||||
~SmartSet()
|
||||
{ // Smart container destructor
|
||||
for (const_iterator i = m_elements.begin(); i != m_elements.end(); ++i)
|
||||
{
|
||||
delete *i;
|
||||
}
|
||||
// No need to "clear" the set, as the set destructor does this
|
||||
}
|
||||
|
||||
SmartSet(const SmartSet& o)
|
||||
{ // Copy constructor, copy all underlying objects
|
||||
for (iterator i = o.Begin(); i != o.End(); ++i)
|
||||
{
|
||||
Add((*i)->Copy());
|
||||
}
|
||||
}
|
||||
|
||||
void Add(const T& t) // Add element, will be deleted on Clear or destructor
|
||||
{
|
||||
m_elements.insert(t);
|
||||
}
|
||||
|
||||
bool Remove(T& t) // Remove and delete specified element
|
||||
{ // Find the specified element, delete it, and remove from the container.
|
||||
// Returns true if found
|
||||
iterator i = m_elements.find(t);
|
||||
if (i != m_elements.end())
|
||||
{ // Found it, delete it
|
||||
delete t; // Delete the object
|
||||
m_elements.erase(i); // Erase the element
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{ // Delete and remove all elements from the smart container
|
||||
for (const_iterator i = m_elements.begin(); i != m_elements.end(); ++i)
|
||||
{
|
||||
delete *i;
|
||||
}
|
||||
m_elements.clear();
|
||||
}
|
||||
|
||||
// Iterator access
|
||||
iterator Begin() const
|
||||
{
|
||||
return m_elements.begin();
|
||||
}
|
||||
|
||||
iterator End() const
|
||||
{
|
||||
return m_elements.end();
|
||||
}
|
||||
|
||||
// Miscellaneous
|
||||
size_type Size() const
|
||||
{
|
||||
return m_elements.size();
|
||||
}
|
||||
|
||||
bool Empty() const
|
||||
{
|
||||
return m_elements.empty();
|
||||
}
|
||||
|
||||
private:
|
||||
std::set<T> m_elements;
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
#endif
|
||||
@@ -1,142 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
//
|
||||
// Copyright (c) 2006 Georgia Tech Research Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation;
|
||||
//
|
||||
// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// Author: George F. Riley<riley@ece.gatech.edu>
|
||||
//
|
||||
|
||||
#ifndef __SMART_VECTOR_H__
|
||||
#define __SMART_VECTOR_H__
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
// Define a "smart" vector container to be used by any ns3 object
|
||||
// maintaining a collection of pointers, which must be freed at
|
||||
// a later time. The template parameter T must be a pointer, or an
|
||||
// object supporting the delete operator, and the dereferenced object
|
||||
// must support the Copy() operation. The vector implementation
|
||||
// has in inefficient "Remove" operation, that removes and deletes
|
||||
// a single element in the container. If frequent "Remove" operations
|
||||
// are needed, the SmartSet is likey a better choice.
|
||||
|
||||
template <typename T> class SmartVector {
|
||||
public:
|
||||
typedef typename std::vector<T>::const_iterator const_iterator;
|
||||
typedef typename std::vector<T>::iterator iterator;
|
||||
typedef typename std::vector<T>::size_type size_type;
|
||||
SmartVector()
|
||||
{ // Nothing needed for default constructor
|
||||
}
|
||||
~SmartVector()
|
||||
{ // Smart container destructor
|
||||
for (const_iterator i = m_elements.begin(); i != m_elements.end(); ++i)
|
||||
{
|
||||
delete *i;
|
||||
}
|
||||
// No need to "clear" the vector, as the vector destructor does this
|
||||
}
|
||||
|
||||
SmartVector(const SmartVector& o)
|
||||
{ // Copy constructor, copy each underlying object
|
||||
for (const_iterator i = o.Begin(); i != o.End(); ++i)
|
||||
{
|
||||
Add((*i)->Copy());
|
||||
}
|
||||
}
|
||||
|
||||
void Add(const T& t) // Add element, will be deleted on Clear or destructor
|
||||
{
|
||||
m_elements.push_back(t);
|
||||
}
|
||||
|
||||
bool Remove()
|
||||
{ // Remove the back element
|
||||
if (Empty()) return false; // No back element exists
|
||||
m_elements.pop_back();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Remove(const T& t) // Remove and delete specified element
|
||||
{ // Find the specified element, delete it, and remove from the container.
|
||||
// Returns true if found.
|
||||
// Note, this implementation is not particularly efficient. If
|
||||
// explicit individual element removal is a frequent operation for a given
|
||||
// smart container, an implementation based on STL "set" will
|
||||
// be a better choice. See "SmartSet" if for this approach.
|
||||
// The SmartSet adds extra overhead in that the elementes are sorted,
|
||||
// so it should be used with caution.
|
||||
for (const_iterator i = m_elements.begin(); i != m_elements.end(); ++i)
|
||||
{
|
||||
if (*i == t)
|
||||
{ // Found it
|
||||
delete t; // Delete the object
|
||||
m_elements.erase(i); // Erase the element
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{ // Delete and remove all elements from the smart container
|
||||
for (const_iterator i = m_elements.begin(); i != m_elements.end(); ++i)
|
||||
{
|
||||
delete *i;
|
||||
}
|
||||
m_elements.clear();
|
||||
}
|
||||
|
||||
// Iterator access
|
||||
const_iterator Begin() const
|
||||
{
|
||||
return m_elements.begin();
|
||||
}
|
||||
|
||||
const_iterator End() const
|
||||
{
|
||||
return m_elements.end();
|
||||
}
|
||||
|
||||
// Miscellaneous
|
||||
size_type Size() const
|
||||
{
|
||||
return m_elements.size();
|
||||
}
|
||||
|
||||
bool Empty() const
|
||||
{
|
||||
return m_elements.empty();
|
||||
}
|
||||
|
||||
T& Back()
|
||||
{
|
||||
return m_elements.back();
|
||||
}
|
||||
|
||||
T operator[](size_type i) const
|
||||
{ // Indexing operator
|
||||
return m_elements[i];
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<T> m_elements;
|
||||
};
|
||||
|
||||
} // Namespace ns3
|
||||
#endif
|
||||
@@ -43,7 +43,5 @@ def build(bld):
|
||||
'array-trace-resolver.h',
|
||||
'trace-root.h',
|
||||
'terminal-trace-resolver.h',
|
||||
'smartvector.h',
|
||||
'smartset.h',
|
||||
'data-rate.h',
|
||||
]
|
||||
|
||||
@@ -192,8 +192,17 @@ CallbackTest::RunTests (void)
|
||||
f1 (1);
|
||||
g1 (2);
|
||||
|
||||
a1.Nullify ();
|
||||
b1.Nullify ();
|
||||
c1.Nullify ();
|
||||
d1.Nullify ();
|
||||
e1.Nullify ();
|
||||
g1.Nullify ();
|
||||
|
||||
Test8 (f1);
|
||||
|
||||
f1.Nullify ();
|
||||
|
||||
Callback<void, int64_t,int64_t> a2;
|
||||
|
||||
if (IsWrong ())
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#ifndef CALLBACK_H
|
||||
#define CALLBACK_H
|
||||
|
||||
#include "reference-list.h"
|
||||
#include "ptr.h"
|
||||
#include "fatal-error.h"
|
||||
|
||||
namespace ns3 {
|
||||
@@ -58,10 +58,35 @@ namespace ns3 {
|
||||
*/
|
||||
class empty {};
|
||||
|
||||
template <typename T>
|
||||
struct CallbackTraits;
|
||||
|
||||
template <typename T>
|
||||
struct CallbackTraits<T *>
|
||||
{
|
||||
static T & GetReference (T * const p)
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
};
|
||||
|
||||
class CallbackImplBase {
|
||||
public:
|
||||
CallbackImplBase ()
|
||||
: m_count (1) {}
|
||||
virtual ~CallbackImplBase () {}
|
||||
void Ref (void) {
|
||||
m_count++;
|
||||
}
|
||||
void Unref (void) {
|
||||
m_count--;
|
||||
if (m_count == 0) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
virtual bool IsEqual (CallbackImplBase const *other) const = 0;
|
||||
private:
|
||||
uint32_t m_count;
|
||||
};
|
||||
|
||||
// declare the CallbackImpl class
|
||||
@@ -116,7 +141,7 @@ template <typename T, typename R, typename T1, typename T2, typename T3, typenam
|
||||
class FunctorCallbackImpl : public CallbackImpl<R,T1,T2,T3,T4,T5> {
|
||||
public:
|
||||
FunctorCallbackImpl (T const &functor)
|
||||
: m_functor (functor) {}
|
||||
: m_functor (functor) {}
|
||||
virtual ~FunctorCallbackImpl () {}
|
||||
R operator() (void) {
|
||||
return m_functor ();
|
||||
@@ -158,25 +183,25 @@ template <typename OBJ_PTR, typename MEM_PTR, typename R, typename T1, typename
|
||||
class MemPtrCallbackImpl : public CallbackImpl<R,T1,T2,T3,T4,T5> {
|
||||
public:
|
||||
MemPtrCallbackImpl (OBJ_PTR const&objPtr, MEM_PTR mem_ptr)
|
||||
: m_objPtr (objPtr), m_memPtr (mem_ptr) {}
|
||||
: m_objPtr (objPtr), m_memPtr (mem_ptr) {}
|
||||
virtual ~MemPtrCallbackImpl () {}
|
||||
R operator() (void) {
|
||||
return ((*m_objPtr).*m_memPtr) ();
|
||||
return ((CallbackTraits<OBJ_PTR>::GetReference (m_objPtr)).*m_memPtr) ();
|
||||
}
|
||||
R operator() (T1 a1) {
|
||||
return ((*m_objPtr).*m_memPtr) (a1);
|
||||
return ((CallbackTraits<OBJ_PTR>::GetReference (m_objPtr)).*m_memPtr) (a1);
|
||||
}
|
||||
R operator() (T1 a1,T2 a2) {
|
||||
return ((*m_objPtr).*m_memPtr) (a1,a2);
|
||||
return ((CallbackTraits<OBJ_PTR>::GetReference (m_objPtr)).*m_memPtr) (a1, a2);
|
||||
}
|
||||
R operator() (T1 a1,T2 a2,T3 a3) {
|
||||
return ((*m_objPtr).*m_memPtr) (a1,a2,a3);
|
||||
return ((CallbackTraits<OBJ_PTR>::GetReference (m_objPtr)).*m_memPtr) (a1, a2, a3);
|
||||
}
|
||||
R operator() (T1 a1,T2 a2,T3 a3,T4 a4) {
|
||||
return ((*m_objPtr).*m_memPtr) (a1,a2,a3,a4);
|
||||
return ((CallbackTraits<OBJ_PTR>::GetReference (m_objPtr)).*m_memPtr) (a1, a2, a3, a4);
|
||||
}
|
||||
R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5) {
|
||||
return ((*m_objPtr).*m_memPtr) (a1,a2,a3,a4,a5);
|
||||
return ((CallbackTraits<OBJ_PTR>::GetReference (m_objPtr)).*m_memPtr) (a1, a2, a3, a4, a5);
|
||||
}
|
||||
virtual bool IsEqual (CallbackImplBase const *other) const {
|
||||
MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5> const *otherDerived =
|
||||
@@ -242,40 +267,43 @@ public:
|
||||
// always properly disambiguited by the c++ compiler
|
||||
template <typename FUNCTOR>
|
||||
Callback (FUNCTOR const &functor, bool, bool)
|
||||
: m_impl (new FunctorCallbackImpl<FUNCTOR,R,T1,T2,T3,T4,T5> (functor))
|
||||
: m_impl (MakeNewObject<FunctorCallbackImpl<FUNCTOR,R,T1,T2,T3,T4,T5> > (functor))
|
||||
{}
|
||||
|
||||
template <typename OBJ_PTR, typename MEM_PTR>
|
||||
Callback (OBJ_PTR const &objPtr, MEM_PTR mem_ptr)
|
||||
: m_impl (new MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5> (objPtr, mem_ptr))
|
||||
: m_impl (MakeNewObject<MemPtrCallbackImpl<OBJ_PTR,MEM_PTR,R,T1,T2,T3,T4,T5> > (objPtr, mem_ptr))
|
||||
{}
|
||||
|
||||
Callback (ReferenceList<CallbackImpl<R,T1,T2,T3,T4,T5> *> const &impl)
|
||||
Callback (Ptr<CallbackImpl<R,T1,T2,T3,T4,T5> > const &impl)
|
||||
: m_impl (impl)
|
||||
{}
|
||||
|
||||
bool IsNull (void) {
|
||||
return (m_impl.Get () == 0)?true:false;
|
||||
return (PeekImpl () == 0)?true:false;
|
||||
}
|
||||
void Nullify (void) {
|
||||
m_impl = 0;
|
||||
}
|
||||
|
||||
Callback () : m_impl () {}
|
||||
R operator() (void) const {
|
||||
return (*(m_impl.Get ())) ();
|
||||
return (*(PeekImpl ())) ();
|
||||
}
|
||||
R operator() (T1 a1) const {
|
||||
return (*(m_impl.Get ())) (a1);
|
||||
return (*(PeekImpl ())) (a1);
|
||||
}
|
||||
R operator() (T1 a1, T2 a2) const {
|
||||
return (*(m_impl).Get ()) (a1,a2);
|
||||
return (*(PeekImpl ())) (a1,a2);
|
||||
}
|
||||
R operator() (T1 a1, T2 a2, T3 a3) const {
|
||||
return (*(m_impl).Get ()) (a1,a2,a3);
|
||||
return (*(PeekImpl ())) (a1,a2,a3);
|
||||
}
|
||||
R operator() (T1 a1, T2 a2, T3 a3, T4 a4) const {
|
||||
return (*(m_impl).Get ()) (a1,a2,a3,a4);
|
||||
return (*(PeekImpl ())) (a1,a2,a3,a4);
|
||||
}
|
||||
R operator() (T1 a1, T2 a2, T3 a3, T4 a4,T5 a5) const {
|
||||
return (*(m_impl).Get ()) (a1,a2,a3,a4,a5);
|
||||
return (*(PeekImpl ())) (a1,a2,a3,a4,a5);
|
||||
}
|
||||
|
||||
bool IsEqual (CallbackBase const &other) {
|
||||
@@ -304,10 +332,10 @@ public:
|
||||
*this = *goodType;
|
||||
}
|
||||
private:
|
||||
virtual CallbackImplBase *PeekImpl (void) const {
|
||||
return m_impl.Get ();
|
||||
virtual CallbackImpl<R,T1,T2,T3,T4,T5> *PeekImpl (void) const {
|
||||
return PeekPointer (m_impl);
|
||||
}
|
||||
ReferenceList<CallbackImpl<R,T1,T2,T3,T4,T5>*> m_impl;
|
||||
Ptr<CallbackImpl<R,T1,T2,T3,T4,T5> > m_impl;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -323,12 +351,12 @@ private:
|
||||
* Build Callbacks for class method members which takes no arguments
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename OBJ, typename R>
|
||||
Callback<R> MakeCallback (R (OBJ::*mem_ptr) (), OBJ *const objPtr) {
|
||||
return Callback<R> (objPtr, mem_ptr);
|
||||
template <typename T, typename OBJ, typename R>
|
||||
Callback<R> MakeCallback (R (T::*memPtr) (void), OBJ objPtr) {
|
||||
return Callback<R> (objPtr, memPtr);
|
||||
}
|
||||
template <typename OBJ, typename R>
|
||||
Callback<R> MakeCallback (R (OBJ::*mem_ptr) () const, OBJ const *const objPtr) {
|
||||
template <typename T, typename OBJ, typename R>
|
||||
Callback<R> MakeCallback (R (T::*mem_ptr) () const, OBJ const objPtr) {
|
||||
return Callback<R> (objPtr, mem_ptr);
|
||||
}
|
||||
/**
|
||||
@@ -339,12 +367,12 @@ Callback<R> MakeCallback (R (OBJ::*mem_ptr) () const, OBJ const *const objPtr) {
|
||||
* Build Callbacks for class method members which takes one argument
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename OBJ, typename R, typename T1>
|
||||
Callback<R,T1> MakeCallback (R (OBJ::*mem_ptr) (T1), OBJ *const objPtr) {
|
||||
template <typename T, typename OBJ, typename R, typename T1>
|
||||
Callback<R,T1> MakeCallback (R (T::*mem_ptr) (T1), OBJ *const objPtr) {
|
||||
return Callback<R,T1> (objPtr, mem_ptr);
|
||||
}
|
||||
template <typename OBJ, typename R, typename T1>
|
||||
Callback<R,T1> MakeCallback (R (OBJ::*mem_ptr) (T1) const, OBJ const *const objPtr) {
|
||||
template <typename T, typename OBJ, typename R, typename T1>
|
||||
Callback<R,T1> MakeCallback (R (T::*mem_ptr) (T1) const, OBJ const *const objPtr) {
|
||||
return Callback<R,T1> (objPtr, mem_ptr);
|
||||
}
|
||||
/**
|
||||
@@ -355,12 +383,12 @@ Callback<R,T1> MakeCallback (R (OBJ::*mem_ptr) (T1) const, OBJ const *const objP
|
||||
* Build Callbacks for class method members which takes two arguments
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename OBJ, typename R, typename T1, typename T2>
|
||||
Callback<R,T1,T2> MakeCallback (R (OBJ::*mem_ptr) (T1,T2), OBJ *const objPtr) {
|
||||
template <typename T, typename OBJ, typename R, typename T1, typename T2>
|
||||
Callback<R,T1,T2> MakeCallback (R (T::*mem_ptr) (T1,T2), OBJ *const objPtr) {
|
||||
return Callback<R,T1,T2> (objPtr, mem_ptr);
|
||||
}
|
||||
template <typename OBJ, typename R, typename T1, typename T2>
|
||||
Callback<R,T1,T2> MakeCallback (R (OBJ::*mem_ptr) (T1,T2) const, OBJ const*const objPtr) {
|
||||
template <typename T, typename OBJ, typename R, typename T1, typename T2>
|
||||
Callback<R,T1,T2> MakeCallback (R (T::*mem_ptr) (T1,T2) const, OBJ const*const objPtr) {
|
||||
return Callback<R,T1,T2> (objPtr, mem_ptr);
|
||||
}
|
||||
/**
|
||||
@@ -371,12 +399,12 @@ Callback<R,T1,T2> MakeCallback (R (OBJ::*mem_ptr) (T1,T2) const, OBJ const*const
|
||||
* Build Callbacks for class method members which takes three arguments
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename OBJ, typename R, typename T1,typename T2, typename T3>
|
||||
Callback<R,T1,T2,T3> MakeCallback (R (OBJ::*mem_ptr) (T1,T2,T3), OBJ *const objPtr) {
|
||||
template <typename T, typename OBJ, typename R, typename T1,typename T2, typename T3>
|
||||
Callback<R,T1,T2,T3> MakeCallback (R (T::*mem_ptr) (T1,T2,T3), OBJ *const objPtr) {
|
||||
return Callback<R,T1,T2,T3> (objPtr, mem_ptr);
|
||||
}
|
||||
template <typename OBJ, typename R, typename T1,typename T2, typename T3>
|
||||
Callback<R,T1,T2,T3> MakeCallback (R (OBJ::*mem_ptr) (T1,T2,T3) const, OBJ const*const objPtr) {
|
||||
template <typename T, typename OBJ, typename R, typename T1,typename T2, typename T3>
|
||||
Callback<R,T1,T2,T3> MakeCallback (R (T::*mem_ptr) (T1,T2,T3) const, OBJ const*const objPtr) {
|
||||
return Callback<R,T1,T2,T3> (objPtr, mem_ptr);
|
||||
}
|
||||
/**
|
||||
@@ -387,12 +415,12 @@ Callback<R,T1,T2,T3> MakeCallback (R (OBJ::*mem_ptr) (T1,T2,T3) const, OBJ const
|
||||
* Build Callbacks for class method members which takes four arguments
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4>
|
||||
Callback<R,T1,T2,T3,T4> MakeCallback (R (OBJ::*mem_ptr) (T1,T2,T3,T4), OBJ *const objPtr) {
|
||||
template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4>
|
||||
Callback<R,T1,T2,T3,T4> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4), OBJ *const objPtr) {
|
||||
return Callback<R,T1,T2,T3,T4> (objPtr, mem_ptr);
|
||||
}
|
||||
template <typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4>
|
||||
Callback<R,T1,T2,T3,T4> MakeCallback (R (OBJ::*mem_ptr) (T1,T2,T3,T4) const, OBJ const*const objPtr) {
|
||||
template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4>
|
||||
Callback<R,T1,T2,T3,T4> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4) const, OBJ const*const objPtr) {
|
||||
return Callback<R,T1,T2,T3,T4> (objPtr, mem_ptr);
|
||||
}
|
||||
/**
|
||||
@@ -403,12 +431,12 @@ Callback<R,T1,T2,T3,T4> MakeCallback (R (OBJ::*mem_ptr) (T1,T2,T3,T4) const, OBJ
|
||||
* Build Callbacks for class method members which takes five arguments
|
||||
* and potentially return a value.
|
||||
*/
|
||||
template <typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4,typename T5>
|
||||
Callback<R,T1,T2,T3,T4,T5> MakeCallback (R (OBJ::*mem_ptr) (T1,T2,T3,T4,T5), OBJ *const objPtr) {
|
||||
template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4,typename T5>
|
||||
Callback<R,T1,T2,T3,T4,T5> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ *const objPtr) {
|
||||
return Callback<R,T1,T2,T3,T4,T5> (objPtr, mem_ptr);
|
||||
}
|
||||
template <typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4,typename T5>
|
||||
Callback<R,T1,T2,T3,T4,T5> MakeCallback (R (OBJ::*mem_ptr) (T1,T2,T3,T4,T5) const, OBJ const*const objPtr) {
|
||||
template <typename T, typename OBJ, typename R, typename T1, typename T2, typename T3, typename T4,typename T5>
|
||||
Callback<R,T1,T2,T3,T4,T5> MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5) const, OBJ const*const objPtr) {
|
||||
return Callback<R,T1,T2,T3,T4,T5> (objPtr, mem_ptr);
|
||||
}
|
||||
|
||||
@@ -599,44 +627,34 @@ private:
|
||||
|
||||
template <typename R, typename TX>
|
||||
Callback<R> MakeBoundCallback (R (*fnPtr) (TX), TX a) {
|
||||
ReferenceList<CallbackImpl<R,empty,empty,empty,empty,empty>*> impl =
|
||||
ReferenceList<CallbackImpl<R,empty,empty,empty,empty,empty>*> (
|
||||
new BoundFunctorCallbackImpl<R (*) (TX),R,TX,empty,empty,empty,empty,empty> (fnPtr, a)
|
||||
);
|
||||
Ptr<CallbackImpl<R,empty,empty,empty,empty,empty> > impl =
|
||||
MakeNewObject<BoundFunctorCallbackImpl<R (*) (TX),R,TX,empty,empty,empty,empty,empty> >(fnPtr, a);
|
||||
return Callback<R> (impl);
|
||||
}
|
||||
|
||||
template <typename R, typename TX, typename T1>
|
||||
Callback<R,T1> MakeBoundCallback (R (*fnPtr) (TX,T1), TX a) {
|
||||
ReferenceList<CallbackImpl<R,T1,empty,empty,empty,empty>*> impl =
|
||||
ReferenceList<CallbackImpl<R,T1,empty,empty,empty,empty>*> (
|
||||
new BoundFunctorCallbackImpl<R (*) (TX,T1),R,TX,T1,empty,empty,empty,empty> (fnPtr, a)
|
||||
);
|
||||
Ptr<CallbackImpl<R,T1,empty,empty,empty,empty> > impl =
|
||||
MakeNewObject<BoundFunctorCallbackImpl<R (*) (TX,T1),R,TX,T1,empty,empty,empty,empty> > (fnPtr, a);
|
||||
return Callback<R,T1> (impl);
|
||||
}
|
||||
template <typename R, typename TX, typename T1, typename T2>
|
||||
Callback<R,T1,T2> MakeBoundCallback (R (*fnPtr) (TX,T1,T2), TX a) {
|
||||
ReferenceList<CallbackImpl<R,T1,T2,empty,empty,empty>*> impl =
|
||||
ReferenceList<CallbackImpl<R,T1,T2,empty,empty,empty>*> (
|
||||
new BoundFunctorCallbackImpl<R (*) (TX,T1,T2),R,TX,T1,T2,empty,empty,empty> (fnPtr, a)
|
||||
);
|
||||
Ptr<CallbackImpl<R,T1,T2,empty,empty,empty> > impl =
|
||||
MakeNewObject<BoundFunctorCallbackImpl<R (*) (TX,T1,T2),R,TX,T1,T2,empty,empty,empty> > (fnPtr, a);
|
||||
return Callback<R,T1,T2> (impl);
|
||||
}
|
||||
template <typename R, typename TX, typename T1, typename T2,typename T3,typename T4>
|
||||
Callback<R,T1,T2,T3,T4> MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3,T4), TX a) {
|
||||
ReferenceList<CallbackImpl<R,T1,T2,T3,T4,empty>*> impl =
|
||||
ReferenceList<CallbackImpl<R,T1,T2,T3,T4,empty>*> (
|
||||
new BoundFunctorCallbackImpl<R (*) (TX,T1,T2,T3,T4),R,TX,T1,T2,T3,T4,empty> (fnPtr, a)
|
||||
);
|
||||
Ptr<CallbackImpl<R,T1,T2,T3,T4,empty> > impl =
|
||||
MakeNewObject<BoundFunctorCallbackImpl<R (*) (TX,T1,T2,T3,T4),R,TX,T1,T2,T3,T4,empty> > (fnPtr, a);
|
||||
return Callback<R,T1,T2,T3,T4> (impl);
|
||||
}
|
||||
|
||||
template <typename R, typename TX, typename T1, typename T2,typename T3,typename T4,typename T5>
|
||||
Callback<R,T1,T2,T3,T4,T5> MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3,T4,T5), TX a) {
|
||||
ReferenceList<CallbackImpl<R,T1,T2,T3,T4,T5>*> impl =
|
||||
ReferenceList<CallbackImpl<R,T1,T2,T3,T4,T5>*> (
|
||||
new BoundFunctorCallbackImpl<R (*) (TX,T1,T2,T3,T4,T5),R,TX,T1,T2,T3,T4,T5> (fnPtr, a)
|
||||
);
|
||||
Ptr<CallbackImpl<R,T1,T2,T3,T4,T5> > impl =
|
||||
MakeNewObject<BoundFunctorCallbackImpl<R (*) (TX,T1,T2,T3,T4,T5),R,TX,T1,T2,T3,T4,T5> > (fnPtr, a);
|
||||
return Callback<R,T1,T2,T3,T4,T5> (impl);
|
||||
}
|
||||
|
||||
|
||||
@@ -286,6 +286,10 @@ public:
|
||||
* user with ns3::Bind
|
||||
*/
|
||||
T GetValue (void);
|
||||
/**
|
||||
* \param value the new default value.
|
||||
*/
|
||||
void SetValue (T value);
|
||||
private:
|
||||
virtual bool DoParseValue (const std::string &value);
|
||||
virtual std::string DoGetType (void) const;
|
||||
@@ -467,6 +471,12 @@ EnumDefaultValue<T>::GetValue (void)
|
||||
return m_value;
|
||||
}
|
||||
template <typename T>
|
||||
void
|
||||
EnumDefaultValue<T>::SetValue (T value)
|
||||
{
|
||||
m_value = value;
|
||||
}
|
||||
template <typename T>
|
||||
bool
|
||||
EnumDefaultValue<T>::DoParseValue (const std::string &value)
|
||||
{
|
||||
|
||||
@@ -33,7 +33,7 @@ class NoCount : public Object
|
||||
public:
|
||||
NoCount (Callback<void> cb);
|
||||
~NoCount ();
|
||||
void Nothing () const;
|
||||
void Nothing (void) const;
|
||||
private:
|
||||
Callback<void> m_cb;
|
||||
};
|
||||
@@ -280,6 +280,25 @@ PtrTest::RunTests (void)
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Ptr<NoCount> p = MakeNewObject<NoCount> (cb);
|
||||
Callback<void> callback = MakeCallback (&NoCount::Nothing, p);
|
||||
callback ();
|
||||
}
|
||||
{
|
||||
Ptr<const NoCount> p = MakeNewObject<NoCount> (cb);
|
||||
Callback<void> callback = MakeCallback (&NoCount::Nothing, p);
|
||||
callback ();
|
||||
}
|
||||
|
||||
#if 0
|
||||
// as expected, fails compilation.
|
||||
{
|
||||
Ptr<const Object> p = MakeNewObject<NoCount> (cb);
|
||||
Callback<void> callback = MakeCallback (&NoCount::Nothing, p);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
return ok;
|
||||
|
||||
@@ -73,11 +73,12 @@ public:
|
||||
/**
|
||||
* \param ptr raw pointer to manage
|
||||
*
|
||||
* Create a smart pointer which points to the
|
||||
* input raw pointer. This method takes ownershipt
|
||||
* of the input raw pointer. That is, the smart pointer
|
||||
* becomes responsible for calling delete on the
|
||||
* raw pointer when needed.
|
||||
* Create a smart pointer which points to the object pointed to by
|
||||
* the input raw pointer ptr. This method creates its own reference
|
||||
* to the pointed object. The caller is responsible for Unref()'ing
|
||||
* its own reference, and the smart pointer will eventually do the
|
||||
* same, so that object is deleted if no more references to it
|
||||
* remain.
|
||||
*/
|
||||
Ptr (T *ptr);
|
||||
Ptr (Ptr const&o);
|
||||
@@ -170,6 +171,31 @@ bool operator != (Ptr<T1> const &lhs, Ptr<T2> const &rhs);
|
||||
template <typename T1, typename T2>
|
||||
Ptr<T1> const_pointer_cast (Ptr<T2> const&p);
|
||||
|
||||
template <typename T>
|
||||
struct CallbackTraits;
|
||||
|
||||
template <typename T>
|
||||
struct CallbackTraits<Ptr<T> >
|
||||
{
|
||||
static T & GetReference (Ptr<T> const p)
|
||||
{
|
||||
return *PeekPointer (p);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct EventMemberImplTraits;
|
||||
|
||||
template <typename T>
|
||||
struct EventMemberImplTraits<Ptr<T> >
|
||||
{
|
||||
static T &GetReference (Ptr<T> p) {
|
||||
return *PeekPointer (p);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
|
||||
|
||||
@@ -663,7 +663,7 @@ LogNormalVariable::GetValue ()
|
||||
return z;
|
||||
}
|
||||
|
||||
double LogNormalVariable::GetSingleValue(double sigma,double mu)
|
||||
double LogNormalVariable::GetSingleValue (double mu, double sigma)
|
||||
{
|
||||
double u, v, r2, normal, z;
|
||||
do
|
||||
@@ -686,3 +686,104 @@ double LogNormalVariable::GetSingleValue(double sigma,double mu)
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
|
||||
#ifdef RUN_SELF_TESTS
|
||||
#include "test.h"
|
||||
#include <vector>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
|
||||
class RandomVariableTest : public Test
|
||||
{
|
||||
public:
|
||||
RandomVariableTest () : Test ("RandomVariable") {}
|
||||
virtual bool RunTests (void)
|
||||
{
|
||||
bool ok = true;
|
||||
const double desired_mean = 1.0;
|
||||
const double desired_stddev = 1.0;
|
||||
double tmp = log (1 + (desired_stddev/desired_mean)*(desired_stddev/desired_mean));
|
||||
double sigma = sqrt (tmp);
|
||||
double mu = log (desired_mean) - 0.5*tmp;
|
||||
|
||||
// Test a custom lognormal instance
|
||||
{
|
||||
LogNormalVariable lognormal (mu, sigma);
|
||||
vector<double> samples;
|
||||
const int NSAMPLES = 10000;
|
||||
double sum = 0;
|
||||
for (int n = NSAMPLES; n; --n)
|
||||
{
|
||||
double value = lognormal.GetValue ();
|
||||
sum += value;
|
||||
samples.push_back (value);
|
||||
}
|
||||
double obtained_mean = sum / NSAMPLES;
|
||||
sum = 0;
|
||||
for (vector<double>::iterator iter = samples.begin (); iter != samples.end (); iter++)
|
||||
{
|
||||
double tmp = (*iter - obtained_mean);
|
||||
sum += tmp*tmp;
|
||||
}
|
||||
double obtained_stddev = sqrt (sum / (NSAMPLES - 1));
|
||||
|
||||
if (not (obtained_mean/desired_mean > 0.90 and obtained_mean/desired_mean < 1.10))
|
||||
{
|
||||
ok = false;
|
||||
Failure () << "Obtained lognormal mean value " << obtained_mean << ", expected " << desired_mean << std::endl;
|
||||
}
|
||||
|
||||
if (not (obtained_stddev/desired_stddev > 0.90 and obtained_stddev/desired_stddev < 1.10))
|
||||
{
|
||||
ok = false;
|
||||
Failure () << "Obtained lognormal stddev value " << obtained_stddev <<
|
||||
", expected " << desired_stddev << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Test GetSingleValue
|
||||
{
|
||||
vector<double> samples;
|
||||
const int NSAMPLES = 10000;
|
||||
double sum = 0;
|
||||
for (int n = NSAMPLES; n; --n)
|
||||
{
|
||||
double value = LogNormalVariable::GetSingleValue (mu, sigma);
|
||||
sum += value;
|
||||
samples.push_back (value);
|
||||
}
|
||||
double obtained_mean = sum / NSAMPLES;
|
||||
sum = 0;
|
||||
for (vector<double>::iterator iter = samples.begin (); iter != samples.end (); iter++)
|
||||
{
|
||||
double tmp = (*iter - obtained_mean);
|
||||
sum += tmp*tmp;
|
||||
}
|
||||
double obtained_stddev = sqrt (sum / (NSAMPLES - 1));
|
||||
|
||||
if (not (obtained_mean/desired_mean > 0.90 and obtained_mean/desired_mean < 1.10))
|
||||
{
|
||||
ok = false;
|
||||
Failure () << "Obtained LogNormalVariable::GetSingleValue mean value " << obtained_mean
|
||||
<< ", expected " << desired_mean << std::endl;
|
||||
}
|
||||
|
||||
if (not (obtained_stddev/desired_stddev > 0.90 and obtained_stddev/desired_stddev < 1.10))
|
||||
{
|
||||
ok = false;
|
||||
Failure () << "Obtained LogNormalVariable::GetSingleValue stddev value " << obtained_stddev <<
|
||||
", expected " << desired_stddev << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static RandomVariableTest g_random_variable_tests;
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
#endif /* RUN_SELF_TESTS */
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* \defgroup randomvariable Random Variable Distributions
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#include "reference-list.h"
|
||||
#include "test.h"
|
||||
|
||||
#ifdef RUN_SELF_TESTS
|
||||
|
||||
#define noREFTEST_DEBUG 1
|
||||
|
||||
#ifdef REFTEST_DEBUG
|
||||
#include <iostream>
|
||||
#define TRACE(x) \
|
||||
std::cout << x << std::endl;
|
||||
#else
|
||||
#define TRACE(x)
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
class A {
|
||||
public:
|
||||
A () {
|
||||
TRACE ("constructor");
|
||||
}
|
||||
~A () {
|
||||
TRACE ("destructor");
|
||||
}
|
||||
void Trace (void) {
|
||||
TRACE ("trace");
|
||||
}
|
||||
};
|
||||
|
||||
class RefTest : public ns3::Test {
|
||||
public:
|
||||
RefTest ();
|
||||
virtual bool RunTests (void);
|
||||
private:
|
||||
void OneTest (ns3::ReferenceList<A *>);
|
||||
};
|
||||
|
||||
RefTest::RefTest ()
|
||||
: ns3::Test ("ReferenceList")
|
||||
{}
|
||||
|
||||
void
|
||||
RefTest::OneTest (ns3::ReferenceList<A *> a)
|
||||
{
|
||||
a->Trace ();
|
||||
}
|
||||
|
||||
bool
|
||||
RefTest::RunTests (void)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
{
|
||||
ns3::ReferenceList<A *> tmp;
|
||||
{
|
||||
ns3::ReferenceList<A *> a (new A ());
|
||||
|
||||
OneTest (a);
|
||||
tmp = a;
|
||||
OneTest (tmp);
|
||||
a = tmp;
|
||||
OneTest (a);
|
||||
TRACE ("leave inner scope");
|
||||
}
|
||||
OneTest (tmp);
|
||||
TRACE ("leave outer scope");
|
||||
}
|
||||
|
||||
{
|
||||
ns3::ReferenceList<A *> tmp;
|
||||
}
|
||||
|
||||
{
|
||||
ns3::ReferenceList<A *> tmp (new A ());
|
||||
}
|
||||
|
||||
{
|
||||
ns3::ReferenceList<A *> tmp;
|
||||
tmp.Set (new A ());
|
||||
}
|
||||
|
||||
{
|
||||
TRACE ("test assignement");
|
||||
ns3::ReferenceList<A *> a0 (new A ());
|
||||
ns3::ReferenceList<A *> a1 (new A ());
|
||||
a0 = a1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
static RefTest gRefTest = RefTest ();
|
||||
|
||||
}; // namespace
|
||||
|
||||
#endif /* RUN_SELF_TESTS */
|
||||
@@ -1,118 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2006 INRIA
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef REFERENCE_LIST_H
|
||||
#define REFERENCE_LIST_H
|
||||
|
||||
/* This is a reference list implementation. The technique underlying
|
||||
* this code was first described in 1995 by Risto Lankinen on Usenet
|
||||
* but I have never been able to find his original posting. Instead,
|
||||
* this code is based on the description of the technique found in
|
||||
* "Modern C++ design" by Andrei Alexandrescu in chapter 7.
|
||||
*/
|
||||
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
template <typename OBJ_PTR>
|
||||
class ReferenceList;
|
||||
|
||||
template <typename OBJ_PTR>
|
||||
class ReferenceList {
|
||||
public:
|
||||
ReferenceList ()
|
||||
: m_objPtr (),
|
||||
m_prev (),
|
||||
m_next ()
|
||||
{
|
||||
m_prev = this;
|
||||
m_next = this;
|
||||
}
|
||||
ReferenceList (ReferenceList &o)
|
||||
: m_objPtr (),
|
||||
m_prev (),
|
||||
m_next ()
|
||||
{
|
||||
m_prev = this;
|
||||
m_next = this;
|
||||
InsertSelfInOther (o);
|
||||
}
|
||||
ReferenceList (ReferenceList const&o)
|
||||
: m_objPtr (),
|
||||
m_prev (),
|
||||
m_next ()
|
||||
{
|
||||
m_prev = this;
|
||||
m_next = this;
|
||||
InsertSelfInOther (o);
|
||||
}
|
||||
ReferenceList (OBJ_PTR const &objPtr)
|
||||
: m_objPtr (objPtr),
|
||||
m_prev (),
|
||||
m_next ()
|
||||
{
|
||||
m_prev = this;
|
||||
m_next = this;
|
||||
}
|
||||
~ReferenceList () {
|
||||
RemoveFromList ();
|
||||
}
|
||||
ReferenceList & operator= (ReferenceList const&o) {
|
||||
RemoveFromList ();
|
||||
InsertSelfInOther (o);
|
||||
return *this;
|
||||
}
|
||||
OBJ_PTR operator-> () const {
|
||||
return m_objPtr;
|
||||
}
|
||||
void Set (OBJ_PTR objPtr) {
|
||||
RemoveFromList ();
|
||||
m_objPtr = objPtr;
|
||||
}
|
||||
OBJ_PTR Get (void) const {
|
||||
// explicit conversion to raw pointer type.
|
||||
return m_objPtr;
|
||||
}
|
||||
private:
|
||||
void InsertSelfInOther (ReferenceList const&o) {
|
||||
m_prev = &o;
|
||||
m_next = o.m_next;
|
||||
m_next->m_prev = this;
|
||||
o.m_next = this;
|
||||
m_objPtr = o.m_objPtr;
|
||||
}
|
||||
void RemoveFromList (void) {
|
||||
if (m_prev == this)
|
||||
{
|
||||
//NS_ASSERT (m_next == this);
|
||||
delete m_objPtr;
|
||||
m_objPtr = OBJ_PTR ();
|
||||
}
|
||||
m_prev->m_next = m_next;
|
||||
m_next->m_prev = m_prev;
|
||||
}
|
||||
OBJ_PTR m_objPtr;
|
||||
mutable ReferenceList const*m_prev;
|
||||
mutable ReferenceList const*m_next;
|
||||
};
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
#endif /* REFERENCE_LIST_H */
|
||||
@@ -20,6 +20,7 @@
|
||||
#ifndef RNGSTREAM_H
|
||||
#define RNGSTREAM_H
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace ns3{
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@ namespace ns3 {
|
||||
|
||||
class SystemWallClockMsPrivate {
|
||||
public:
|
||||
void start (void);
|
||||
unsigned long long end (void);
|
||||
void Start (void);
|
||||
unsigned long long End (void);
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ def build(bld):
|
||||
core.name = 'ns3-core'
|
||||
core.target = core.name
|
||||
core.source = [
|
||||
'reference-list-test.cc',
|
||||
'callback-test.cc',
|
||||
'debug.cc',
|
||||
'assert.cc',
|
||||
@@ -53,7 +52,6 @@ def build(bld):
|
||||
headers = bld.create_obj('ns3header')
|
||||
headers.source = [
|
||||
'system-wall-clock-ms.h',
|
||||
'reference-list.h',
|
||||
'callback.h',
|
||||
'ptr.h',
|
||||
'object.h',
|
||||
|
||||
@@ -30,7 +30,7 @@ UdpSocket::UdpSocket (Ptr<INode> node, Ptr<Udp> udp)
|
||||
: m_endPoint (0),
|
||||
m_node (node),
|
||||
m_udp (udp),
|
||||
m_errno (ENOTERROR),
|
||||
m_errno (ERROR_NOTERROR),
|
||||
m_shutdownSend (false),
|
||||
m_shutdownRecv (false),
|
||||
m_connected (false)
|
||||
@@ -154,7 +154,7 @@ UdpSocket::DoAccept(ns3::Callback<bool, Ptr<Socket>, const Ipv4Address&, uint16_
|
||||
ns3::Callback<void, Ptr<Socket> > closeRequested)
|
||||
{
|
||||
// calling accept on a udp socket is a programming error.
|
||||
m_errno = EOPNOTSUPP;
|
||||
m_errno = ERROR_OPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
int
|
||||
@@ -164,7 +164,7 @@ UdpSocket::DoSend (const uint8_t* buffer,
|
||||
{
|
||||
if (!m_connected)
|
||||
{
|
||||
m_errno = ENOTCONN;
|
||||
m_errno = ERROR_NOTCONN;
|
||||
return -1;
|
||||
}
|
||||
Packet p;
|
||||
@@ -193,7 +193,7 @@ UdpSocket::DoSendPacketTo (const Packet &p, Ipv4Address daddr, uint16_t dport,
|
||||
}
|
||||
if (m_shutdownSend)
|
||||
{
|
||||
m_errno = ESHUTDOWN;
|
||||
m_errno = ERROR_SHUTDOWN;
|
||||
return -1;
|
||||
}
|
||||
m_udp->Send (p, m_endPoint->GetLocalAddress (), daddr,
|
||||
@@ -213,7 +213,7 @@ UdpSocket::DoSendTo(const Ipv4Address &address,
|
||||
{
|
||||
if (m_connected)
|
||||
{
|
||||
m_errno = EISCONN;
|
||||
m_errno = ERROR_ISCONN;
|
||||
return -1;
|
||||
}
|
||||
Packet p;
|
||||
|
||||
@@ -46,13 +46,13 @@ public:
|
||||
virtual ~Socket();
|
||||
|
||||
enum SocketErrno {
|
||||
ENOTERROR,
|
||||
EISCONN,
|
||||
ENOTCONN,
|
||||
EMSGSIZE,
|
||||
EAGAIN,
|
||||
ESHUTDOWN,
|
||||
EOPNOTSUPP,
|
||||
ERROR_NOTERROR,
|
||||
ERROR_ISCONN,
|
||||
ERROR_NOTCONN,
|
||||
ERROR_MSGSIZE,
|
||||
ERROR_AGAIN,
|
||||
ERROR_SHUTDOWN,
|
||||
ERROR_OPNOTSUPP,
|
||||
SOCKET_ERRNO_LAST
|
||||
};
|
||||
|
||||
|
||||
@@ -26,13 +26,13 @@ namespace ns3 {
|
||||
|
||||
EventId::EventId ()
|
||||
: m_eventImpl (0),
|
||||
m_ns (0),
|
||||
m_ts (0),
|
||||
m_uid (0)
|
||||
{}
|
||||
|
||||
EventId::EventId (EventImpl *impl, uint64_t ns, uint32_t uid)
|
||||
EventId::EventId (EventImpl *impl, uint64_t ts, uint32_t uid)
|
||||
: m_eventImpl (impl),
|
||||
m_ns (ns),
|
||||
m_ts (ts),
|
||||
m_uid (uid)
|
||||
{}
|
||||
void
|
||||
@@ -60,9 +60,9 @@ EventId::GetEventImpl (void) const
|
||||
return m_eventImpl;
|
||||
}
|
||||
uint64_t
|
||||
EventId::GetNs (void) const
|
||||
EventId::GetTs (void) const
|
||||
{
|
||||
return m_ns;
|
||||
return m_ts;
|
||||
}
|
||||
uint32_t
|
||||
EventId::GetUid (void) const
|
||||
|
||||
@@ -33,7 +33,7 @@ class EventImpl;
|
||||
class EventId {
|
||||
public:
|
||||
EventId ();
|
||||
EventId (EventImpl *impl, uint64_t ns, uint32_t uid);
|
||||
EventId (EventImpl *impl, uint64_t ts, uint32_t uid);
|
||||
/**
|
||||
* This method is syntactic sugar for the ns3::Simulator::cancel
|
||||
* method.
|
||||
@@ -52,11 +52,11 @@ public:
|
||||
* subclasses of the Scheduler base class.
|
||||
*/
|
||||
EventImpl *GetEventImpl (void) const;
|
||||
uint64_t GetNs (void) const;
|
||||
uint64_t GetTs (void) const;
|
||||
uint32_t GetUid (void) const;
|
||||
private:
|
||||
EventImpl *m_eventImpl;
|
||||
uint64_t m_ns;
|
||||
uint64_t m_ts;
|
||||
uint32_t m_uid;
|
||||
};
|
||||
|
||||
|
||||
@@ -22,12 +22,42 @@
|
||||
#define TIME_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include "ns3/assert.h"
|
||||
#include <ostream>
|
||||
#include "high-precision.h"
|
||||
#include "cairo-wideint-private.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
namespace TimeStepPrecision {
|
||||
|
||||
enum precision_t {
|
||||
S = 0,
|
||||
MS = 3,
|
||||
US = 6,
|
||||
NS = 9,
|
||||
PS = 12,
|
||||
FS = 15
|
||||
};
|
||||
/**
|
||||
* \param precision the new precision to use
|
||||
*
|
||||
* This should be invoked before any Time object
|
||||
* is created. i.e., it should be invoked at the very start
|
||||
* of every simulation. The unit specified by this method
|
||||
* is used as the unit of the internal simulation time
|
||||
* which is stored as a 64 bit integer.
|
||||
*/
|
||||
void Set (precision_t precision);
|
||||
/**
|
||||
* \returns the currently-used time precision.
|
||||
*/
|
||||
precision_t Get (void);
|
||||
|
||||
} // namespace TimeStepPrecision
|
||||
|
||||
|
||||
/**
|
||||
* \brief keep track of time unit.
|
||||
*
|
||||
@@ -235,6 +265,9 @@ TimeUnit<N1+N2> operator * (TimeUnit<N1> const &lhs, TimeUnit<N2> const &rhs)
|
||||
{
|
||||
HighPrecision retval = lhs.GetHighPrecision ();
|
||||
retval.Mul (rhs.GetHighPrecision ());
|
||||
// std::cout << lhs.GetHighPrecision().GetInteger() << " * "
|
||||
// << rhs.GetHighPrecision().GetInteger()
|
||||
// << " = " << retval.GetInteger() << std::endl;
|
||||
return TimeUnit<N1+N2> (retval);
|
||||
}
|
||||
template <int N1, int N2>
|
||||
@@ -316,6 +349,8 @@ public:
|
||||
* - ms (milliseconds)
|
||||
* - us (microseconds)
|
||||
* - ns (nanoseconds)
|
||||
* - ps (picoseconds)
|
||||
* - fs (femtoseconds)
|
||||
*
|
||||
* There can be no white space between the numerical portion
|
||||
* and the units. Any otherwise malformed string causes a fatal error to
|
||||
@@ -328,11 +363,12 @@ public:
|
||||
* instance.
|
||||
*/
|
||||
double GetSeconds (void) const;
|
||||
|
||||
/**
|
||||
* \returns an approximation in milliseconds of the time stored in this
|
||||
* instance.
|
||||
*/
|
||||
int32_t GetMilliSeconds (void) const;
|
||||
*/
|
||||
int64_t GetMilliSeconds (void) const;
|
||||
/**
|
||||
* \returns an approximation in microseconds of the time stored in this
|
||||
* instance.
|
||||
@@ -343,6 +379,21 @@ public:
|
||||
* instance.
|
||||
*/
|
||||
int64_t GetNanoSeconds (void) const;
|
||||
/**
|
||||
* \returns an approximation in picoseconds of the time stored in this
|
||||
* instance.
|
||||
*/
|
||||
int64_t GetPicoSeconds (void) const;
|
||||
/**
|
||||
* \returns an approximation in femtoseconds of the time stored in this
|
||||
* instance.
|
||||
*/
|
||||
int64_t GetFemtoSeconds (void) const;
|
||||
/**
|
||||
* \returns an approximation of the time stored in this
|
||||
* instance in the units specified in m_tsPrecision.
|
||||
*/
|
||||
int64_t GetTimeStep (void) const;
|
||||
|
||||
// -*- The rest is the the same as in the generic template class -*-
|
||||
public:
|
||||
@@ -378,8 +429,18 @@ public:
|
||||
HighPrecision *PeekHighPrecision (void) {
|
||||
return &m_data;
|
||||
}
|
||||
|
||||
static uint64_t UnitsToTimestep (uint64_t unitValue,
|
||||
uint64_t unitFactor);
|
||||
private:
|
||||
HighPrecision m_data;
|
||||
|
||||
/*
|
||||
* \Returns the value of time_value in units of unitPrec. time_value
|
||||
* must be specified in timestep units (which are the same as the
|
||||
* m_tsPrecision units
|
||||
*/
|
||||
int64_t ConvertToUnits (int64_t timeValue, uint64_t unitFactor) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -387,13 +448,17 @@ private:
|
||||
*
|
||||
* This is an instance of type ns3::TimeUnit<1>: it is
|
||||
* the return value of the ns3::Simulator::Now method
|
||||
* and is needed for the Simulator::Schedule methods
|
||||
* and is needed for the Simulator::Schedule methods.
|
||||
* The precision of the underlying Time unit can be
|
||||
* changed with calls to TimeStepPrecision::Set.
|
||||
*
|
||||
* Time instances can be created through any of the following classes:
|
||||
* Time instances can be created through any of the following functions:
|
||||
* - ns3::Seconds
|
||||
* - ns3::MilliSeconds
|
||||
* - ns3::MicroSeconds
|
||||
* - ns3::NanoSeconds
|
||||
* - ns3::PicoSeconds
|
||||
* - ns3::FemtoSeconds
|
||||
* - ns3::Now
|
||||
*
|
||||
* Time instances can be added, substracted, multipled and divided using
|
||||
@@ -417,7 +482,7 @@ private:
|
||||
* instance.
|
||||
*
|
||||
* \code
|
||||
* int32_t GetMilliSeconds (void) const;
|
||||
* int64_t GetMilliSeconds (void) const;
|
||||
* \endcode
|
||||
* returns an approximation in milliseconds of the time stored in this
|
||||
* instance.
|
||||
@@ -433,6 +498,18 @@ private:
|
||||
* \endcode
|
||||
* returns an approximation in nanoseconds of the time stored in this
|
||||
* instance.
|
||||
*
|
||||
* \code
|
||||
* int64_t GetPicoSeconds (void) const;
|
||||
* \endcode
|
||||
* returns an approximation in picoseconds of the time stored in this
|
||||
* instance.
|
||||
*
|
||||
* \code
|
||||
* int64_t GetFemtoSeconds (void) const;
|
||||
* \endcode
|
||||
* returns an approximation in femtoseconds of the time stored in this
|
||||
* instance.
|
||||
*/
|
||||
typedef TimeUnit<1> Time;
|
||||
|
||||
@@ -459,7 +536,7 @@ Time Seconds (double seconds);
|
||||
* Simulator::Schedule (MilliSeconds (5), ...);
|
||||
* \endcode
|
||||
*/
|
||||
Time MilliSeconds (uint32_t ms);
|
||||
Time MilliSeconds (uint64_t ms);
|
||||
/**
|
||||
* \brief create ns3::Time instances in units of microseconds.
|
||||
*
|
||||
@@ -480,20 +557,29 @@ Time MicroSeconds (uint64_t us);
|
||||
* \endcode
|
||||
*/
|
||||
Time NanoSeconds (uint64_t ns);
|
||||
|
||||
/**
|
||||
* \brief create an ns3::Time instance which contains the
|
||||
* current simulation time.
|
||||
* \brief create ns3::Time instances in units of picoseconds.
|
||||
*
|
||||
* This is really a shortcut for the ns3::Simulator::Now method.
|
||||
* It is typically used as shown below to schedule an event
|
||||
* which expires at the absolute time "2 seconds":
|
||||
* For example:
|
||||
* \code
|
||||
* Simulator::Schedule (Seconds (2.0) - Now (), &my_function);
|
||||
* Time t = PicoSeconds (2);
|
||||
* Simulator::Schedule (PicoSeconds (5), ...);
|
||||
* \endcode
|
||||
*/
|
||||
Time Now (void);
|
||||
Time PicoSeconds (uint64_t ps);
|
||||
/**
|
||||
* \brief create ns3::Time instances in units of femtoseconds.
|
||||
*
|
||||
* For example:
|
||||
* \code
|
||||
* Time t = FemtoSeconds (2);
|
||||
* Simulator::Schedule (FemtoSeconds (5), ...);
|
||||
* \endcode
|
||||
*/
|
||||
Time FemtoSeconds (uint64_t fs);
|
||||
|
||||
// internal function not publicly documented
|
||||
Time TimeStep (uint64_t ts);
|
||||
|
||||
// Explicit instatiation of the TimeUnit template for N=0, with a few
|
||||
// additional methods that should not be available for N != 0
|
||||
@@ -539,6 +625,7 @@ public:
|
||||
HighPrecision *PeekHighPrecision (void) {
|
||||
return &m_data;
|
||||
}
|
||||
|
||||
private:
|
||||
HighPrecision m_data;
|
||||
};
|
||||
|
||||
@@ -88,7 +88,7 @@ SchedulerFactory::Add (const SchedulerFactory *factory,
|
||||
StringEnumDefaultValue *
|
||||
SchedulerFactory::GetDefault (void)
|
||||
{
|
||||
static StringEnumDefaultValue value ("scheduler", "Event Scheduler algorithm");
|
||||
static StringEnumDefaultValue value ("Scheduler", "Event Scheduler algorithm");
|
||||
return &value;
|
||||
}
|
||||
|
||||
|
||||
@@ -139,11 +139,11 @@ SchedulerHeap::Exch (uint32_t a, uint32_t b)
|
||||
bool
|
||||
SchedulerHeap::IsLowerStrictly (Scheduler::EventKey const*a, Scheduler::EventKey const*b) const
|
||||
{
|
||||
if (a->m_ns < b->m_ns)
|
||||
if (a->m_ts < b->m_ts)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (a->m_ns > b->m_ns)
|
||||
else if (a->m_ts > b->m_ts)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -227,7 +227,7 @@ SchedulerHeap::RealInsert (EventImpl *event, Scheduler::EventKey key)
|
||||
{
|
||||
m_heap.push_back (std::make_pair (event, key));
|
||||
BottomUp ();
|
||||
return EventId (event, key.m_ns, key.m_uid);
|
||||
return EventId (event, key.m_ts, key.m_uid);
|
||||
}
|
||||
|
||||
EventImpl *
|
||||
@@ -252,7 +252,7 @@ SchedulerHeap::RealRemoveNext (void)
|
||||
EventImpl *
|
||||
SchedulerHeap::RealRemove (EventId id, Scheduler::EventKey *key)
|
||||
{
|
||||
key->m_ns = id.GetNs ();
|
||||
key->m_ts = id.GetTs ();
|
||||
key->m_uid = id.GetUid ();
|
||||
for (uint32_t i = 1; i < m_heap.size (); i++)
|
||||
{
|
||||
|
||||
@@ -33,7 +33,7 @@ static class SchedulerListFactory : public SchedulerFactory
|
||||
public:
|
||||
SchedulerListFactory ()
|
||||
{
|
||||
SchedulerFactory::AddDefault (this, "list");
|
||||
SchedulerFactory::AddDefault (this, "List");
|
||||
}
|
||||
private:
|
||||
virtual Scheduler *DoCreate (void) const
|
||||
@@ -51,11 +51,11 @@ SchedulerList::~SchedulerList ()
|
||||
bool
|
||||
SchedulerList::IsLower (Scheduler::EventKey const*a, Scheduler::EventKey const*b) const
|
||||
{
|
||||
if (a->m_ns < b->m_ns)
|
||||
if (a->m_ts < b->m_ts)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (a->m_ns == b->m_ns &&
|
||||
else if (a->m_ts == b->m_ts &&
|
||||
a->m_uid < b->m_uid)
|
||||
{
|
||||
return true;
|
||||
@@ -74,11 +74,11 @@ SchedulerList::RealInsert (EventImpl *event, Scheduler::EventKey key)
|
||||
if (IsLower (&key, &i->second))
|
||||
{
|
||||
m_events.insert (i, std::make_pair (event, key));
|
||||
return EventId (event, key.m_ns, key.m_uid);
|
||||
return EventId (event, key.m_ts, key.m_uid);
|
||||
}
|
||||
}
|
||||
m_events.push_back (std::make_pair (event, key));
|
||||
return EventId (event, key.m_ns, key.m_uid);
|
||||
return EventId (event, key.m_ts, key.m_uid);
|
||||
}
|
||||
bool
|
||||
SchedulerList::RealIsEmpty (void) const
|
||||
@@ -111,7 +111,7 @@ SchedulerList::RealRemove (EventId id, Scheduler::EventKey *key)
|
||||
{
|
||||
EventImpl *retval = i->first;
|
||||
NS_ASSERT (id.GetEventImpl () == retval);
|
||||
key->m_ns = id.GetNs ();
|
||||
key->m_ts = id.GetTs ();
|
||||
key->m_uid = id.GetUid ();
|
||||
m_events.erase (i);
|
||||
return retval;
|
||||
|
||||
@@ -44,7 +44,7 @@ static class SchedulerMapFactory : public SchedulerFactory
|
||||
public:
|
||||
SchedulerMapFactory ()
|
||||
{
|
||||
SchedulerFactory::Add (this, "map");
|
||||
SchedulerFactory::Add (this, "Map");
|
||||
}
|
||||
private:
|
||||
virtual Scheduler *DoCreate (void) const
|
||||
@@ -67,11 +67,11 @@ SchedulerMap::~SchedulerMap ()
|
||||
bool
|
||||
SchedulerMap::EventKeyCompare::operator () (struct EventKey const&a, struct EventKey const&b)
|
||||
{
|
||||
if (a.m_ns < b.m_ns)
|
||||
if (a.m_ts < b.m_ts)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (a.m_ns > b.m_ns)
|
||||
else if (a.m_ts > b.m_ts)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -93,7 +93,7 @@ SchedulerMap::RealInsert (EventImpl *event, Scheduler::EventKey key)
|
||||
std::pair<EventMapI,bool> result;
|
||||
result = m_list.insert (std::make_pair (key, event));
|
||||
NS_ASSERT (result.second);
|
||||
return EventId (event, key.m_ns, key.m_uid);
|
||||
return EventId (event, key.m_ts, key.m_uid);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -125,7 +125,7 @@ SchedulerMap::RealRemoveNext (void)
|
||||
EventImpl *
|
||||
SchedulerMap::RealRemove (EventId id, Scheduler::EventKey *key)
|
||||
{
|
||||
key->m_ns = id.GetNs ();
|
||||
key->m_ts = id.GetTs ();
|
||||
key->m_uid = id.GetUid ();
|
||||
EventMapI i = m_list.find (*key);
|
||||
EventImpl *retval = i->second;
|
||||
|
||||
@@ -55,7 +55,7 @@ class EventImpl;
|
||||
class Scheduler {
|
||||
public:
|
||||
struct EventKey {
|
||||
uint64_t m_ns;
|
||||
uint64_t m_ts;
|
||||
uint32_t m_uid;
|
||||
};
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
|
||||
private:
|
||||
void ProcessOneEvent (void);
|
||||
uint64_t NextNs (void) const;
|
||||
uint64_t NextTs (void) const;
|
||||
|
||||
typedef std::list<std::pair<EventImpl *,uint32_t> > Events;
|
||||
Events m_destroy;
|
||||
@@ -81,7 +81,7 @@ private:
|
||||
Scheduler *m_events;
|
||||
uint32_t m_uid;
|
||||
uint32_t m_currentUid;
|
||||
uint64_t m_currentNs;
|
||||
uint64_t m_currentTs;
|
||||
std::ofstream m_log;
|
||||
std::ifstream m_inputLog;
|
||||
bool m_logEnable;
|
||||
@@ -103,7 +103,7 @@ SimulatorPrivate::SimulatorPrivate (Scheduler *events)
|
||||
// before ::Run is entered, the m_currentUid will be zero
|
||||
m_currentUid = 0;
|
||||
m_logEnable = false;
|
||||
m_currentNs = 0;
|
||||
m_currentTs = 0;
|
||||
m_unscheduledEvents = 0;
|
||||
}
|
||||
|
||||
@@ -136,15 +136,15 @@ SimulatorPrivate::ProcessOneEvent (void)
|
||||
Scheduler::EventKey nextKey = m_events->PeekNextKey ();
|
||||
m_events->RemoveNext ();
|
||||
|
||||
NS_ASSERT (nextKey.m_ns >= m_currentNs);
|
||||
NS_ASSERT (nextKey.m_ts >= m_currentTs);
|
||||
--m_unscheduledEvents;
|
||||
|
||||
TRACE ("handle " << nextEv);
|
||||
m_currentNs = nextKey.m_ns;
|
||||
m_currentTs = nextKey.m_ts;
|
||||
m_currentUid = nextKey.m_uid;
|
||||
if (m_logEnable)
|
||||
{
|
||||
m_log << "e "<<nextKey.m_uid << " " << nextKey.m_ns << std::endl;
|
||||
m_log << "e "<<nextKey.m_uid << " " << nextKey.m_ts << std::endl;
|
||||
}
|
||||
nextEv->Invoke ();
|
||||
delete nextEv;
|
||||
@@ -156,25 +156,24 @@ SimulatorPrivate::IsFinished (void) const
|
||||
return m_events->IsEmpty ();
|
||||
}
|
||||
uint64_t
|
||||
SimulatorPrivate::NextNs (void) const
|
||||
SimulatorPrivate::NextTs (void) const
|
||||
{
|
||||
NS_ASSERT (!m_events->IsEmpty ());
|
||||
Scheduler::EventKey nextKey = m_events->PeekNextKey ();
|
||||
return nextKey.m_ns;
|
||||
return nextKey.m_ts;
|
||||
}
|
||||
Time
|
||||
SimulatorPrivate::Next (void) const
|
||||
{
|
||||
return NanoSeconds (NextNs ());
|
||||
return TimeStep (NextTs ());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SimulatorPrivate::Run (void)
|
||||
{
|
||||
|
||||
while (!m_events->IsEmpty () && !m_stop &&
|
||||
(m_stopAt == 0 || m_stopAt > NextNs ()))
|
||||
(m_stopAt == 0 || m_stopAt > NextTs ()))
|
||||
{
|
||||
ProcessOneEvent ();
|
||||
}
|
||||
@@ -196,19 +195,19 @@ void
|
||||
SimulatorPrivate::StopAt (Time const &at)
|
||||
{
|
||||
NS_ASSERT (at.IsPositive ());
|
||||
m_stopAt = at.GetNanoSeconds ();
|
||||
m_stopAt = at.GetTimeStep ();
|
||||
}
|
||||
EventId
|
||||
SimulatorPrivate::Schedule (Time const &time, EventImpl *event)
|
||||
{
|
||||
NS_ASSERT (time.IsPositive ());
|
||||
NS_ASSERT (time >= NanoSeconds (m_currentNs));
|
||||
uint64_t ns = (uint64_t) time.GetNanoSeconds ();
|
||||
Scheduler::EventKey key = {ns, m_uid};
|
||||
NS_ASSERT (time >= TimeStep (m_currentTs));
|
||||
uint64_t ts = (uint64_t) time.GetTimeStep ();
|
||||
Scheduler::EventKey key = {ts, m_uid};
|
||||
if (m_logEnable)
|
||||
{
|
||||
m_log << "i "<<m_currentUid<<" "<<m_currentNs<<" "
|
||||
<<m_uid<<" "<<time.GetNanoSeconds () << std::endl;
|
||||
m_log << "i "<<m_currentUid<<" "<<m_currentTs<<" "
|
||||
<<m_uid<<" "<<time.GetTimeStep () << std::endl;
|
||||
}
|
||||
m_uid++;
|
||||
++m_unscheduledEvents;
|
||||
@@ -217,12 +216,12 @@ SimulatorPrivate::Schedule (Time const &time, EventImpl *event)
|
||||
void
|
||||
SimulatorPrivate::ScheduleNow (EventImpl *event)
|
||||
{
|
||||
uint64_t ns = m_currentNs;
|
||||
Scheduler::EventKey key = {ns, m_uid};
|
||||
uint64_t ts = m_currentTs;
|
||||
Scheduler::EventKey key = {ts, m_uid};
|
||||
if (m_logEnable)
|
||||
{
|
||||
m_log << "i "<<m_currentUid<<" "<<m_currentNs<<" "
|
||||
<<m_uid<<" "<<ns << std::endl;
|
||||
m_log << "i "<<m_currentUid<<" "<<m_currentTs<<" "
|
||||
<<m_uid<<" "<<ts << std::endl;
|
||||
}
|
||||
m_uid++;
|
||||
++m_unscheduledEvents;
|
||||
@@ -234,7 +233,7 @@ SimulatorPrivate::ScheduleDestroy (EventImpl *event)
|
||||
m_destroy.push_back (std::make_pair (event, m_uid));
|
||||
if (m_logEnable)
|
||||
{
|
||||
m_log << "id " << m_currentUid << " " << Now ().GetNanoSeconds () << " "
|
||||
m_log << "id " << m_currentUid << " " << Now ().GetTimeStep () << " "
|
||||
<< m_uid << std::endl;
|
||||
}
|
||||
m_uid++;
|
||||
@@ -243,7 +242,7 @@ SimulatorPrivate::ScheduleDestroy (EventImpl *event)
|
||||
Time
|
||||
SimulatorPrivate::Now (void) const
|
||||
{
|
||||
return NanoSeconds (m_currentNs);
|
||||
return TimeStep (m_currentTs);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -254,8 +253,8 @@ SimulatorPrivate::Remove (EventId ev)
|
||||
delete impl;
|
||||
if (m_logEnable)
|
||||
{
|
||||
m_log << "r " << m_currentUid << " " << m_currentNs << " "
|
||||
<< key.m_uid << " " << key.m_ns << std::endl;
|
||||
m_log << "r " << m_currentUid << " " << m_currentTs << " "
|
||||
<< key.m_uid << " " << key.m_ts << std::endl;
|
||||
}
|
||||
--m_unscheduledEvents;
|
||||
}
|
||||
@@ -270,8 +269,8 @@ bool
|
||||
SimulatorPrivate::IsExpired (EventId ev)
|
||||
{
|
||||
if (ev.GetEventImpl () == 0 ||
|
||||
ev.GetNs () < m_currentNs ||
|
||||
(ev.GetNs () == m_currentNs &&
|
||||
ev.GetTs () < m_currentTs ||
|
||||
(ev.GetTs () == m_currentTs &&
|
||||
ev.GetUid () <= m_currentUid) ||
|
||||
ev.GetEventImpl ()->IsCancelled ())
|
||||
{
|
||||
@@ -299,20 +298,20 @@ SimulatorPrivate *Simulator::m_priv = 0;
|
||||
|
||||
void Simulator::SetLinkedList (void)
|
||||
{
|
||||
Bind ("scheduler", "list");
|
||||
Bind ("Scheduler", "List");
|
||||
}
|
||||
void Simulator::SetBinaryHeap (void)
|
||||
{
|
||||
Bind ("scheduler", "BinaryHeap");
|
||||
Bind ("Scheduler", "BinaryHeap");
|
||||
}
|
||||
void Simulator::SetStdMap (void)
|
||||
{
|
||||
Bind ("scheduler", "map");
|
||||
Bind ("Scheduler", "Map");
|
||||
}
|
||||
void
|
||||
Simulator::SetExternal (const std::string &external)
|
||||
{
|
||||
Bind ("scheduler", external);
|
||||
Bind ("Scheduler", external);
|
||||
}
|
||||
void Simulator::EnableLogTo (char const *filename)
|
||||
{
|
||||
@@ -444,12 +443,18 @@ Simulator::IsExpired (EventId id)
|
||||
return GetPriv ()->IsExpired (id);
|
||||
}
|
||||
|
||||
Time Now (void)
|
||||
{
|
||||
return Time (Simulator::Now ());
|
||||
}
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
|
||||
#ifdef RUN_SELF_TESTS
|
||||
|
||||
#include "ns3/test.h"
|
||||
#include "ns3/ptr.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
@@ -470,6 +475,9 @@ static void foo5 (int, int, int, int, int)
|
||||
class SimulatorTests : public Test {
|
||||
public:
|
||||
SimulatorTests ();
|
||||
// only here for testing of Ptr<>
|
||||
void Ref (void);
|
||||
void Unref (void);
|
||||
virtual ~SimulatorTests ();
|
||||
virtual bool RunTests (void);
|
||||
private:
|
||||
@@ -498,6 +506,12 @@ SimulatorTests::SimulatorTests ()
|
||||
{}
|
||||
SimulatorTests::~SimulatorTests ()
|
||||
{}
|
||||
void
|
||||
SimulatorTests::Ref (void)
|
||||
{}
|
||||
void
|
||||
SimulatorTests::Unref (void)
|
||||
{}
|
||||
uint64_t
|
||||
SimulatorTests::NowUs (void)
|
||||
{
|
||||
@@ -630,6 +644,12 @@ SimulatorTests::RunTests (void)
|
||||
Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar3, this, 0, 0, 0);
|
||||
Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar4, this, 0, 0, 0, 0);
|
||||
Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar5, this, 0, 0, 0, 0, 0);
|
||||
Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar0, Ptr<SimulatorTests> (this));
|
||||
Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar1, Ptr<SimulatorTests> (this), 0);
|
||||
Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar2, Ptr<SimulatorTests> (this), 0, 0);
|
||||
Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar3, Ptr<SimulatorTests> (this), 0, 0, 0);
|
||||
Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar4, Ptr<SimulatorTests> (this), 0, 0, 0, 0);
|
||||
Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar5, Ptr<SimulatorTests> (this), 0, 0, 0, 0, 0);
|
||||
Simulator::ScheduleNow (&foo0);
|
||||
Simulator::ScheduleNow (&foo1, 0);
|
||||
Simulator::ScheduleNow (&foo2, 0, 0);
|
||||
@@ -642,6 +662,12 @@ SimulatorTests::RunTests (void)
|
||||
Simulator::ScheduleNow (&SimulatorTests::bar3, this, 0, 0, 0);
|
||||
Simulator::ScheduleNow (&SimulatorTests::bar4, this, 0, 0, 0, 0);
|
||||
Simulator::ScheduleNow (&SimulatorTests::bar5, this, 0, 0, 0, 0, 0);
|
||||
Simulator::ScheduleNow (&SimulatorTests::bar0, Ptr<SimulatorTests> (this));
|
||||
Simulator::ScheduleNow (&SimulatorTests::bar1, Ptr<SimulatorTests> (this), 0);
|
||||
Simulator::ScheduleNow (&SimulatorTests::bar2, Ptr<SimulatorTests> (this), 0, 0);
|
||||
Simulator::ScheduleNow (&SimulatorTests::bar3, Ptr<SimulatorTests> (this), 0, 0, 0);
|
||||
Simulator::ScheduleNow (&SimulatorTests::bar4, Ptr<SimulatorTests> (this), 0, 0, 0, 0);
|
||||
Simulator::ScheduleNow (&SimulatorTests::bar5, Ptr<SimulatorTests> (this), 0, 0, 0, 0, 0);
|
||||
Simulator::ScheduleDestroy (&foo0);
|
||||
Simulator::ScheduleDestroy (&foo1, 0);
|
||||
Simulator::ScheduleDestroy (&foo2, 0, 0);
|
||||
@@ -654,6 +680,12 @@ SimulatorTests::RunTests (void)
|
||||
Simulator::ScheduleDestroy (&SimulatorTests::bar3, this, 0, 0, 0);
|
||||
Simulator::ScheduleDestroy (&SimulatorTests::bar4, this, 0, 0, 0, 0);
|
||||
Simulator::ScheduleDestroy (&SimulatorTests::bar5, this, 0, 0, 0, 0, 0);
|
||||
Simulator::ScheduleDestroy (&SimulatorTests::bar0, Ptr<SimulatorTests> (this));
|
||||
Simulator::ScheduleDestroy (&SimulatorTests::bar1, Ptr<SimulatorTests> (this), 0);
|
||||
Simulator::ScheduleDestroy (&SimulatorTests::bar2, Ptr<SimulatorTests> (this), 0, 0);
|
||||
Simulator::ScheduleDestroy (&SimulatorTests::bar3, Ptr<SimulatorTests> (this), 0, 0, 0);
|
||||
Simulator::ScheduleDestroy (&SimulatorTests::bar4, Ptr<SimulatorTests> (this), 0, 0, 0, 0);
|
||||
Simulator::ScheduleDestroy (&SimulatorTests::bar5, Ptr<SimulatorTests> (this), 0, 0, 0, 0, 0);
|
||||
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
|
||||
@@ -37,11 +37,13 @@ class SchedulerFactory;
|
||||
* \brief Control the scheduling of simulation events.
|
||||
*
|
||||
* The internal simulation clock is maintained
|
||||
* as a 64-bit integer in nanosecond units. This means that it is
|
||||
* as a 64-bit integer in a unit specified by the user
|
||||
* through the TimeStepPrecision::Set function. This means that it is
|
||||
* not possible to specify event expiration times with anything better
|
||||
* than nanosecond accuracy. Events whose expiration time is
|
||||
* the same are scheduled in FIFO order: the first event inserted in the
|
||||
* Scheduling queue is scheduled to expire first.
|
||||
* than this user-specified accuracy. Events whose expiration time is
|
||||
* the same modulo this accuracy are scheduled in FIFO order: the
|
||||
* first event inserted in the scheduling queue is scheduled to
|
||||
* expire first.
|
||||
*
|
||||
* A simple example of how to use the Simulator class to schedule events
|
||||
* is shown below:
|
||||
@@ -160,8 +162,8 @@ public:
|
||||
* @param obj the object on which to invoke the member method
|
||||
* @returns an id for the scheduled event.
|
||||
*/
|
||||
template <typename T>
|
||||
static EventId Schedule (Time const &time, void (T::*mem_ptr) (void), T *obj);
|
||||
template <typename T, typename OBJ>
|
||||
static EventId Schedule (Time const &time, void (T::*mem_ptr) (void), OBJ obj);
|
||||
/**
|
||||
* @param time the relative expiration time of the event.
|
||||
* @param mem_ptr member method pointer to invoke
|
||||
@@ -169,8 +171,8 @@ public:
|
||||
* @param a1 the first argument to pass to the invoked method
|
||||
* @returns an id for the scheduled event.
|
||||
*/
|
||||
template <typename T, typename T1>
|
||||
static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1), T* obj, T1 a1);
|
||||
template <typename T, typename OBJ, typename T1>
|
||||
static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1), OBJ obj, T1 a1);
|
||||
/**
|
||||
* @param time the relative expiration time of the event.
|
||||
* @param mem_ptr member method pointer to invoke
|
||||
@@ -179,8 +181,8 @@ public:
|
||||
* @param a2 the second argument to pass to the invoked method
|
||||
* @returns an id for the scheduled event.
|
||||
*/
|
||||
template <typename T, typename T1, typename T2>
|
||||
static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1,T2), T* obj, T1 a1, T2 a2);
|
||||
template <typename T, typename OBJ, typename T1, typename T2>
|
||||
static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2);
|
||||
/**
|
||||
* @param time the relative expiration time of the event.
|
||||
* @param mem_ptr member method pointer to invoke
|
||||
@@ -190,8 +192,8 @@ public:
|
||||
* @param a3 the third argument to pass to the invoked method
|
||||
* @returns an id for the scheduled event.
|
||||
*/
|
||||
template <typename T, typename T1, typename T2, typename T3>
|
||||
static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3), T* obj, T1 a1, T2 a2, T3 a3);
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3>
|
||||
static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3);
|
||||
/**
|
||||
* @param time the relative expiration time of the event.
|
||||
* @param mem_ptr member method pointer to invoke
|
||||
@@ -202,8 +204,8 @@ public:
|
||||
* @param a4 the fourth argument to pass to the invoked method
|
||||
* @returns an id for the scheduled event.
|
||||
*/
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4>
|
||||
static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3,T4), T* obj, T1 a1, T2 a2, T3 a3, T4 a4);
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
|
||||
static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4);
|
||||
/**
|
||||
* @param time the relative expiration time of the event.
|
||||
* @param mem_ptr member method pointer to invoke
|
||||
@@ -215,9 +217,9 @@ public:
|
||||
* @param a5 the fifth argument to pass to the invoked method
|
||||
* @returns an id for the scheduled event.
|
||||
*/
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3,T4,T5), T* obj,
|
||||
T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj,
|
||||
T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
|
||||
/**
|
||||
* @param time the relative expiration time of the event.
|
||||
* @param f the function to invoke
|
||||
@@ -284,23 +286,23 @@ public:
|
||||
* @param mem_ptr member method pointer to invoke
|
||||
* @param obj the object on which to invoke the member method
|
||||
*/
|
||||
template <typename T>
|
||||
static void ScheduleNow (void (T::*mem_ptr) (void), T *obj);
|
||||
template <typename T, typename OBJ>
|
||||
static void ScheduleNow (void (T::*mem_ptr) (void), OBJ obj);
|
||||
/**
|
||||
* @param mem_ptr member method pointer to invoke
|
||||
* @param obj the object on which to invoke the member method
|
||||
* @param a1 the first argument to pass to the invoked method
|
||||
*/
|
||||
template <typename T, typename T1>
|
||||
static void ScheduleNow (void (T::*mem_ptr) (T1), T* obj, T1 a1);
|
||||
template <typename T, typename OBJ, typename T1>
|
||||
static void ScheduleNow (void (T::*mem_ptr) (T1), OBJ obj, T1 a1);
|
||||
/**
|
||||
* @param mem_ptr member method pointer to invoke
|
||||
* @param obj the object on which to invoke the member method
|
||||
* @param a1 the first argument to pass to the invoked method
|
||||
* @param a2 the second argument to pass to the invoked method
|
||||
*/
|
||||
template <typename T, typename T1, typename T2>
|
||||
static void ScheduleNow (void (T::*mem_ptr) (T1,T2), T* obj, T1 a1, T2 a2);
|
||||
template <typename T, typename OBJ, typename T1, typename T2>
|
||||
static void ScheduleNow (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2);
|
||||
/**
|
||||
* @param mem_ptr member method pointer to invoke
|
||||
* @param obj the object on which to invoke the member method
|
||||
@@ -308,8 +310,8 @@ public:
|
||||
* @param a2 the second argument to pass to the invoked method
|
||||
* @param a3 the third argument to pass to the invoked method
|
||||
*/
|
||||
template <typename T, typename T1, typename T2, typename T3>
|
||||
static void ScheduleNow (void (T::*mem_ptr) (T1,T2,T3), T* obj, T1 a1, T2 a2, T3 a3);
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3>
|
||||
static void ScheduleNow (void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3);
|
||||
/**
|
||||
* @param mem_ptr member method pointer to invoke
|
||||
* @param obj the object on which to invoke the member method
|
||||
@@ -318,8 +320,8 @@ public:
|
||||
* @param a3 the third argument to pass to the invoked method
|
||||
* @param a4 the fourth argument to pass to the invoked method
|
||||
*/
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4>
|
||||
static void ScheduleNow (void (T::*mem_ptr) (T1,T2,T3,T4), T* obj,
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
|
||||
static void ScheduleNow (void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj,
|
||||
T1 a1, T2 a2, T3 a3, T4 a4);
|
||||
/**
|
||||
* @param mem_ptr member method pointer to invoke
|
||||
@@ -330,8 +332,8 @@ public:
|
||||
* @param a4 the fourth argument to pass to the invoked method
|
||||
* @param a5 the fifth argument to pass to the invoked method
|
||||
*/
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
static void ScheduleNow (void (T::*mem_ptr) (T1,T2,T3,T4,T5), T* obj,
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
static void ScheduleNow (void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj,
|
||||
T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
|
||||
/**
|
||||
* @param f the function to invoke
|
||||
@@ -388,23 +390,23 @@ public:
|
||||
* @param mem_ptr member method pointer to invoke
|
||||
* @param obj the object on which to invoke the member method
|
||||
*/
|
||||
template <typename T>
|
||||
static void ScheduleDestroy (void (T::*mem_ptr) (void), T *obj);
|
||||
template <typename T, typename OBJ>
|
||||
static void ScheduleDestroy (void (T::*mem_ptr) (void), OBJ obj);
|
||||
/**
|
||||
* @param mem_ptr member method pointer to invoke
|
||||
* @param obj the object on which to invoke the member method
|
||||
* @param a1 the first argument to pass to the invoked method
|
||||
*/
|
||||
template <typename T, typename T1>
|
||||
static void ScheduleDestroy (void (T::*mem_ptr) (T1), T* obj, T1 a1);
|
||||
template <typename T, typename OBJ, typename T1>
|
||||
static void ScheduleDestroy (void (T::*mem_ptr) (T1), OBJ obj, T1 a1);
|
||||
/**
|
||||
* @param mem_ptr member method pointer to invoke
|
||||
* @param obj the object on which to invoke the member method
|
||||
* @param a1 the first argument to pass to the invoked method
|
||||
* @param a2 the second argument to pass to the invoked method
|
||||
*/
|
||||
template <typename T, typename T1, typename T2>
|
||||
static void ScheduleDestroy (void (T::*mem_ptr) (T1,T2), T* obj, T1 a1, T2 a2);
|
||||
template <typename T, typename OBJ, typename T1, typename T2>
|
||||
static void ScheduleDestroy (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2);
|
||||
/**
|
||||
* @param mem_ptr member method pointer to invoke
|
||||
* @param obj the object on which to invoke the member method
|
||||
@@ -412,8 +414,8 @@ public:
|
||||
* @param a2 the second argument to pass to the invoked method
|
||||
* @param a3 the third argument to pass to the invoked method
|
||||
*/
|
||||
template <typename T, typename T1, typename T2, typename T3>
|
||||
static void ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3), T* obj, T1 a1, T2 a2, T3 a3);
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3>
|
||||
static void ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3);
|
||||
/**
|
||||
* @param mem_ptr member method pointer to invoke
|
||||
* @param obj the object on which to invoke the member method
|
||||
@@ -422,9 +424,9 @@ public:
|
||||
* @param a3 the third argument to pass to the invoked method
|
||||
* @param a4 the fourth argument to pass to the invoked method
|
||||
*/
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4>
|
||||
static void ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3,T4), T* obj,
|
||||
T1 a1, T2 a2, T3 a3, T4 a4);
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
|
||||
static void ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj,
|
||||
T1 a1, T2 a2, T3 a3, T4 a4);
|
||||
/**
|
||||
* @param mem_ptr member method pointer to invoke
|
||||
* @param obj the object on which to invoke the member method
|
||||
@@ -434,9 +436,9 @@ public:
|
||||
* @param a4 the fourth argument to pass to the invoked method
|
||||
* @param a5 the fifth argument to pass to the invoked method
|
||||
*/
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
static void ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3,T4,T5), T* obj,
|
||||
T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
static void ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj,
|
||||
T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
|
||||
/**
|
||||
* @param f the function to invoke
|
||||
*/
|
||||
@@ -527,19 +529,19 @@ public:
|
||||
private:
|
||||
Simulator ();
|
||||
~Simulator ();
|
||||
template <typename T>
|
||||
static EventImpl *MakeEvent (void (T::*mem_ptr) (void), T *obj);
|
||||
template <typename T, typename T1>
|
||||
static EventImpl *MakeEvent (void (T::*mem_ptr) (T1), T* obj, T1 a1);
|
||||
template <typename T, typename T1, typename T2>
|
||||
static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2), T* obj, T1 a1, T2 a2);
|
||||
template <typename T, typename T1, typename T2, typename T3>
|
||||
static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2,T3), T* obj, T1 a1, T2 a2, T3 a3);
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4>
|
||||
static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2,T3,T4), T* obj, T1 a1, T2 a2, T3 a3, T4 a4);
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2,T3,T4,T5), T* obj,
|
||||
T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
|
||||
template <typename T, typename OBJ>
|
||||
static EventImpl *MakeEvent (void (T::*mem_ptr) (void), OBJ obj);
|
||||
template <typename T, typename OBJ, typename T1>
|
||||
static EventImpl *MakeEvent (void (T::*mem_ptr) (T1), OBJ obj, T1 a1);
|
||||
template <typename T, typename OBJ, typename T1, typename T2>
|
||||
static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2);
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3>
|
||||
static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3);
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
|
||||
static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4);
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj,
|
||||
T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
|
||||
static EventImpl *MakeEvent (void (*f) (void));
|
||||
template <typename T1>
|
||||
static EventImpl *MakeEvent (void (*f) (T1), T1 a1);
|
||||
@@ -559,6 +561,19 @@ private:
|
||||
static SimulatorPrivate *m_priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief create an ns3::Time instance which contains the
|
||||
* current simulation time.
|
||||
*
|
||||
* This is really a shortcut for the ns3::Simulator::Now method.
|
||||
* It is typically used as shown below to schedule an event
|
||||
* which expires at the absolute time "2 seconds":
|
||||
* \code
|
||||
* Simulator::Schedule (Seconds (2.0) - Now (), &my_function);
|
||||
* \endcode
|
||||
*/
|
||||
Time Now (void);
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
|
||||
@@ -569,174 +584,185 @@ private:
|
||||
namespace ns3 {
|
||||
|
||||
template <typename T>
|
||||
EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (void), T *obj)
|
||||
struct EventMemberImplTraits;
|
||||
|
||||
template <typename T>
|
||||
struct EventMemberImplTraits<T *>
|
||||
{
|
||||
static T &GetReference (T *p) {
|
||||
return *p;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename OBJ>
|
||||
EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (void), OBJ obj)
|
||||
{
|
||||
// zero argument version
|
||||
class EventMemberImpl0 : public EventImpl {
|
||||
public:
|
||||
typedef void (T::*F)(void);
|
||||
EventMemberImpl0 (T *obj, F function)
|
||||
: m_obj (obj),
|
||||
m_function (function)
|
||||
{}
|
||||
virtual ~EventMemberImpl0 () {}
|
||||
typedef void (T::*F)(void);
|
||||
EventMemberImpl0 (OBJ obj, F function)
|
||||
: m_obj (obj),
|
||||
m_function (function)
|
||||
{}
|
||||
virtual ~EventMemberImpl0 () {}
|
||||
private:
|
||||
virtual void Notify (void) {
|
||||
(m_obj->*m_function) ();
|
||||
}
|
||||
T* m_obj;
|
||||
F m_function;
|
||||
virtual void Notify (void) {
|
||||
(EventMemberImplTraits<OBJ>::GetReference (m_obj).*m_function) ();
|
||||
}
|
||||
OBJ m_obj;
|
||||
F m_function;
|
||||
} *ev = new EventMemberImpl0 (obj, mem_ptr);
|
||||
return ev;
|
||||
}
|
||||
|
||||
|
||||
template <typename T, typename T1>
|
||||
EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1), T* obj, T1 a1)
|
||||
template <typename T, typename OBJ, typename T1>
|
||||
EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1), OBJ obj, T1 a1)
|
||||
{
|
||||
// one argument version
|
||||
class EventMemberImpl1 : public EventImpl {
|
||||
public:
|
||||
typedef void (T::*F)(T1);
|
||||
EventMemberImpl1 (T *obj, F function, T1 a1)
|
||||
: m_obj (obj),
|
||||
m_function (function),
|
||||
m_a1 (a1)
|
||||
{}
|
||||
typedef void (T::*F)(T1);
|
||||
EventMemberImpl1 (OBJ obj, F function, T1 a1)
|
||||
: m_obj (obj),
|
||||
m_function (function),
|
||||
m_a1 (a1)
|
||||
{}
|
||||
protected:
|
||||
virtual ~EventMemberImpl1 () {}
|
||||
virtual ~EventMemberImpl1 () {}
|
||||
private:
|
||||
virtual void Notify (void) {
|
||||
(m_obj->*m_function) (m_a1);
|
||||
}
|
||||
T* m_obj;
|
||||
F m_function;
|
||||
T1 m_a1;
|
||||
virtual void Notify (void) {
|
||||
(EventMemberImplTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1);
|
||||
}
|
||||
OBJ m_obj;
|
||||
F m_function;
|
||||
T1 m_a1;
|
||||
} *ev = new EventMemberImpl1 (obj, mem_ptr, a1);
|
||||
return ev;
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2>
|
||||
EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1,T2), T* obj, T1 a1, T2 a2)
|
||||
template <typename T, typename OBJ, typename T1, typename T2>
|
||||
EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2)
|
||||
{
|
||||
// two argument version
|
||||
class EventMemberImpl2 : public EventImpl {
|
||||
public:
|
||||
typedef void (T::*F)(T1, T2);
|
||||
typedef void (T::*F)(T1, T2);
|
||||
|
||||
EventMemberImpl2 (T *obj, F function, T1 a1, T2 a2)
|
||||
: m_obj (obj),
|
||||
m_function (function),
|
||||
m_a1 (a1),
|
||||
m_a2 (a2)
|
||||
{ }
|
||||
EventMemberImpl2 (OBJ obj, F function, T1 a1, T2 a2)
|
||||
: m_obj (obj),
|
||||
m_function (function),
|
||||
m_a1 (a1),
|
||||
m_a2 (a2)
|
||||
{ }
|
||||
protected:
|
||||
virtual ~EventMemberImpl2 () {}
|
||||
virtual ~EventMemberImpl2 () {}
|
||||
private:
|
||||
virtual void Notify (void) {
|
||||
(m_obj->*m_function) (m_a1, m_a2);
|
||||
}
|
||||
T* m_obj;
|
||||
F m_function;
|
||||
T1 m_a1;
|
||||
T2 m_a2;
|
||||
virtual void Notify (void) {
|
||||
(EventMemberImplTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2);
|
||||
}
|
||||
OBJ m_obj;
|
||||
F m_function;
|
||||
T1 m_a1;
|
||||
T2 m_a2;
|
||||
} *ev = new EventMemberImpl2 (obj, mem_ptr, a1, a2);
|
||||
return ev;
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3>
|
||||
EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1,T2,T3), T* obj, T1 a1, T2 a2, T3 a3)
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3>
|
||||
EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3)
|
||||
{
|
||||
// three argument version
|
||||
class EventMemberImpl3 : public EventImpl {
|
||||
public:
|
||||
typedef void (T::*F)(T1, T2, T3);
|
||||
typedef void (T::*F)(T1, T2, T3);
|
||||
|
||||
EventMemberImpl3 (T *obj, F function, T1 a1, T2 a2, T3 a3)
|
||||
: m_obj (obj),
|
||||
m_function (function),
|
||||
m_a1 (a1),
|
||||
m_a2 (a2),
|
||||
m_a3 (a3)
|
||||
{ }
|
||||
EventMemberImpl3 (OBJ obj, F function, T1 a1, T2 a2, T3 a3)
|
||||
: m_obj (obj),
|
||||
m_function (function),
|
||||
m_a1 (a1),
|
||||
m_a2 (a2),
|
||||
m_a3 (a3)
|
||||
{ }
|
||||
protected:
|
||||
virtual ~EventMemberImpl3 () {}
|
||||
virtual ~EventMemberImpl3 () {}
|
||||
private:
|
||||
virtual void Notify (void) {
|
||||
(m_obj->*m_function) (m_a1, m_a2, m_a3);
|
||||
}
|
||||
T* m_obj;
|
||||
F m_function;
|
||||
T1 m_a1;
|
||||
T2 m_a2;
|
||||
T3 m_a3;
|
||||
virtual void Notify (void) {
|
||||
(EventMemberImplTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3);
|
||||
}
|
||||
OBJ m_obj;
|
||||
F m_function;
|
||||
T1 m_a1;
|
||||
T2 m_a2;
|
||||
T3 m_a3;
|
||||
} *ev = new EventMemberImpl3 (obj, mem_ptr, a1, a2, a3);
|
||||
return ev;
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4>
|
||||
EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1,T2,T3,T4), T* obj, T1 a1, T2 a2, T3 a3, T4 a4)
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
|
||||
EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4)
|
||||
{
|
||||
// four argument version
|
||||
class EventMemberImpl4 : public EventImpl {
|
||||
public:
|
||||
typedef void (T::*F)(T1, T2, T3, T4);
|
||||
typedef void (T::*F)(T1, T2, T3, T4);
|
||||
|
||||
EventMemberImpl4 (T *obj, F function, T1 a1, T2 a2, T3 a3, T4 a4)
|
||||
: m_obj (obj),
|
||||
m_function (function),
|
||||
m_a1 (a1),
|
||||
m_a2 (a2),
|
||||
m_a3 (a3),
|
||||
m_a4 (a4)
|
||||
{ }
|
||||
EventMemberImpl4 (OBJ obj, F function, T1 a1, T2 a2, T3 a3, T4 a4)
|
||||
: m_obj (obj),
|
||||
m_function (function),
|
||||
m_a1 (a1),
|
||||
m_a2 (a2),
|
||||
m_a3 (a3),
|
||||
m_a4 (a4)
|
||||
{ }
|
||||
protected:
|
||||
virtual ~EventMemberImpl4 () {}
|
||||
virtual ~EventMemberImpl4 () {}
|
||||
private:
|
||||
virtual void Notify (void) {
|
||||
(m_obj->*m_function) (m_a1, m_a2, m_a3, m_a4);
|
||||
}
|
||||
T* m_obj;
|
||||
F m_function;
|
||||
T1 m_a1;
|
||||
T2 m_a2;
|
||||
T3 m_a3;
|
||||
T4 m_a4;
|
||||
virtual void Notify (void) {
|
||||
(EventMemberImplTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3, m_a4);
|
||||
}
|
||||
OBJ m_obj;
|
||||
F m_function;
|
||||
T1 m_a1;
|
||||
T2 m_a2;
|
||||
T3 m_a3;
|
||||
T4 m_a4;
|
||||
} *ev = new EventMemberImpl4 (obj, mem_ptr, a1, a2, a3, a4);
|
||||
return ev;
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1,T2,T3,T4,T5), T* obj,
|
||||
T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj,
|
||||
T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
|
||||
{
|
||||
// five argument version
|
||||
class EventMemberImpl5 : public EventImpl {
|
||||
public:
|
||||
typedef void (T::*F)(T1, T2, T3, T4, T5);
|
||||
typedef void (T::*F)(T1, T2, T3, T4, T5);
|
||||
|
||||
EventMemberImpl5 (T *obj, F function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
|
||||
: m_obj (obj),
|
||||
m_function (function),
|
||||
m_a1 (a1),
|
||||
m_a2 (a2),
|
||||
m_a3 (a3),
|
||||
m_a4 (a4),
|
||||
m_a5 (a5)
|
||||
{ }
|
||||
EventMemberImpl5 (OBJ obj, F function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
|
||||
: m_obj (obj),
|
||||
m_function (function),
|
||||
m_a1 (a1),
|
||||
m_a2 (a2),
|
||||
m_a3 (a3),
|
||||
m_a4 (a4),
|
||||
m_a5 (a5)
|
||||
{ }
|
||||
protected:
|
||||
virtual ~EventMemberImpl5 () {}
|
||||
virtual ~EventMemberImpl5 () {}
|
||||
private:
|
||||
virtual void Notify (void) {
|
||||
(m_obj->*m_function) (m_a1, m_a2, m_a3, m_a4, m_a5);
|
||||
}
|
||||
T* m_obj;
|
||||
F m_function;
|
||||
T1 m_a1;
|
||||
T2 m_a2;
|
||||
T3 m_a3;
|
||||
T4 m_a4;
|
||||
T5 m_a5;
|
||||
virtual void Notify (void) {
|
||||
(EventMemberImplTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3, m_a4, m_a5);
|
||||
}
|
||||
OBJ m_obj;
|
||||
F m_function;
|
||||
T1 m_a1;
|
||||
T2 m_a2;
|
||||
T3 m_a3;
|
||||
T4 m_a4;
|
||||
T5 m_a5;
|
||||
} *ev = new EventMemberImpl5 (obj, mem_ptr, a1, a2, a3, a4, a5);
|
||||
return ev;
|
||||
}
|
||||
@@ -881,39 +907,39 @@ EventImpl *Simulator::MakeEvent (void (*f) (T1,T2,T3,T4,T5), T1 a1, T2 a2, T3 a3
|
||||
return ev;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (void), T *obj)
|
||||
template <typename T, typename OBJ>
|
||||
EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (void), OBJ obj)
|
||||
{
|
||||
return Schedule (time, MakeEvent (mem_ptr, obj));
|
||||
}
|
||||
|
||||
|
||||
template <typename T, typename T1>
|
||||
EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1), T* obj, T1 a1)
|
||||
template <typename T, typename OBJ, typename T1>
|
||||
EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1), OBJ obj, T1 a1)
|
||||
{
|
||||
return Schedule (time, MakeEvent (mem_ptr, obj, a1));
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2>
|
||||
EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1,T2), T* obj, T1 a1, T2 a2)
|
||||
template <typename T, typename OBJ, typename T1, typename T2>
|
||||
EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2)
|
||||
{
|
||||
return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2));
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3>
|
||||
EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3), T* obj, T1 a1, T2 a2, T3 a3)
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3>
|
||||
EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3)
|
||||
{
|
||||
return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2, a3));
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4>
|
||||
EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3,T4), T* obj, T1 a1, T2 a2, T3 a3, T4 a4)
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
|
||||
EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4)
|
||||
{
|
||||
return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2, a3, a4));
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3,T4,T5), T* obj,
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj,
|
||||
T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
|
||||
{
|
||||
return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2, a3, a4, a5));
|
||||
@@ -952,46 +978,46 @@ EventId Simulator::Schedule (Time const &time, void (*f) (T1,T2,T3,T4,T5), T1 a1
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
template <typename T, typename OBJ>
|
||||
void
|
||||
Simulator::ScheduleNow (void (T::*mem_ptr) (void), T *obj)
|
||||
Simulator::ScheduleNow (void (T::*mem_ptr) (void), OBJ obj)
|
||||
{
|
||||
ScheduleNow (MakeEvent (mem_ptr, obj));
|
||||
}
|
||||
|
||||
|
||||
template <typename T, typename T1>
|
||||
template <typename T, typename OBJ, typename T1>
|
||||
void
|
||||
Simulator::ScheduleNow (void (T::*mem_ptr) (T1), T* obj, T1 a1)
|
||||
Simulator::ScheduleNow (void (T::*mem_ptr) (T1), OBJ obj, T1 a1)
|
||||
{
|
||||
ScheduleNow (MakeEvent (mem_ptr, obj, a1));
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2>
|
||||
template <typename T, typename OBJ, typename T1, typename T2>
|
||||
void
|
||||
Simulator::ScheduleNow (void (T::*mem_ptr) (T1,T2), T* obj, T1 a1, T2 a2)
|
||||
Simulator::ScheduleNow (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2)
|
||||
{
|
||||
ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2));
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3>
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3>
|
||||
void
|
||||
Simulator::ScheduleNow (void (T::*mem_ptr) (T1,T2,T3), T* obj, T1 a1, T2 a2, T3 a3)
|
||||
Simulator::ScheduleNow (void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3)
|
||||
{
|
||||
ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2, a3));
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4>
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
|
||||
void
|
||||
Simulator::ScheduleNow (void (T::*mem_ptr) (T1,T2,T3,T4), T* obj, T1 a1, T2 a2, T3 a3, T4 a4)
|
||||
Simulator::ScheduleNow (void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4)
|
||||
{
|
||||
ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2, a3, a4));
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
void
|
||||
Simulator::ScheduleNow (void (T::*mem_ptr) (T1,T2,T3,T4,T5), T* obj,
|
||||
T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
|
||||
Simulator::ScheduleNow (void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj,
|
||||
T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
|
||||
{
|
||||
ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2, a3, a4, a5));
|
||||
}
|
||||
@@ -1033,46 +1059,46 @@ Simulator::ScheduleNow (void (*f) (T1,T2,T3,T4,T5), T1 a1, T2 a2, T3 a3, T4 a4,
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
template <typename T, typename OBJ>
|
||||
void
|
||||
Simulator::ScheduleDestroy (void (T::*mem_ptr) (void), T *obj)
|
||||
Simulator::ScheduleDestroy (void (T::*mem_ptr) (void), OBJ obj)
|
||||
{
|
||||
ScheduleDestroy (MakeEvent (mem_ptr, obj));
|
||||
}
|
||||
|
||||
|
||||
template <typename T, typename T1>
|
||||
template <typename T, typename OBJ, typename T1>
|
||||
void
|
||||
Simulator::ScheduleDestroy (void (T::*mem_ptr) (T1), T* obj, T1 a1)
|
||||
Simulator::ScheduleDestroy (void (T::*mem_ptr) (T1), OBJ obj, T1 a1)
|
||||
{
|
||||
ScheduleDestroy (MakeEvent (mem_ptr, obj, a1));
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2>
|
||||
template <typename T, typename OBJ, typename T1, typename T2>
|
||||
void
|
||||
Simulator::ScheduleDestroy (void (T::*mem_ptr) (T1,T2), T* obj, T1 a1, T2 a2)
|
||||
Simulator::ScheduleDestroy (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2)
|
||||
{
|
||||
ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2));
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3>
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3>
|
||||
void
|
||||
Simulator::ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3), T* obj, T1 a1, T2 a2, T3 a3)
|
||||
Simulator::ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3)
|
||||
{
|
||||
ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2, a3));
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4>
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4>
|
||||
void
|
||||
Simulator::ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3,T4), T* obj, T1 a1, T2 a2, T3 a3, T4 a4)
|
||||
Simulator::ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4)
|
||||
{
|
||||
ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2, a3, a4));
|
||||
}
|
||||
|
||||
template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
template <typename T, typename OBJ, typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
void
|
||||
Simulator::ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3,T4,T5), T* obj,
|
||||
T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
|
||||
Simulator::ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ obj,
|
||||
T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
|
||||
{
|
||||
ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2, a3, a4, a5));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005,2006 INRIA
|
||||
* Copyright (c) 2007 Emmanuelle Laprise
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -17,13 +18,49 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
* TimeStep support by Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
|
||||
*/
|
||||
#include "time.h"
|
||||
#include "simulator.h"
|
||||
#include "nstime.h"
|
||||
#include "ns3/fatal-error.h"
|
||||
#include "ns3/default-value.h"
|
||||
#include <math.h>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
namespace TimeStepPrecision {
|
||||
|
||||
static const uint64_t MS_FACTOR = (uint64_t)pow(10,3);
|
||||
static const uint64_t US_FACTOR = (uint64_t)pow(10,6);
|
||||
static const uint64_t NS_FACTOR = (uint64_t)pow(10,9);
|
||||
static const uint64_t PS_FACTOR = (uint64_t)pow(10,12);
|
||||
static const uint64_t FS_FACTOR = (uint64_t)pow(10,15);
|
||||
static uint64_t g_tsPrecFactor = NS_FACTOR;
|
||||
|
||||
static EnumDefaultValue<enum precision_t> g_precisionDefaultValue ("TimeStepPrecision",
|
||||
"The time unit of the internal 64 bit integer time.",
|
||||
NS, "NS",
|
||||
S, "S",
|
||||
MS, "MS",
|
||||
US, "US",
|
||||
PS, "PS",
|
||||
FS, "FS",
|
||||
0, (void *)0);
|
||||
|
||||
precision_t
|
||||
Get (void)
|
||||
{
|
||||
return g_precisionDefaultValue.GetValue ();
|
||||
}
|
||||
|
||||
void
|
||||
Set (precision_t precision)
|
||||
{
|
||||
g_precisionDefaultValue.SetValue (precision);
|
||||
g_tsPrecFactor = (uint64_t)pow(10, precision);
|
||||
}
|
||||
|
||||
} // namespace TimeStepPrecision
|
||||
|
||||
TimeUnit<1>::TimeUnit(const std::string& s)
|
||||
{
|
||||
std::string::size_type n = s.find_first_not_of("0123456789.");
|
||||
@@ -33,81 +70,192 @@ TimeUnit<1>::TimeUnit(const std::string& s)
|
||||
std::string trailer = s.substr(n, std::string::npos);
|
||||
if (trailer == std::string("s"))
|
||||
{
|
||||
m_data = HighPrecision (r * 1000000000.0);
|
||||
m_data = HighPrecision (r * TimeStepPrecision::g_tsPrecFactor);
|
||||
return;
|
||||
}
|
||||
if (trailer == std::string("ms"))
|
||||
{
|
||||
m_data = HighPrecision ((int64_t)(r * 1000000), false);
|
||||
m_data = HighPrecision ((int64_t)(r * (TimeStepPrecision::g_tsPrecFactor/pow(10,3))),
|
||||
false);
|
||||
return;
|
||||
}
|
||||
if (trailer == std::string("us"))
|
||||
{
|
||||
m_data = HighPrecision ((int64_t)(r * 1000), false);
|
||||
m_data = HighPrecision ((int64_t)(r * (TimeStepPrecision::g_tsPrecFactor/pow(10,6))),
|
||||
false);
|
||||
return;
|
||||
}
|
||||
if (trailer == std::string("ns"))
|
||||
{
|
||||
m_data = HighPrecision ((int64_t)r, false);
|
||||
m_data = HighPrecision ((int64_t)(r * (TimeStepPrecision::g_tsPrecFactor/pow(10,9))),
|
||||
false);
|
||||
return;
|
||||
}
|
||||
if (trailer == std::string("ps"))
|
||||
{
|
||||
m_data = HighPrecision ((int64_t)(r * (TimeStepPrecision::g_tsPrecFactor/pow(10,12))),
|
||||
false);
|
||||
return;
|
||||
}
|
||||
if (trailer == std::string("fs"))
|
||||
{
|
||||
m_data = HighPrecision ((int64_t)(r * (TimeStepPrecision::g_tsPrecFactor/pow(10,15))),
|
||||
false);
|
||||
return;
|
||||
}
|
||||
NS_FATAL_ERROR("Can't Parse Time "<<s);
|
||||
}
|
||||
//else
|
||||
//they didn't provide units, assume seconds
|
||||
m_data = HighPrecision (atof(s.c_str()) * 1000000000.0);
|
||||
m_data = HighPrecision (atof(s.c_str()) * TimeStepPrecision::g_tsPrecFactor);
|
||||
}
|
||||
|
||||
double
|
||||
TimeUnit<1>::GetSeconds (void) const
|
||||
{
|
||||
double ns = GetHighPrecision ().GetDouble ();
|
||||
return ns/1000000000.0;
|
||||
double timeValue = GetHighPrecision ().GetDouble ();
|
||||
return timeValue/TimeStepPrecision::g_tsPrecFactor;
|
||||
}
|
||||
int32_t
|
||||
|
||||
int64_t
|
||||
TimeUnit<1>::ConvertToUnits (int64_t timeValue, uint64_t unitFactor) const
|
||||
{
|
||||
uint64_t precFactor;
|
||||
// In order to avoid conversion to double, precFactor can't be less 1
|
||||
if (TimeStepPrecision::g_tsPrecFactor < unitFactor)
|
||||
{
|
||||
precFactor = unitFactor / TimeStepPrecision::g_tsPrecFactor;
|
||||
timeValue = timeValue * precFactor;
|
||||
}
|
||||
else
|
||||
{
|
||||
precFactor = TimeStepPrecision::g_tsPrecFactor / unitFactor;
|
||||
timeValue = timeValue / precFactor;
|
||||
}
|
||||
return timeValue;
|
||||
}
|
||||
|
||||
|
||||
int64_t
|
||||
TimeUnit<1>::GetMilliSeconds (void) const
|
||||
{
|
||||
int64_t ns = GetHighPrecision ().GetInteger ();
|
||||
ns /= 1000000;
|
||||
return ns;
|
||||
int64_t ts = GetTimeStep();
|
||||
int64_t ms = ConvertToUnits(ts, TimeStepPrecision::MS_FACTOR);
|
||||
|
||||
return ms;
|
||||
}
|
||||
int64_t
|
||||
TimeUnit<1>::GetMicroSeconds (void) const
|
||||
{
|
||||
int64_t ns = GetHighPrecision ().GetInteger ();
|
||||
return ns/1000;
|
||||
int64_t ts = GetTimeStep();
|
||||
int64_t us = ConvertToUnits(ts, TimeStepPrecision::US_FACTOR);
|
||||
|
||||
return us;
|
||||
}
|
||||
int64_t
|
||||
TimeUnit<1>::GetNanoSeconds (void) const
|
||||
{
|
||||
return GetHighPrecision ().GetInteger ();
|
||||
int64_t ts = GetTimeStep();
|
||||
int64_t ns = ConvertToUnits(ts, TimeStepPrecision::NS_FACTOR);
|
||||
|
||||
return ns;
|
||||
}
|
||||
int64_t
|
||||
TimeUnit<1>::GetPicoSeconds (void) const
|
||||
{
|
||||
int64_t ts = GetTimeStep();
|
||||
int64_t ps = ConvertToUnits(ts, TimeStepPrecision::PS_FACTOR);
|
||||
|
||||
return ps;
|
||||
}
|
||||
int64_t
|
||||
TimeUnit<1>::GetFemtoSeconds (void) const
|
||||
{
|
||||
int64_t ts = GetTimeStep();
|
||||
int64_t fs = ConvertToUnits(ts, TimeStepPrecision::FS_FACTOR);
|
||||
|
||||
return fs;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the value with the precision returned by TimeStepPrecision::Get
|
||||
*/
|
||||
int64_t
|
||||
TimeUnit<1>::GetTimeStep (void) const
|
||||
{
|
||||
int64_t timeValue = GetHighPrecision ().GetInteger ();
|
||||
return timeValue;
|
||||
}
|
||||
|
||||
|
||||
std::ostream&
|
||||
operator<< (std::ostream& os, Time const& time)
|
||||
{
|
||||
os << time.GetNanoSeconds () << "ns";
|
||||
os << time.GetTimeStep () << "ts";
|
||||
return os;
|
||||
}
|
||||
|
||||
Time Seconds (double seconds)
|
||||
{
|
||||
return Time (HighPrecision (seconds * 1000000000.0));
|
||||
double d_sec = seconds * TimeStepPrecision::g_tsPrecFactor;
|
||||
return Time (HighPrecision (d_sec));
|
||||
// return Time (HighPrecision ((int64_t)d_sec, false));
|
||||
}
|
||||
Time MilliSeconds (uint32_t ms)
|
||||
|
||||
uint64_t
|
||||
TimeUnit<1>::UnitsToTimestep (uint64_t unitValue,
|
||||
uint64_t unitFactor)
|
||||
{
|
||||
return Time (HighPrecision (ms * 1000000, false));
|
||||
uint64_t precFactor;
|
||||
// In order to avoid conversion to double, precFactor can't be less 1
|
||||
if (TimeStepPrecision::g_tsPrecFactor < unitFactor)
|
||||
{
|
||||
precFactor = unitFactor / TimeStepPrecision::g_tsPrecFactor;
|
||||
unitValue = unitValue / precFactor;
|
||||
}
|
||||
else
|
||||
{
|
||||
precFactor = TimeStepPrecision::g_tsPrecFactor / unitFactor;
|
||||
unitValue = unitValue * precFactor;
|
||||
}
|
||||
return unitValue;
|
||||
}
|
||||
|
||||
Time MilliSeconds (uint64_t ms)
|
||||
{
|
||||
uint64_t ts = TimeUnit<1>::UnitsToTimestep(ms, TimeStepPrecision::MS_FACTOR);
|
||||
return TimeStep(ts);
|
||||
}
|
||||
|
||||
Time MicroSeconds (uint64_t us)
|
||||
{
|
||||
return Time (HighPrecision (us * 1000, false));
|
||||
uint64_t ts = TimeUnit<1>::UnitsToTimestep(us, TimeStepPrecision::US_FACTOR);
|
||||
return TimeStep(ts);
|
||||
}
|
||||
|
||||
Time NanoSeconds (uint64_t ns)
|
||||
{
|
||||
return Time (HighPrecision (ns, false));
|
||||
uint64_t ts = TimeUnit<1>::UnitsToTimestep(ns, TimeStepPrecision::NS_FACTOR);
|
||||
return TimeStep(ts);
|
||||
}
|
||||
Time Now (void)
|
||||
Time PicoSeconds (uint64_t ps)
|
||||
{
|
||||
return Time (Simulator::Now ());
|
||||
uint64_t ts = TimeUnit<1>::UnitsToTimestep(ps, TimeStepPrecision::PS_FACTOR);
|
||||
return TimeStep(ts);
|
||||
}
|
||||
Time FemtoSeconds (uint64_t fs)
|
||||
{
|
||||
uint64_t ts = TimeUnit<1>::UnitsToTimestep(fs, TimeStepPrecision::FS_FACTOR);
|
||||
return TimeStep(ts);
|
||||
}
|
||||
|
||||
/*
|
||||
* The timestep value passed to this function must be of the precision
|
||||
* of TimeStepPrecision::Get
|
||||
*/
|
||||
Time TimeStep (uint64_t ts)
|
||||
{
|
||||
return Time (HighPrecision (ts, false));
|
||||
}
|
||||
|
||||
TimeUnit<0>::TimeUnit (double scalar)
|
||||
@@ -136,6 +284,46 @@ public:
|
||||
TimeTests ();
|
||||
virtual ~TimeTests ();
|
||||
virtual bool RunTests (void);
|
||||
|
||||
/*
|
||||
* Verifies that a calculated time value is as expected using
|
||||
* doubles since GetSeconds() returns a double
|
||||
*/
|
||||
void CheckTimeSec(std::string test_id, double actual, double expected,
|
||||
bool *flag, double precMultFactor = 1,
|
||||
bool verbose = false);
|
||||
|
||||
/*
|
||||
* Verifies that a calculated time value is as expected.
|
||||
*/
|
||||
void CheckTime(std::string test_id, int64_t actual, int64_t expected,
|
||||
bool *flag, double precMultFactor = 1,
|
||||
bool verbose = false);
|
||||
|
||||
/*
|
||||
* Verifies the +, -, * and / operations for the TimeUnit<1> or Time class
|
||||
*/
|
||||
void CheckOperations(Time t0, Time t1, bool *ok, bool verbose = false);
|
||||
|
||||
/*
|
||||
* Verifies that the TimeUnit class stores values with the precision
|
||||
* set in the variable TimeStepPrecision::Get
|
||||
* Checks that overflow and underflow occur at expected numbers
|
||||
*/
|
||||
void CheckPrecision(TimeStepPrecision::precision_t prec, uint64_t val, bool *ok,
|
||||
bool verbose = false);
|
||||
|
||||
/*
|
||||
* Verifies that the conversion between units in the class
|
||||
* TimeUnit<1> or Time is done correctly. This is verified both when
|
||||
* setting and retrieving a Time value
|
||||
*/
|
||||
void CheckConversions(uint64_t tval, bool *ok, bool verbose = false);
|
||||
|
||||
/*
|
||||
* These are the old tests that used to be run
|
||||
*/
|
||||
void CheckOld(bool *ok);
|
||||
};
|
||||
|
||||
TimeTests::TimeTests ()
|
||||
@@ -143,21 +331,102 @@ TimeTests::TimeTests ()
|
||||
{}
|
||||
TimeTests::~TimeTests ()
|
||||
{}
|
||||
|
||||
bool TimeTests::RunTests (void)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
Time t0 = Seconds (10.0);
|
||||
//std::cout << "t0="<<t0.GetSeconds ()<<" (expected 10.0)"<<std::endl;
|
||||
Time t1 = Seconds (11.0);
|
||||
//std::cout << "t1="<<t1.GetSeconds ()<<" (expected 11.0)"<<std::endl;
|
||||
t0 = Seconds (1.5);
|
||||
//std::cout << "t0="<<t0.GetSeconds ()<<" (expected +1.5)"<<std::endl;
|
||||
t0 = Seconds (-1.5);
|
||||
//std::cout << "t0="<<t0.GetSeconds ()<<" (expected -1.5)"<<std::endl;
|
||||
Time t0, t1;
|
||||
|
||||
t0 = Seconds (10.0);
|
||||
t1 = Seconds (11.0);
|
||||
CheckOld(&ok);
|
||||
|
||||
t0 = MilliSeconds ((uint64_t)10.0);
|
||||
t1 = MilliSeconds ((uint64_t)11.0);
|
||||
|
||||
CheckOperations(t0, t1, &ok);
|
||||
|
||||
// t0 = Seconds ((uint64_t)10.0);
|
||||
// t1 = Seconds ((uint64_t)11.0);
|
||||
|
||||
// CheckOperations(t0, t1, &ok);
|
||||
|
||||
CheckConversions((uint64_t)5, &ok);
|
||||
CheckConversions((uint64_t)0, &ok);
|
||||
CheckConversions((uint64_t)783, &ok);
|
||||
CheckConversions((uint64_t)1132, &ok);
|
||||
// CheckConversions((uint64_t)3341039, &ok);
|
||||
|
||||
// Now vary the precision and check the conversions
|
||||
if (TimeStepPrecision::Get () != TimeStepPrecision::NS) {
|
||||
ok = false;
|
||||
}
|
||||
|
||||
CheckPrecision(TimeStepPrecision::US, 7, &ok);
|
||||
|
||||
CheckConversions((uint64_t)7, &ok);
|
||||
CheckConversions((uint64_t)546, &ok);
|
||||
CheckConversions((uint64_t)6231, &ok);
|
||||
// CheckConversions((uint64_t)1234639, &ok);
|
||||
|
||||
CheckPrecision(TimeStepPrecision::MS, 3, &ok);
|
||||
|
||||
CheckConversions((uint64_t)3, &ok);
|
||||
CheckConversions((uint64_t)134, &ok);
|
||||
CheckConversions((uint64_t)2341, &ok);
|
||||
// CheckConversions((uint64_t)8956239, &ok);
|
||||
|
||||
CheckPrecision(TimeStepPrecision::PS, 21, &ok);
|
||||
|
||||
CheckConversions((uint64_t)4, &ok);
|
||||
CheckConversions((uint64_t)342, &ok);
|
||||
CheckConversions((uint64_t)1327, &ok);
|
||||
// CheckConversions((uint64_t)5439627, &ok);
|
||||
|
||||
CheckPrecision(TimeStepPrecision::NS, 12, &ok);
|
||||
CheckConversions((uint64_t)12, &ok);
|
||||
|
||||
CheckPrecision(TimeStepPrecision::S, 7, &ok);
|
||||
CheckConversions((uint64_t)7, &ok);
|
||||
|
||||
CheckPrecision(TimeStepPrecision::FS, 5, &ok);
|
||||
CheckConversions((uint64_t)5, &ok);
|
||||
|
||||
TimeStepPrecision::Set (TimeStepPrecision::NS);
|
||||
|
||||
Bind ("TimeStepPrecision", "S");
|
||||
Bind ("TimeStepPrecision", "MS");
|
||||
Bind ("TimeStepPrecision", "US");
|
||||
Bind ("TimeStepPrecision", "NS");
|
||||
Bind ("TimeStepPrecision", "PS");
|
||||
Bind ("TimeStepPrecision", "FS");
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void TimeTests::CheckOld (bool *ok)
|
||||
{
|
||||
double dt0, dt1, dt2;
|
||||
int64_t it0, it1;
|
||||
|
||||
Time t0 = Seconds (10.0);
|
||||
CheckTimeSec("old 1", t0.GetSeconds(), 10.0, ok);
|
||||
|
||||
Time t1 = Seconds (11.0);
|
||||
CheckTimeSec("old 2", t1.GetSeconds(), 11.0, ok);
|
||||
|
||||
t0 = Seconds (1.5);
|
||||
CheckTimeSec("old 3", t0.GetSeconds(), 1.5, ok);
|
||||
|
||||
t0 = Seconds (-1.5);
|
||||
CheckTimeSec("old 4", t0.GetSeconds(), -1.5, ok);
|
||||
|
||||
t0 = MilliSeconds ((uint64_t)10.0);
|
||||
dt0 = t0.GetSeconds();
|
||||
CheckTimeSec("old 5", dt0, 0.01, ok);
|
||||
|
||||
t1 = MilliSeconds ((uint64_t)11.0);
|
||||
dt1 = t1.GetSeconds();
|
||||
CheckTimeSec("old 6", dt1, 0.011, ok);
|
||||
|
||||
Time t2, t3;
|
||||
|
||||
@@ -166,44 +435,31 @@ bool TimeTests::RunTests (void)
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
dt2 = t2.GetSeconds();
|
||||
CheckTimeSec("old 7", dt2, dt1-dt0, ok);
|
||||
|
||||
t2 = t1 - t1;
|
||||
if (!t2.IsZero ())
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
dt2 = t2.GetSeconds();
|
||||
CheckTimeSec("old 8", dt2, dt1-dt1, ok);
|
||||
|
||||
t2 = t0 - t1;
|
||||
if (!t2.IsStrictlyNegative ())
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
dt2 = t2.GetSeconds();
|
||||
CheckTimeSec("old 9", dt2, dt0-dt1, ok);
|
||||
|
||||
t2 = t0 - t1;
|
||||
t3 = t2 * t0 / t1;
|
||||
t3 = t0 * t2 / t1;
|
||||
t3 = t0 * t1 / t2;
|
||||
t3 = t0 * (t1 / t2);
|
||||
t3 = (t0 * t1) / t2;
|
||||
t3 = t0 / t1 * t2;
|
||||
t3 = (t0 / t1) * t2;
|
||||
TimeInvert ti0;
|
||||
ti0 = t0 / (t1 * t2);
|
||||
t3 = t0 * Scalar (10.0);
|
||||
t3 = Scalar (10.0) * t0;
|
||||
t3 = Scalar (10.0) * t0 / t2 * t1;
|
||||
t3 = (Scalar (10.0) * t0 ) / t2 * t1;
|
||||
Scalar s0 = t0 / t1;
|
||||
Scalar s1;
|
||||
s1 = t0 * t1 / (t2 * t0);
|
||||
TimeUnit<0> tu0;
|
||||
tu0 = s0;
|
||||
TimeUnit<1> tu1;
|
||||
tu1 = t0;
|
||||
TimeUnit<2> tu2;
|
||||
tu2 = t0 * t1;
|
||||
TimeUnit<3> tu3;
|
||||
tu3 = t0 * tu2;
|
||||
TimeUnit<-2> tu4;
|
||||
tu4 = t0 / tu3;
|
||||
t1 = NanoSeconds(15);
|
||||
it0 = t0.GetNanoSeconds();
|
||||
it1 = t1.GetNanoSeconds();
|
||||
TimeUnit<-2> tu4 = t0 / (t1 * t1 * t1);
|
||||
CheckTime("old 10", tu4.GetHighPrecision().GetInteger(), it0 / (it1*it1*it1),
|
||||
ok, 1e9);
|
||||
|
||||
Time tmp = MilliSeconds (0);
|
||||
if ((tmp != NanoSeconds (0)) ||
|
||||
@@ -215,20 +471,274 @@ bool TimeTests::RunTests (void)
|
||||
|
||||
Time t4;
|
||||
t4 = Seconds (10.0) * Scalar (1.5);
|
||||
//std::cout << "10.0s * 1.5 = " << t4.GetSeconds () << "s" << std::endl;
|
||||
CheckTimeSec("old 11", t4.GetSeconds(), 10, ok);
|
||||
|
||||
Time t5;
|
||||
t5 = NanoSeconds (10) * Scalar (1.5);
|
||||
//std::cout << "10ns * 1.5 = " << t5.GetNanoSeconds () << "ns" <<
|
||||
//std::endl;
|
||||
CheckTime("old 12", t5.GetNanoSeconds(), 10, ok);
|
||||
|
||||
t4 = Seconds (10.0) * Scalar (15) / Scalar (10);
|
||||
CheckTimeSec("old 13", t4.GetSeconds(), 15, ok);
|
||||
|
||||
t5 = NanoSeconds (10) * Scalar (15) / Scalar (10);
|
||||
CheckTime("old 14", t5.GetNanoSeconds(), 15, ok);
|
||||
|
||||
|
||||
double foo = (t1 + t2).GetSeconds ();
|
||||
dt1 = t1.GetSeconds();
|
||||
dt2 = t2.GetSeconds();
|
||||
CheckTimeSec("old 15", foo, dt1+dt2, ok);
|
||||
|
||||
foo += (t4 == t5)? 1 : 0;
|
||||
CheckTimeSec("old 16", foo, dt1+dt2, ok);
|
||||
|
||||
foo = (t1/t2).GetDouble ();
|
||||
|
||||
return ok;
|
||||
CheckTimeSec("old 17", foo, dt1/dt2, ok);
|
||||
}
|
||||
|
||||
|
||||
void TimeTests::CheckOperations(Time t0, Time t1, bool *ok, bool verbose)
|
||||
{
|
||||
|
||||
if (verbose)
|
||||
std::cout << std::endl << "Check operations: "
|
||||
<< t0 << " " << t1 << std::endl;
|
||||
|
||||
Time t2, t3;
|
||||
double it0, it1, it2, it3, itu2, itu3;
|
||||
int64_t iti0;
|
||||
|
||||
it0 = t0.GetSeconds();
|
||||
it1 = t1.GetSeconds();
|
||||
|
||||
t2 = t0 - t1;
|
||||
it2 = t2.GetSeconds();
|
||||
CheckTimeSec("ops 1", it2, it0-it1, ok);
|
||||
|
||||
t3 = t2 * t0 / t0;
|
||||
it3 = t3.GetSeconds();
|
||||
CheckTimeSec("ops 2a", it3, it2*it0/it0, ok);
|
||||
|
||||
t3 = t2 * t0 / t1;
|
||||
it3 = t3.GetSeconds();
|
||||
CheckTimeSec("ops 2", it3, it2*it0/it1, ok);
|
||||
|
||||
t3 = t0 * t2 / t1;
|
||||
it3 = t3.GetSeconds();
|
||||
CheckTimeSec("ops 3", it3, it0*it2/it1, ok);
|
||||
|
||||
t3 = t0 * t1 / t2;
|
||||
it3 = t3.GetSeconds();
|
||||
CheckTimeSec("ops 4", it3, it0*it1/it2, ok);
|
||||
|
||||
t3 = t0 * (t1 / t2);
|
||||
it3 = t3.GetSeconds();
|
||||
CheckTimeSec("ops 5", it3, it0*(it1/it2), ok);
|
||||
|
||||
t3 = (t0 * t1) / t2;
|
||||
it3 = t3.GetSeconds();
|
||||
CheckTimeSec("ops 6", it3, (it0*it1)/it2, ok);
|
||||
|
||||
t3 = t0 / t1 * t2;
|
||||
it3 = t3.GetSeconds();
|
||||
CheckTimeSec("ops 7", it3, it0/it1*it2, ok);
|
||||
|
||||
t3 = (t0 / t1) * t2;
|
||||
it3 = t3.GetSeconds();
|
||||
CheckTimeSec("ops 8", it3, (it0/it1)*it2, ok);
|
||||
|
||||
t3 = t0 * Scalar (10.0);
|
||||
it3 = t3.GetSeconds();
|
||||
CheckTimeSec("ops 9", it3, it0*10, ok);
|
||||
|
||||
t3 = Scalar (10.0) * t0;
|
||||
it3 = t3.GetSeconds();
|
||||
CheckTimeSec("ops 10", it3, 10 * it0, ok);
|
||||
|
||||
t3 = Scalar (10.0) * t0 / t2 * t1;
|
||||
it3 = t3.GetSeconds();
|
||||
CheckTimeSec("ops 11", it3, 10 * it0 / it2 * it1, ok);
|
||||
|
||||
t3 = (Scalar (10.0) * t0 ) / t2 * t1;
|
||||
it3 = t3.GetSeconds();
|
||||
CheckTimeSec("ops 12", it3, (10 * it0) / it2 * it1, ok);
|
||||
|
||||
TimeInvert ti0;
|
||||
ti0 = t0 / (t1 * t2);
|
||||
iti0 = ti0.GetHighPrecision().GetInteger();
|
||||
// This check is not quite working yet.
|
||||
// CheckTime("ops 13", iti0, (int64_t)(it0/(it1*it2)), ok);
|
||||
|
||||
Scalar s0 = t0 / t1;
|
||||
CheckTimeSec("ops 14", s0.GetDouble(), it0/it1, ok);
|
||||
|
||||
Scalar s1;
|
||||
s1 = t0 * t1 / (t2 * t0);
|
||||
CheckTimeSec("ops 15", s1.GetDouble(), it0*it1/(it2*it0), ok);
|
||||
|
||||
TimeUnit<0> tu0;
|
||||
tu0 = s0;
|
||||
CheckTimeSec("ops 16", tu0.GetDouble(), s0.GetDouble(), ok);
|
||||
|
||||
TimeUnit<1> tu1;
|
||||
tu1 = t0;
|
||||
CheckTimeSec("ops 17", tu1.GetSeconds(), it0, ok);
|
||||
|
||||
TimeUnit<2> tu2;
|
||||
tu2 = t0 * t1;
|
||||
CheckTimeSec("ops 18", tu2.GetHighPrecision().GetInteger()/(1e18),
|
||||
it0 * it1, ok);
|
||||
itu2 = tu2.GetHighPrecision().GetInteger()/(1e18);
|
||||
|
||||
TimeUnit<3> tu3;
|
||||
tu3 = t0 / Scalar(10e6) * tu2;
|
||||
CheckTimeSec("ops 19", tu3.GetHighPrecision().GetInteger()/(1e27),
|
||||
it0 / 1000000 * itu2, ok);
|
||||
itu3 = tu3.GetHighPrecision().GetInteger()/(1e27);
|
||||
}
|
||||
|
||||
void TimeTests::CheckConversions(uint64_t tval, bool *ok, bool verbose) {
|
||||
Time t_sec, t_ms, t_us, t_ns, t_ps, t_fs;
|
||||
|
||||
if (verbose)
|
||||
std::cout << std::endl << "Check conversions: " << tval << std::endl;
|
||||
|
||||
// First check the seconds
|
||||
t_sec = Seconds((double)tval);
|
||||
CheckTimeSec("conv sec sec", t_sec.GetSeconds(), (double)tval, ok);
|
||||
CheckTime("conv sec ms", t_sec.GetMilliSeconds(), (int64_t)(tval*1e3), ok, 1e3);
|
||||
CheckTime("conv sec us", t_sec.GetMicroSeconds(), (int64_t)(tval*1e6), ok, 1e6);
|
||||
CheckTime("conv sec ns", t_sec.GetNanoSeconds(), (int64_t)(tval*1e9), ok, 1e9);
|
||||
CheckTime("conv sec ps", t_sec.GetPicoSeconds(),
|
||||
(int64_t)(tval*1e12), ok, 1e12);
|
||||
CheckTime("conv sec fs", t_sec.GetFemtoSeconds(),
|
||||
(int64_t)(tval*1e15), ok, 1e15);
|
||||
|
||||
// Then check the milliseconds
|
||||
t_ms = MilliSeconds(tval);
|
||||
CheckTimeSec("conv ms sec", t_ms.GetSeconds(), (double)tval/1e3, ok);
|
||||
CheckTime("conv ms ms", t_ms.GetMilliSeconds(), (int64_t)(tval), ok, 1e3);
|
||||
CheckTime("conv ms us", t_ms.GetMicroSeconds(), (int64_t)(tval*1e3), ok, 1e6);
|
||||
CheckTime("conv ms ns", t_ms.GetNanoSeconds(), (int64_t)(tval*1e6), ok, 1e9);
|
||||
CheckTime("conv ms ps", t_ms.GetPicoSeconds(), (int64_t)(tval*1e9), ok, 1e12);
|
||||
CheckTime("conv ms fs", t_ms.GetFemtoSeconds(), (int64_t)(tval*1e12), ok, 1e15);
|
||||
|
||||
// Then check the microseconds
|
||||
t_us = MicroSeconds(tval);
|
||||
CheckTimeSec("conv us sec", t_us.GetSeconds(), (double)tval/1e6, ok);
|
||||
CheckTime("conv us ms", t_us.GetMilliSeconds(), (int64_t)(tval/1e3), ok, 1e3);
|
||||
CheckTime("conv us us", t_us.GetMicroSeconds(), (int64_t)(tval), ok, 1e6);
|
||||
CheckTime("conv us ns", t_us.GetNanoSeconds(), (int64_t)(tval*1e3), ok, 1e9);
|
||||
CheckTime("conv us ps", t_us.GetPicoSeconds(), (int64_t)(tval*1e6), ok, 1e12);
|
||||
CheckTime("conv us fs", t_us.GetFemtoSeconds(), (int64_t)(tval*1e9), ok, 1e15);
|
||||
|
||||
// Then check the nanoseconds
|
||||
t_ns = NanoSeconds(tval);
|
||||
CheckTimeSec("conv ns sec", t_ns.GetSeconds(), (double)tval/1e9, ok);
|
||||
CheckTime("conv ns ms", t_ns.GetMilliSeconds(), (int64_t)(tval/1e6), ok, 1e3);
|
||||
CheckTime("conv ns us", t_ns.GetMicroSeconds(), (int64_t)(tval/1e3), ok, 1e6);
|
||||
CheckTime("conv ns ns", t_ns.GetNanoSeconds(), (int64_t)(tval), ok, 1e9);
|
||||
CheckTime("conv ns ps", t_ns.GetPicoSeconds(), (int64_t)(tval*1e3), ok, 1e12);
|
||||
CheckTime("conv ns fs", t_ns.GetFemtoSeconds(), (int64_t)(tval*1e6), ok, 1e15);
|
||||
|
||||
// Then check the picoseconds
|
||||
t_ps = PicoSeconds(tval);
|
||||
CheckTimeSec("conv ps sec", t_ps.GetSeconds(), (double)tval/1e12, ok);
|
||||
CheckTime("conv ps ms", t_ps.GetMilliSeconds(), (int64_t)(tval/1e9), ok, 1e3);
|
||||
CheckTime("conv ps us", t_ps.GetMicroSeconds(), (int64_t)(tval/1e6), ok, 1e6);
|
||||
CheckTime("conv ps ns", t_ps.GetNanoSeconds(), (int64_t)(tval/1e3), ok, 1e9);
|
||||
CheckTime("conv ps ps", t_ps.GetPicoSeconds(), (int64_t)(tval), ok, 1e12);
|
||||
CheckTime("conv ps fs", t_ps.GetFemtoSeconds(), (int64_t)(tval*1e3), ok, 1e15);
|
||||
|
||||
// Then check the femtoseconds
|
||||
t_fs = FemtoSeconds(tval);
|
||||
CheckTimeSec("conv fs sec", t_fs.GetSeconds(), (double)tval/1e15, ok);
|
||||
CheckTime("conv fs ms", t_fs.GetMilliSeconds(), (int64_t)(tval/1e12), ok, 1e3);
|
||||
CheckTime("conv fs us", t_fs.GetMicroSeconds(), (int64_t)(tval/1e9), ok, 1e6);
|
||||
CheckTime("conv fs ns", t_fs.GetNanoSeconds(), (int64_t)(tval/1e6), ok, 1e9);
|
||||
CheckTime("conv fs ps", t_fs.GetPicoSeconds(), (int64_t)(tval/1e3), ok, 1e12);
|
||||
CheckTime("conv fs fs", t_fs.GetFemtoSeconds(), (int64_t)(tval), ok, 1e15);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void TimeTests::CheckPrecision(TimeStepPrecision::precision_t prec, uint64_t val, bool *ok,
|
||||
bool verbose) {
|
||||
if (verbose) {
|
||||
std::cout << "check precision 10^-" << prec << std::endl;
|
||||
}
|
||||
|
||||
TimeStepPrecision::Set (prec);
|
||||
if (TimeStepPrecision::Get () != prec) {
|
||||
ok = false;
|
||||
}
|
||||
|
||||
/* These still need to be fixed.
|
||||
// The smallest value that can be stored is 1x10^(-prec)
|
||||
Time smallest = Seconds(pow(10,-prec));
|
||||
CheckTimeSec("Prec small: ", smallest.GetSeconds(), pow(10,-prec), ok, 0.1,
|
||||
true);
|
||||
|
||||
double d_ts = pow(10,-prec) - pow(10, -(prec+3));
|
||||
Time too_small = Seconds(d_ts);
|
||||
CheckTimeSec("Prec too small: ", too_small.GetSeconds(), 0, ok, 0.1, true);
|
||||
|
||||
double d_la = 0xFFFFFFFF*pow(10,-prec);
|
||||
Time largest = Seconds(d_la);
|
||||
CheckTimeSec("Prec large: ", largest.GetSeconds(), d_la, ok, 0.1, true);
|
||||
|
||||
double d_tl = (0xFFFFFFFF*pow(10,-prec)) + 1;
|
||||
Time too_large = Seconds(d_tl);
|
||||
if ((largest.GetSeconds() + 1) == too_large.GetSeconds())
|
||||
std::cout << "Overflow did not occur." << std::endl;
|
||||
|
||||
NS_ASSERT(d_la+1 == d_tl);
|
||||
*/
|
||||
}
|
||||
|
||||
void TimeTests::CheckTimeSec (std::string test_id, double actual,
|
||||
double expected, bool *flag, double precMultFactor,
|
||||
bool verbose)
|
||||
{
|
||||
double prec = pow(10,-((double)(ns3::TimeStepPrecision::Get ()))) * precMultFactor;
|
||||
if ((actual < (expected-prec)) || (actual > (expected+prec))) {
|
||||
std::cout << "FAIL " << test_id
|
||||
<< " Expected:" << expected
|
||||
<< " Actual: " << actual
|
||||
<< " Precision: " << prec << std::endl;
|
||||
*flag = false;
|
||||
} else {
|
||||
if (verbose) {
|
||||
std::cout << "PASS " << test_id
|
||||
<< " Expected:" << expected
|
||||
<< " Actual: " << actual
|
||||
<< " Precision: " << prec << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TimeTests::CheckTime (std::string test_id, int64_t actual,
|
||||
int64_t expected, bool *flag, double precMultFactor,
|
||||
bool verbose)
|
||||
{
|
||||
double prec = pow(10,-((double)(ns3::TimeStepPrecision::Get ()))) * precMultFactor;
|
||||
if ((actual < (expected-prec)) || (actual > (expected+prec))) {
|
||||
std::cout << "FAIL " << test_id
|
||||
<< " Expected:" << expected
|
||||
<< " Actual: " << actual
|
||||
<< " Precision: " << prec << std::endl;
|
||||
*flag = false;
|
||||
} else {
|
||||
if (verbose) {
|
||||
std::cout << "PASS " << test_id
|
||||
<< " Expected:" << expected
|
||||
<< " Actual: " << actual
|
||||
<< " Precision: " << prec << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static TimeTests g_time_tests;
|
||||
|
||||
};
|
||||
|
||||
76
src/wscript
76
src/wscript
@@ -1,7 +1,14 @@
|
||||
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
import os
|
||||
import shutil
|
||||
|
||||
import Action
|
||||
import Common
|
||||
import Object
|
||||
import Params
|
||||
|
||||
|
||||
all_modules = [
|
||||
'core',
|
||||
'common',
|
||||
@@ -15,29 +22,68 @@ all_modules = [
|
||||
|
||||
def set_options(opt):
|
||||
opt.sub_options('simulator')
|
||||
opt.add_option('--disable-rpath',
|
||||
help=("Don't link programs with rpath"),
|
||||
action="store_true", default=False,
|
||||
dest='disable_rpath')
|
||||
|
||||
|
||||
|
||||
def configure(conf):
|
||||
conf.sub_config('core')
|
||||
conf.sub_config('simulator')
|
||||
|
||||
conf.env['DISABLE_RPATH'] = Params.g_options.disable_rpath
|
||||
|
||||
|
||||
def build(bld):
|
||||
Object.register('ns3header', Ns3Header)
|
||||
Action.Action('ns3_headers', func=_ns3_headers_inst, color='BLUE')
|
||||
|
||||
## Add a global RPATH pointing to each module, so that programs can find the libs
|
||||
## Note: this is slightly evil; we get away because our programs
|
||||
## and libs are not supposed to be installed system wide.
|
||||
env = bld.env_of_name('default')
|
||||
if not env['DISABLE_RPATH']:
|
||||
for module in all_modules:
|
||||
node = bld.m_curdirnode.find_dir(module)
|
||||
env.append_value('RPATH', '-Wl,--rpath=%s' % (node.abspath(env),))
|
||||
for module in all_modules:
|
||||
node = bld.m_curdirnode.find_dir(module)
|
||||
node_path = node.abspath(env)
|
||||
env.append_value('NS3_MODULE_PATH', node_path)
|
||||
|
||||
bld.add_subdirs(all_modules)
|
||||
|
||||
|
||||
class Ns3Header(Object.genobj):
|
||||
"""A set of NS-3 header files"""
|
||||
def __init__(self, env=None):
|
||||
Object.genobj.__init__(self, 'other')
|
||||
self.inst_var = 'INCLUDEDIR'
|
||||
self.inst_dir = 'ns3'
|
||||
self.env = env
|
||||
if not self.env:
|
||||
self.env = Params.g_build.m_allenvs['default']
|
||||
|
||||
def apply(self):
|
||||
ns3_dir_node = Params.g_build.m_srcnode.find_dir("ns3")
|
||||
inputs = []
|
||||
outputs = []
|
||||
for filename in self.to_list(self.source):
|
||||
src_node = self.path.find_source(filename)
|
||||
if src_node is None:
|
||||
Params.fatal("source ns3 header file %s not found" % (filename,))
|
||||
dst_node = ns3_dir_node.find_build(os.path.basename(filename))
|
||||
assert dst_node is not None
|
||||
inputs.append(src_node)
|
||||
outputs.append(dst_node)
|
||||
task = self.create_task('ns3_headers', self.env, 1)
|
||||
task.set_inputs(inputs)
|
||||
task.set_outputs(outputs)
|
||||
|
||||
def install(self):
|
||||
for i in self.m_tasks:
|
||||
current = Params.g_build.m_curdirnode
|
||||
lst = map(lambda a: a.relpath_gen(current), i.m_outputs)
|
||||
Common.install_files(self.inst_var, self.inst_dir, lst)
|
||||
|
||||
def _ns3_headers_inst(task):
|
||||
assert len(task.m_inputs) == len(task.m_outputs)
|
||||
inputs = [node.srcpath(task.m_env) for node in task.m_inputs]
|
||||
outputs = [node.bldpath(task.m_env) for node in task.m_outputs]
|
||||
for src, dst in zip(inputs, outputs):
|
||||
try:
|
||||
os.chmod(dst, 0600)
|
||||
except OSError:
|
||||
pass
|
||||
shutil.copy2(src, dst)
|
||||
## make the headers in builddir read-only, to prevent
|
||||
## accidental modification
|
||||
os.chmod(dst, 0400)
|
||||
return 0
|
||||
|
||||
239
wscript
239
wscript
@@ -1,78 +1,30 @@
|
||||
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
import os
|
||||
import sys
|
||||
import shlex
|
||||
import shutil
|
||||
|
||||
import Params
|
||||
import Object
|
||||
import Action
|
||||
import Common
|
||||
import shutil
|
||||
import subprocess
|
||||
import pproc as subprocess
|
||||
|
||||
Params.g_autoconfig = 1
|
||||
|
||||
# the following two variables are used by the target "waf dist"
|
||||
VERSION = '3.0.1'
|
||||
APPNAME = 'ns-3-waf'
|
||||
VERSION = file("VERSION").read().strip()
|
||||
APPNAME = 'ns'
|
||||
|
||||
# these variables are mandatory ('/' are converted automatically)
|
||||
srcdir = '.'
|
||||
blddir = 'build'
|
||||
|
||||
class Ns3Header(Object.genobj):
|
||||
"""A set of NS-3 header files"""
|
||||
def __init__(self, env=None):
|
||||
Object.genobj.__init__(self, 'other')
|
||||
self.inst_var = 'INCLUDEDIR'
|
||||
self.inst_dir = 'ns3'
|
||||
self.env = env
|
||||
if not self.env:
|
||||
self.env = Params.g_build.m_allenvs['default']
|
||||
|
||||
def apply(self):
|
||||
ns3_dir_node = Params.g_build.m_srcnode.find_dir("ns3")
|
||||
inputs = []
|
||||
outputs = []
|
||||
for filename in self.to_list(self.source):
|
||||
src_node = self.path.find_source(filename)
|
||||
if src_node is None:
|
||||
Params.fatal("source ns3 header file %s not found" % (filename,))
|
||||
dst_node = ns3_dir_node.find_build(os.path.basename(filename))
|
||||
assert dst_node is not None
|
||||
inputs.append(src_node)
|
||||
outputs.append(dst_node)
|
||||
task = self.create_task('ns3_headers', self.env, 1)
|
||||
task.set_inputs(inputs)
|
||||
task.set_outputs(outputs)
|
||||
|
||||
def install(self):
|
||||
for i in self.m_tasks:
|
||||
current = Params.g_build.m_curdirnode
|
||||
lst = map(lambda a: a.relpath_gen(current), i.m_outputs)
|
||||
Common.install_files(self.inst_var, self.inst_dir, lst)
|
||||
|
||||
def _ns3_headers_inst(task):
|
||||
assert len(task.m_inputs) == len(task.m_outputs)
|
||||
inputs = [node.srcpath(task.m_env) for node in task.m_inputs]
|
||||
outputs = [node.bldpath(task.m_env) for node in task.m_outputs]
|
||||
for src, dst in zip(inputs, outputs):
|
||||
try:
|
||||
os.chmod(dst, 0600)
|
||||
except OSError:
|
||||
pass
|
||||
shutil.copy2(src, dst)
|
||||
## make the headers in builddir read-only, to prevent
|
||||
## accidental modification
|
||||
os.chmod(dst, 0400)
|
||||
return 0
|
||||
|
||||
def init():
|
||||
Object.register('ns3header', Ns3Header)
|
||||
Action.Action('ns3_headers', func=_ns3_headers_inst, color='BLUE')
|
||||
def dist_hook(srcdir, blddir):
|
||||
shutil.rmtree("doc/html")
|
||||
shutil.rmtree("doc/latex")
|
||||
|
||||
def set_options(opt):
|
||||
# options provided by the modules
|
||||
if not opt.tool_options('msvc'):
|
||||
opt.tool_options('g++')
|
||||
opt.tool_options('compiler_cxx')
|
||||
|
||||
opt.add_option('--enable-gcov',
|
||||
help=('Enable code coverage analysis'),
|
||||
@@ -90,14 +42,22 @@ def set_options(opt):
|
||||
action="store_true", default=False,
|
||||
dest='doxygen')
|
||||
|
||||
opt.add_option('--run',
|
||||
help=('Run a locally built program'),
|
||||
type="string", default='', dest='run')
|
||||
|
||||
opt.add_option('--shell',
|
||||
help=('Run a shell with an environment suitably modified to run locally built programs'),
|
||||
action="store_true", default=False,
|
||||
dest='shell')
|
||||
|
||||
# options provided in a script in a subdirectory named "src"
|
||||
opt.sub_options('src')
|
||||
|
||||
|
||||
def configure(conf):
|
||||
if not conf.check_tool('msvc'):
|
||||
if not conf.check_tool('g++'):
|
||||
Params.fatal("No suitable compiler found")
|
||||
if not conf.check_tool('compiler_cxx'):
|
||||
Params.fatal("No suitable compiler found")
|
||||
|
||||
|
||||
# create the second environment, set the variant and set its name
|
||||
@@ -123,6 +83,9 @@ def configure(conf):
|
||||
variant_env.append_value('CXXDEFINES', 'NS3_DEBUG_ENABLE')
|
||||
variant_env.append_value('CXXDEFINES', 'NS3_ASSERT_ENABLE')
|
||||
|
||||
if sys.platform == 'win32':
|
||||
variant_env.append_value("LINKFLAGS", "-Wl,--enable-runtime-pseudo-reloc")
|
||||
|
||||
conf.sub_config('src')
|
||||
|
||||
|
||||
@@ -136,48 +99,126 @@ def build(bld):
|
||||
|
||||
|
||||
def shutdown():
|
||||
import UnitTest
|
||||
ut = UnitTest.unit_test()
|
||||
ut.change_to_testfile_dir = True
|
||||
ut.want_to_see_test_output = True
|
||||
ut.want_to_see_test_error = True
|
||||
ut.run()
|
||||
#import UnitTest
|
||||
#ut = UnitTest.unit_test()
|
||||
#ut.change_to_testfile_dir = True
|
||||
#ut.want_to_see_test_output = True
|
||||
#ut.want_to_see_test_error = True
|
||||
#ut.run()
|
||||
#ut.print_results()
|
||||
|
||||
if Params.g_commands['check']:
|
||||
run_program('run-tests')
|
||||
|
||||
if Params.g_options.lcov_report:
|
||||
env = Params.g_build.env_of_name('default')
|
||||
variant_name = env['NS3_ACTIVE_VARIANT']
|
||||
|
||||
if 'gcov' not in variant_name:
|
||||
Params.fatal("project not configured for code coverage;"
|
||||
" reconfigure with --enable-gcov")
|
||||
|
||||
os.chdir(blddir)
|
||||
try:
|
||||
lcov_report_dir = os.path.join(variant_name, 'lcov-report')
|
||||
create_dir_command = "rm -rf " + lcov_report_dir
|
||||
create_dir_command += " && mkdir " + lcov_report_dir + ";"
|
||||
|
||||
if subprocess.Popen(create_dir_command, shell=True).wait():
|
||||
raise SystemExit(1)
|
||||
|
||||
info_file = os.path.join(lcov_report_dir, variant_name + '.info')
|
||||
lcov_command = "../utils/lcov/lcov -c -d . -o " + info_file
|
||||
lcov_command += " --source-dirs=" + os.getcwd()
|
||||
lcov_command += ":" + os.path.join(
|
||||
os.getcwd(), variant_name, 'include')
|
||||
if subprocess.Popen(lcov_command, shell=True).wait():
|
||||
raise SystemExit(1)
|
||||
|
||||
genhtml_command = "../utils/lcov/genhtml -o " + lcov_report_dir
|
||||
genhtml_command += " " + info_file
|
||||
if subprocess.Popen(genhtml_command, shell=True).wait():
|
||||
raise SystemExit(1)
|
||||
finally:
|
||||
os.chdir("..")
|
||||
lcov_report()
|
||||
|
||||
if Params.g_options.doxygen:
|
||||
doxygen_config = os.path.join('doc', 'doxygen.conf')
|
||||
if subprocess.Popen(['doxygen', doxygen_config]).wait():
|
||||
doxygen()
|
||||
|
||||
if Params.g_options.run:
|
||||
run_program(Params.g_options.run)
|
||||
|
||||
elif Params.g_options.shell:
|
||||
run_shell()
|
||||
|
||||
def _find_program(program_name):
|
||||
for obj in Object.g_allobjs:
|
||||
if obj.target == program_name:
|
||||
return obj
|
||||
raise ValueError("progam '%s' not found" % (program_name,))
|
||||
|
||||
def _run_argv(argv):
|
||||
env = Params.g_build.env_of_name('default')
|
||||
if sys.platform == 'linux2':
|
||||
pathvar = 'LD_LIBRARY_PATH'
|
||||
pathsep = ':'
|
||||
elif sys.platform == 'darwin':
|
||||
pathvar = 'DYLD_LIBRARY_PATH'
|
||||
pathsep = ':'
|
||||
elif sys.platform == 'win32':
|
||||
pathvar = 'PATH'
|
||||
pathsep = ';'
|
||||
else:
|
||||
Params.warning(("Don't know how to configure "
|
||||
"dynamic library path for the platform '%s'") % (sys.platform,))
|
||||
pathvar = None
|
||||
pathsep = None
|
||||
|
||||
os_env = dict(os.environ)
|
||||
if pathvar is not None:
|
||||
if pathvar in os_env:
|
||||
os_env[pathvar] = pathsep.join([os_env[pathvar]] + list(env['NS3_MODULE_PATH']))
|
||||
else:
|
||||
os_env[pathvar] = pathsep.join(list(env['NS3_MODULE_PATH']))
|
||||
|
||||
retval = subprocess.Popen(argv, env=os_env).wait()
|
||||
if retval:
|
||||
raise SystemExit(retval)
|
||||
|
||||
|
||||
def run_program(program_string):
|
||||
env = Params.g_build.env_of_name('default')
|
||||
argv = shlex.split(program_string)
|
||||
program_name = argv[0]
|
||||
|
||||
try:
|
||||
program_obj = _find_program(program_name)
|
||||
except ValueError:
|
||||
Params.fatal("progam '%s' not found" % (program_name,))
|
||||
|
||||
try:
|
||||
program_node, = program_obj.m_linktask.m_outputs
|
||||
except AttributeError:
|
||||
Params.fatal("%s does not appear to be a program" % (program_name,))
|
||||
|
||||
execvec = [program_node.abspath(env)] + argv[1:]
|
||||
return _run_argv(execvec)
|
||||
|
||||
|
||||
def run_shell():
|
||||
if sys.platform == 'win32':
|
||||
shell = os.environ.get("COMSPEC", "cmd.exe")
|
||||
else:
|
||||
shell = os.environ.get("SHELL", "/bin/sh")
|
||||
_run_argv([shell])
|
||||
|
||||
|
||||
def doxygen():
|
||||
doxygen_config = os.path.join('doc', 'doxygen.conf')
|
||||
if subprocess.Popen(['doxygen', doxygen_config]).wait():
|
||||
raise SystemExit(1)
|
||||
|
||||
|
||||
def lcov_report():
|
||||
env = Params.g_build.env_of_name('default')
|
||||
variant_name = env['NS3_ACTIVE_VARIANT']
|
||||
|
||||
if 'gcov' not in variant_name:
|
||||
Params.fatal("project not configured for code coverage;"
|
||||
" reconfigure with --enable-gcov")
|
||||
|
||||
os.chdir(blddir)
|
||||
try:
|
||||
lcov_report_dir = os.path.join(variant_name, 'lcov-report')
|
||||
create_dir_command = "rm -rf " + lcov_report_dir
|
||||
create_dir_command += " && mkdir " + lcov_report_dir + ";"
|
||||
|
||||
if subprocess.Popen(create_dir_command, shell=True).wait():
|
||||
raise SystemExit(1)
|
||||
|
||||
info_file = os.path.join(lcov_report_dir, variant_name + '.info')
|
||||
lcov_command = "../utils/lcov/lcov -c -d . -o " + info_file
|
||||
lcov_command += " --source-dirs=" + os.getcwd()
|
||||
lcov_command += ":" + os.path.join(
|
||||
os.getcwd(), variant_name, 'include')
|
||||
if subprocess.Popen(lcov_command, shell=True).wait():
|
||||
raise SystemExit(1)
|
||||
|
||||
genhtml_command = "../utils/lcov/genhtml -o " + lcov_report_dir
|
||||
genhtml_command += " " + info_file
|
||||
if subprocess.Popen(genhtml_command, shell=True).wait():
|
||||
raise SystemExit(1)
|
||||
finally:
|
||||
os.chdir("..")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user