This commit is contained in:
Mathieu Lacage
2007-05-25 09:44:18 +02:00
45 changed files with 1811 additions and 1717 deletions

View File

@@ -1 +1,2 @@
56928998e05c9c11f5f3aefe79be8d2843e0db88 release ns-3.0.1
7ac5a4b0969b255c4824c926c2b37ef450136ce9 release ns-3.0.2

35
INSTALL
View File

@@ -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
View File

@@ -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"

View File

@@ -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.

View File

@@ -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',
])

View File

@@ -1 +1 @@
3.0.1
3.0.2

View File

@@ -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:

View File

@@ -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

View File

@@ -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
----------

View File

@@ -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
View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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
*

View File

@@ -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

View File

@@ -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

View File

@@ -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',
]

View File

@@ -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 ())

View File

@@ -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);
}

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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

View File

@@ -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 */

View File

@@ -23,7 +23,7 @@
#include <vector>
#include <algorithm>
#include <stdint.h>
/**
* \defgroup randomvariable Random Variable Distributions

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -20,6 +20,7 @@
#ifndef RNGSTREAM_H
#define RNGSTREAM_H
#include <string>
#include <stdint.h>
namespace ns3{

View File

@@ -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:
};

View File

@@ -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',

View File

@@ -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;

View File

@@ -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
};

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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;
};

View File

@@ -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;
}

View File

@@ -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++)
{

View File

@@ -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;

View File

@@ -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;

View File

@@ -55,7 +55,7 @@ class EventImpl;
class Scheduler {
public:
struct EventKey {
uint64_t m_ns;
uint64_t m_ts;
uint32_t m_uid;
};

View File

@@ -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 ();

View File

@@ -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));
}

View File

@@ -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;
};

View File

@@ -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
View File

@@ -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("..")