diff --git a/.hgtags b/.hgtags index f7a167162..b812011d2 100644 --- a/.hgtags +++ b/.hgtags @@ -1 +1,2 @@ 56928998e05c9c11f5f3aefe79be8d2843e0db88 release ns-3.0.1 +7ac5a4b0969b255c4824c926c2b37ef450136ce9 release ns-3.0.2 diff --git a/INSTALL b/INSTALL deleted file mode 100644 index 36b34f92d..000000000 --- a/INSTALL +++ /dev/null @@ -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 - diff --git a/README b/README index c1a85a736..a2bf6ea42 100644 --- a/README +++ b/README @@ -1,9 +1,9 @@ - The Network Simulator Version 3 - ------------------------------- + The Network Simulator, Version 3 + -------------------------------- -Table of Content: ------------------ +Table of Contents: +------------------ 1) An Open Source project 2) An overview of the ns-3 project @@ -16,7 +16,7 @@ Table of Content: 1) An Open Source project ------------------------- -ns-3 is an Open Source project and we intend to make this +ns-3 is an Open Source project. We intend to make this project a successful collaborative project: we hope that the missing pieces of the models we have not yet implemented will be contributed by the community in an open collaboration @@ -25,11 +25,11 @@ process. Contributing to the ns-3 project is still a very informal process because that process depends heavily on the personality of the people involved, the amount of time they can invest -and the type of model they want to work on. +and the type of model they want to work on. Despite this lack of a formal process, there are a number of steps which naturally stem from the open-source roots of the -project. These steps are described in doc/contributing.txt +project. These steps are described in doc/contributing.txt 2) An overview of the ns-3 project ---------------------------------- @@ -42,8 +42,9 @@ number of very simple network simulation models: - point-to-point physical-layer links - OnOff traffic generator -However, the framework is there to make adding new models as -simple as possible: +Our focus to date has been on getting an overall software +framework in place. The framework is there to make adding +new models as simple as possible: - an extensive tracing system can be used to connect any number of arbitrary trace sources to any number of trace sinks. This tracing system is decoupled @@ -65,7 +66,7 @@ simple as possible: The code for the framework and the default models provided by ns-3 is built as a set of libraries. User simulations -are expected to be written as simple programs which make +are expected to be written as simple programs that make use of these ns-3 libraries. To build the set of default libraries and the example @@ -84,7 +85,8 @@ found in the 'examples' directory. The current codebase is expected to build and run on the following set of platforms: - - linux x86 gcc 4.1, gcc 3.4. + - linux x86 gcc 4.2, 4.1, and, 3.4. + - linux x86_64 gcc 4.0 - MacOS X ppc and x86 The current codebase is expected to fail to build on @@ -92,14 +94,14 @@ the following platforms: - gcc 3.3 and earlier - optimized builds on linux x86 gcc 4.0 -Other platforms might or might not work: we welcome +Other platforms may or may not work: we welcome patches to improve the portability of the code to these other platforms. 4) Running ns-3 --------------- -On Recent Linux systems, once you have built ns-3, it +On recent Linux systems, once you have built ns-3, it should be easy to run the sample programs with the following command: @@ -112,7 +114,7 @@ cd build-dir/dbg-shared/bin That program should generate a simple-p2p.tr text trace file and a set of simple-p2p-xx-xx.pcap binary -pcap trace files. +pcap trace files, which can be read by tcpdump. 5) Getting access to the ns-3 documentation ------------------------------------------- @@ -123,18 +125,17 @@ quite likely that you will want to get started on reading some ns-3 documentation. All of that documentation should always be available from -the ns-3 website: http:://www.nsnam.org/ +the ns-3 website: http:://www.nsnam.org/ but we +include some of it in this release for ease of use. -It includes: +This documentation includes: - an architecture document which describes a very high-level view of ns-3: it tries to explain the use-cases the ns-3 developers really focused on when doing the initial design and then goes on to explain the structure of the resulting framework. - XXX introduce url link - - - a user manual: XXX + See the file doc/architecture.pdf - a wiki for user-contributed tips: http://www.nsnam.org/wiki/ @@ -143,6 +144,17 @@ It includes: as introductory text: http://www.nsnam.org/doxygen/index.html +If you want to re-generate this documentation, you can +easily do so: + + - doc/architecture.pdf is generated from the architecture.tex + file in http://code.nsnam.org/docs + + - the doxygen documentation is generated from the doc/doxygen.conf + configuration file. The command "scons doc" will generate it + as doc/html/index.html if you have installed the doxygen tools + (see http://www.doxygen.org) + 6) Working with the development version of ns-3 ----------------------------------------------- @@ -156,4 +168,4 @@ familiar with it. If you have successfully installed mercurial, you can get a copy of the development version with the following command: -"hg clone http://code.nsnam.org/ns-3-dev" \ No newline at end of file +"hg clone http://code.nsnam.org/ns-3-dev" diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 5e0c28ee7..8e02e3ee2 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -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. diff --git a/SConstruct b/SConstruct index de8e80656..d361b4651 100644 --- a/SConstruct +++ b/SConstruct @@ -2,19 +2,27 @@ import os.path import build +version_file = open ('VERSION', 'r') +version = version_file.readline () +version_file.close () +version = version.strip () + ns3 = build.Ns3() ns3.build_dir = 'build-dir' -ns3.version = '0.2' +ns3.version = version ns3.name = 'ns3' -ns3.distname = 'ns-3' +ns3.distname = 'ns' ns3.doxygen_config = os.path.join('doc', 'doxygen.conf') ns3.add_extra_dist(os.path.join('doc', 'main.txt')) +ns3.add_extra_dist ('doc/architecture.pdf') ns3.add_extra_dist ('doc/contributing.txt') ns3.add_extra_dist ('doc/build.txt') +ns3.add_extra_dist ('doc/codingstd.txt') ns3.add_extra_dist ('doc/mercurial.txt') ns3.add_extra_dist ('README') ns3.add_extra_dist ('RELEASE_NOTES') ns3.add_extra_dist ('AUTHORS') +ns3.add_extra_dist ('VERSION') # @@ -23,7 +31,6 @@ ns3.add_extra_dist ('AUTHORS') core = build.Ns3Module('core', 'src/core') ns3.add(core) core.add_sources([ - 'reference-list-test.cc', 'callback-test.cc', 'debug.cc', 'assert.cc', @@ -56,7 +63,6 @@ core.add_headers ([ ]) core.add_inst_headers([ 'system-wall-clock-ms.h', - 'reference-list.h', 'callback.h', 'ptr.h', 'object.h', @@ -196,8 +202,6 @@ common.add_inst_headers([ 'array-trace-resolver.h', 'trace-root.h', 'terminal-trace-resolver.h', - 'smartvector.h', - 'smartset.h', 'data-rate.h', ]) diff --git a/VERSION b/VERSION index cb2b00e4f..b50214693 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.1 +3.0.2 diff --git a/build.py b/build.py index 25a38e4fa..c486ab171 100644 --- a/build.py +++ b/build.py @@ -504,7 +504,7 @@ class Ns3: # dist support dist_env = env.Copy() - if dist_env['PLATFORM'] == 'posix': + if dist_env['PLATFORM'] == 'posix' or dist_env['PLATFORM'] == 'darwin': dist_list = [] for module in self.__modules: for f in module.sources: diff --git a/doc/build-waf.txt b/doc/build-waf.txt index a560b3bff..056a45274 100644 --- a/doc/build-waf.txt +++ b/doc/build-waf.txt @@ -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 diff --git a/doc/build.txt b/doc/build.txt index 4cf112c0e..e724529d3 100644 --- a/doc/build.txt +++ b/doc/build.txt @@ -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 ---------- diff --git a/doc/codingstd.tex b/doc/codingstd.tex deleted file mode 100644 index 8845f6248..000000000 --- a/doc/codingstd.tex +++ /dev/null @@ -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 }), 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 \\ -\#include \\ -\#include \\ - -\#include "application.h" \\ -\#include "dumbbell.h" \\ -\#include "simulator.h" \\ -\#include "tcp.h.h" - -\end{tt} -\end{enumerate} -\end{document} diff --git a/doc/codingstd.txt b/doc/codingstd.txt new file mode 100644 index 000000000..6369035e9 --- /dev/null +++ b/doc/codingstd.txt @@ -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 + */ + +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 + */ +#include "my-class.h" + +namespace ns3 { + +MyClass::MyClass () +{} + +... + +} // namespace ns3 + diff --git a/doc/contributing.txt b/doc/contributing.txt index f0a8b7b83..13da6989d 100644 --- a/doc/contributing.txt +++ b/doc/contributing.txt @@ -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 diff --git a/doc/mercurial.txt b/doc/mercurial.txt index 5e6f8cb4a..fefc88f39 100644 --- a/doc/mercurial.txt +++ b/doc/mercurial.txt @@ -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 diff --git a/src/common/data-rate.cc b/src/common/data-rate.cc index 1bcb5498c..705da04bd 100644 --- a/src/common/data-rate.cc +++ b/src/common/data-rate.cc @@ -147,6 +147,36 @@ uint64_t DataRate::Parse(const std::string s) return v; } +bool DataRate::operator < (const DataRate& rhs) +{ + return m_bps (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(bytes)*8/m_bps; diff --git a/src/common/data-rate.h b/src/common/data-rate.h index dd1c9bda5..1e5db50f9 100644 --- a/src/common/data-rate.h +++ b/src/common/data-rate.h @@ -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 * diff --git a/src/common/smartset.h b/src/common/smartset.h deleted file mode 100644 index 61e9d7d0d..000000000 --- a/src/common/smartset.h +++ /dev/null @@ -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 -// - -#ifndef __SMART_SET_H__ -#define __SMART_SET_H__ - -#include - -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 class SmartSet { -public: - typedef typename std::set::const_iterator const_iterator; - typedef typename std::set::iterator iterator; - typedef typename std::set::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 m_elements; -}; - -} // namespace ns3 -#endif diff --git a/src/common/smartvector.h b/src/common/smartvector.h deleted file mode 100644 index fc76b19dc..000000000 --- a/src/common/smartvector.h +++ /dev/null @@ -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 -// - -#ifndef __SMART_VECTOR_H__ -#define __SMART_VECTOR_H__ - -#include - -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 class SmartVector { -public: - typedef typename std::vector::const_iterator const_iterator; - typedef typename std::vector::iterator iterator; - typedef typename std::vector::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 m_elements; -}; - -} // Namespace ns3 -#endif diff --git a/src/common/wscript b/src/common/wscript index 76c4214f0..b62e204b2 100644 --- a/src/common/wscript +++ b/src/common/wscript @@ -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', ] diff --git a/src/core/callback-test.cc b/src/core/callback-test.cc index 4cc1b77fb..9e8cf259f 100644 --- a/src/core/callback-test.cc +++ b/src/core/callback-test.cc @@ -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 a2; if (IsWrong ()) diff --git a/src/core/callback.h b/src/core/callback.h index 9904a9818..efeb44be2 100644 --- a/src/core/callback.h +++ b/src/core/callback.h @@ -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 +struct CallbackTraits; + +template +struct CallbackTraits +{ + 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 { public: FunctorCallbackImpl (T const &functor) - : m_functor (functor) {} + : m_functor (functor) {} virtual ~FunctorCallbackImpl () {} R operator() (void) { return m_functor (); @@ -158,25 +183,25 @@ template { 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::GetReference (m_objPtr)).*m_memPtr) (); } R operator() (T1 a1) { - return ((*m_objPtr).*m_memPtr) (a1); + return ((CallbackTraits::GetReference (m_objPtr)).*m_memPtr) (a1); } R operator() (T1 a1,T2 a2) { - return ((*m_objPtr).*m_memPtr) (a1,a2); + return ((CallbackTraits::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::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::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::GetReference (m_objPtr)).*m_memPtr) (a1, a2, a3, a4, a5); } virtual bool IsEqual (CallbackImplBase const *other) const { MemPtrCallbackImpl const *otherDerived = @@ -242,40 +267,43 @@ public: // always properly disambiguited by the c++ compiler template Callback (FUNCTOR const &functor, bool, bool) - : m_impl (new FunctorCallbackImpl (functor)) + : m_impl (MakeNewObject > (functor)) {} template Callback (OBJ_PTR const &objPtr, MEM_PTR mem_ptr) - : m_impl (new MemPtrCallbackImpl (objPtr, mem_ptr)) + : m_impl (MakeNewObject > (objPtr, mem_ptr)) {} - Callback (ReferenceList *> const &impl) + Callback (Ptr > 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 *PeekImpl (void) const { + return PeekPointer (m_impl); } - ReferenceList*> m_impl; + Ptr > m_impl; }; /** @@ -323,12 +351,12 @@ private: * Build Callbacks for class method members which takes no arguments * and potentially return a value. */ -template -Callback MakeCallback (R (OBJ::*mem_ptr) (), OBJ *const objPtr) { - return Callback (objPtr, mem_ptr); +template +Callback MakeCallback (R (T::*memPtr) (void), OBJ objPtr) { + return Callback (objPtr, memPtr); } -template -Callback MakeCallback (R (OBJ::*mem_ptr) () const, OBJ const *const objPtr) { +template +Callback MakeCallback (R (T::*mem_ptr) () const, OBJ const objPtr) { return Callback (objPtr, mem_ptr); } /** @@ -339,12 +367,12 @@ Callback 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 -Callback MakeCallback (R (OBJ::*mem_ptr) (T1), OBJ *const objPtr) { +template +Callback MakeCallback (R (T::*mem_ptr) (T1), OBJ *const objPtr) { return Callback (objPtr, mem_ptr); } -template -Callback MakeCallback (R (OBJ::*mem_ptr) (T1) const, OBJ const *const objPtr) { +template +Callback MakeCallback (R (T::*mem_ptr) (T1) const, OBJ const *const objPtr) { return Callback (objPtr, mem_ptr); } /** @@ -355,12 +383,12 @@ Callback 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 -Callback MakeCallback (R (OBJ::*mem_ptr) (T1,T2), OBJ *const objPtr) { +template +Callback MakeCallback (R (T::*mem_ptr) (T1,T2), OBJ *const objPtr) { return Callback (objPtr, mem_ptr); } -template -Callback MakeCallback (R (OBJ::*mem_ptr) (T1,T2) const, OBJ const*const objPtr) { +template +Callback MakeCallback (R (T::*mem_ptr) (T1,T2) const, OBJ const*const objPtr) { return Callback (objPtr, mem_ptr); } /** @@ -371,12 +399,12 @@ Callback 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 -Callback MakeCallback (R (OBJ::*mem_ptr) (T1,T2,T3), OBJ *const objPtr) { +template +Callback MakeCallback (R (T::*mem_ptr) (T1,T2,T3), OBJ *const objPtr) { return Callback (objPtr, mem_ptr); } -template -Callback MakeCallback (R (OBJ::*mem_ptr) (T1,T2,T3) const, OBJ const*const objPtr) { +template +Callback MakeCallback (R (T::*mem_ptr) (T1,T2,T3) const, OBJ const*const objPtr) { return Callback (objPtr, mem_ptr); } /** @@ -387,12 +415,12 @@ Callback 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 -Callback MakeCallback (R (OBJ::*mem_ptr) (T1,T2,T3,T4), OBJ *const objPtr) { +template +Callback MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4), OBJ *const objPtr) { return Callback (objPtr, mem_ptr); } -template -Callback MakeCallback (R (OBJ::*mem_ptr) (T1,T2,T3,T4) const, OBJ const*const objPtr) { +template +Callback MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4) const, OBJ const*const objPtr) { return Callback (objPtr, mem_ptr); } /** @@ -403,12 +431,12 @@ Callback 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 -Callback MakeCallback (R (OBJ::*mem_ptr) (T1,T2,T3,T4,T5), OBJ *const objPtr) { +template +Callback MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5), OBJ *const objPtr) { return Callback (objPtr, mem_ptr); } -template -Callback MakeCallback (R (OBJ::*mem_ptr) (T1,T2,T3,T4,T5) const, OBJ const*const objPtr) { +template +Callback MakeCallback (R (T::*mem_ptr) (T1,T2,T3,T4,T5) const, OBJ const*const objPtr) { return Callback (objPtr, mem_ptr); } @@ -599,44 +627,34 @@ private: template Callback MakeBoundCallback (R (*fnPtr) (TX), TX a) { - ReferenceList*> impl = - ReferenceList*> ( - new BoundFunctorCallbackImpl (fnPtr, a) - ); + Ptr > impl = + MakeNewObject >(fnPtr, a); return Callback (impl); } template Callback MakeBoundCallback (R (*fnPtr) (TX,T1), TX a) { - ReferenceList*> impl = - ReferenceList*> ( - new BoundFunctorCallbackImpl (fnPtr, a) - ); + Ptr > impl = + MakeNewObject > (fnPtr, a); return Callback (impl); } template Callback MakeBoundCallback (R (*fnPtr) (TX,T1,T2), TX a) { - ReferenceList*> impl = - ReferenceList*> ( - new BoundFunctorCallbackImpl (fnPtr, a) - ); + Ptr > impl = + MakeNewObject > (fnPtr, a); return Callback (impl); } template Callback MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3,T4), TX a) { - ReferenceList*> impl = - ReferenceList*> ( - new BoundFunctorCallbackImpl (fnPtr, a) - ); + Ptr > impl = + MakeNewObject > (fnPtr, a); return Callback (impl); } template Callback MakeBoundCallback (R (*fnPtr) (TX,T1,T2,T3,T4,T5), TX a) { - ReferenceList*> impl = - ReferenceList*> ( - new BoundFunctorCallbackImpl (fnPtr, a) - ); + Ptr > impl = + MakeNewObject > (fnPtr, a); return Callback (impl); } diff --git a/src/core/default-value.h b/src/core/default-value.h index cc72547d5..6f9f98508 100644 --- a/src/core/default-value.h +++ b/src/core/default-value.h @@ -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::GetValue (void) return m_value; } template +void +EnumDefaultValue::SetValue (T value) +{ + m_value = value; +} +template bool EnumDefaultValue::DoParseValue (const std::string &value) { diff --git a/src/core/ptr.cc b/src/core/ptr.cc index 77b19fcd9..275a11324 100644 --- a/src/core/ptr.cc +++ b/src/core/ptr.cc @@ -33,7 +33,7 @@ class NoCount : public Object public: NoCount (Callback cb); ~NoCount (); - void Nothing () const; + void Nothing (void) const; private: Callback m_cb; }; @@ -280,6 +280,25 @@ PtrTest::RunTests (void) ok = false; } } + + { + Ptr p = MakeNewObject (cb); + Callback callback = MakeCallback (&NoCount::Nothing, p); + callback (); + } + { + Ptr p = MakeNewObject (cb); + Callback callback = MakeCallback (&NoCount::Nothing, p); + callback (); + } + +#if 0 + // as expected, fails compilation. + { + Ptr p = MakeNewObject (cb); + Callback callback = MakeCallback (&NoCount::Nothing, p); + } +#endif return ok; diff --git a/src/core/ptr.h b/src/core/ptr.h index 0c9efc07e..5b4ae1538 100644 --- a/src/core/ptr.h +++ b/src/core/ptr.h @@ -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 const &lhs, Ptr const &rhs); template Ptr const_pointer_cast (Ptr const&p); +template +struct CallbackTraits; + +template +struct CallbackTraits > +{ + static T & GetReference (Ptr const p) + { + return *PeekPointer (p); + } +}; + +template +struct EventMemberImplTraits; + +template +struct EventMemberImplTraits > +{ + static T &GetReference (Ptr p) { + return *PeekPointer (p); + } +}; + + + } // namespace ns3 diff --git a/src/core/random-variable.cc b/src/core/random-variable.cc index c797841e1..824778c29 100644 --- a/src/core/random-variable.cc +++ b/src/core/random-variable.cc @@ -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 + +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 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::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 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::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 */ diff --git a/src/core/random-variable.h b/src/core/random-variable.h index 9901b665a..1007e878d 100644 --- a/src/core/random-variable.h +++ b/src/core/random-variable.h @@ -23,7 +23,7 @@ #include #include - +#include /** * \defgroup randomvariable Random Variable Distributions diff --git a/src/core/reference-list-test.cc b/src/core/reference-list-test.cc deleted file mode 100644 index fdbad33ac..000000000 --- a/src/core/reference-list-test.cc +++ /dev/null @@ -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 - */ -#include "reference-list.h" -#include "test.h" - -#ifdef RUN_SELF_TESTS - -#define noREFTEST_DEBUG 1 - -#ifdef REFTEST_DEBUG -#include -#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); -}; - -RefTest::RefTest () - : ns3::Test ("ReferenceList") -{} - -void -RefTest::OneTest (ns3::ReferenceList a) -{ - a->Trace (); -} - -bool -RefTest::RunTests (void) -{ - bool ok = true; - - { - ns3::ReferenceList tmp; - { - ns3::ReferenceList 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 tmp; - } - - { - ns3::ReferenceList tmp (new A ()); - } - - { - ns3::ReferenceList tmp; - tmp.Set (new A ()); - } - - { - TRACE ("test assignement"); - ns3::ReferenceList a0 (new A ()); - ns3::ReferenceList a1 (new A ()); - a0 = a1; - } - - - - return ok; -} - - -static RefTest gRefTest = RefTest (); - -}; // namespace - -#endif /* RUN_SELF_TESTS */ diff --git a/src/core/reference-list.h b/src/core/reference-list.h deleted file mode 100644 index 08a4452bb..000000000 --- a/src/core/reference-list.h +++ /dev/null @@ -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 - */ -#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 -class ReferenceList; - -template -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 */ diff --git a/src/core/rng-stream.h b/src/core/rng-stream.h index efdfb47c6..6c1c56eed 100644 --- a/src/core/rng-stream.h +++ b/src/core/rng-stream.h @@ -20,6 +20,7 @@ #ifndef RNGSTREAM_H #define RNGSTREAM_H #include +#include namespace ns3{ diff --git a/src/core/win32-system-wall-clock-ms.cc b/src/core/win32-system-wall-clock-ms.cc index db81d580c..8043d2589 100644 --- a/src/core/win32-system-wall-clock-ms.cc +++ b/src/core/win32-system-wall-clock-ms.cc @@ -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: }; diff --git a/src/core/wscript b/src/core/wscript index 3131d55c8..703951031 100644 --- a/src/core/wscript +++ b/src/core/wscript @@ -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', diff --git a/src/internet-node/udp-socket.cc b/src/internet-node/udp-socket.cc index 8c6c3dcfc..dd58652ad 100644 --- a/src/internet-node/udp-socket.cc +++ b/src/internet-node/udp-socket.cc @@ -30,7 +30,7 @@ UdpSocket::UdpSocket (Ptr node, Ptr 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, const Ipv4Address&, uint16_ ns3::Callback > 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; diff --git a/src/node/socket.h b/src/node/socket.h index ee710ca75..1c352e166 100644 --- a/src/node/socket.h +++ b/src/node/socket.h @@ -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 }; diff --git a/src/simulator/event-id.cc b/src/simulator/event-id.cc index 84e6dfa97..7357070b0 100644 --- a/src/simulator/event-id.cc +++ b/src/simulator/event-id.cc @@ -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 diff --git a/src/simulator/event-id.h b/src/simulator/event-id.h index 2803db6cf..a7514289d 100644 --- a/src/simulator/event-id.h +++ b/src/simulator/event-id.h @@ -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; }; diff --git a/src/simulator/nstime.h b/src/simulator/nstime.h index cfa07f0eb..2958f2f3e 100644 --- a/src/simulator/nstime.h +++ b/src/simulator/nstime.h @@ -22,12 +22,42 @@ #define TIME_H #include +#include #include "ns3/assert.h" #include #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 operator * (TimeUnit const &lhs, TimeUnit const &rhs) { HighPrecision retval = lhs.GetHighPrecision (); retval.Mul (rhs.GetHighPrecision ()); + // std::cout << lhs.GetHighPrecision().GetInteger() << " * " + // << rhs.GetHighPrecision().GetInteger() + // << " = " << retval.GetInteger() << std::endl; return TimeUnit (retval); } template @@ -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; }; diff --git a/src/simulator/scheduler-factory.cc b/src/simulator/scheduler-factory.cc index fff4914bb..760b2ea8b 100644 --- a/src/simulator/scheduler-factory.cc +++ b/src/simulator/scheduler-factory.cc @@ -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; } diff --git a/src/simulator/scheduler-heap.cc b/src/simulator/scheduler-heap.cc index 746691be8..a73e38719 100644 --- a/src/simulator/scheduler-heap.cc +++ b/src/simulator/scheduler-heap.cc @@ -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++) { diff --git a/src/simulator/scheduler-list.cc b/src/simulator/scheduler-list.cc index 71eaa8337..fe5b3317b 100644 --- a/src/simulator/scheduler-list.cc +++ b/src/simulator/scheduler-list.cc @@ -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; diff --git a/src/simulator/scheduler-map.cc b/src/simulator/scheduler-map.cc index 75f1fccaa..46ad3bae5 100644 --- a/src/simulator/scheduler-map.cc +++ b/src/simulator/scheduler-map.cc @@ -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 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; diff --git a/src/simulator/scheduler.h b/src/simulator/scheduler.h index 02566c83d..150aa16fc 100644 --- a/src/simulator/scheduler.h +++ b/src/simulator/scheduler.h @@ -55,7 +55,7 @@ class EventImpl; class Scheduler { public: struct EventKey { - uint64_t m_ns; + uint64_t m_ts; uint32_t m_uid; }; diff --git a/src/simulator/simulator.cc b/src/simulator/simulator.cc index 0b499ecff..226f7357a 100644 --- a/src/simulator/simulator.cc +++ b/src/simulator/simulator.cc @@ -72,7 +72,7 @@ public: private: void ProcessOneEvent (void); - uint64_t NextNs (void) const; + uint64_t NextTs (void) const; typedef std::list > 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 "<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 "<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 (this)); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar1, Ptr (this), 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar2, Ptr (this), 0, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar3, Ptr (this), 0, 0, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar4, Ptr (this), 0, 0, 0, 0); + Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar5, Ptr (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 (this)); + Simulator::ScheduleNow (&SimulatorTests::bar1, Ptr (this), 0); + Simulator::ScheduleNow (&SimulatorTests::bar2, Ptr (this), 0, 0); + Simulator::ScheduleNow (&SimulatorTests::bar3, Ptr (this), 0, 0, 0); + Simulator::ScheduleNow (&SimulatorTests::bar4, Ptr (this), 0, 0, 0, 0); + Simulator::ScheduleNow (&SimulatorTests::bar5, Ptr (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 (this)); + Simulator::ScheduleDestroy (&SimulatorTests::bar1, Ptr (this), 0); + Simulator::ScheduleDestroy (&SimulatorTests::bar2, Ptr (this), 0, 0); + Simulator::ScheduleDestroy (&SimulatorTests::bar3, Ptr (this), 0, 0, 0); + Simulator::ScheduleDestroy (&SimulatorTests::bar4, Ptr (this), 0, 0, 0, 0); + Simulator::ScheduleDestroy (&SimulatorTests::bar5, Ptr (this), 0, 0, 0, 0, 0); Simulator::Run (); Simulator::Destroy (); diff --git a/src/simulator/simulator.h b/src/simulator/simulator.h index 1c71668df..02cf6741c 100644 --- a/src/simulator/simulator.h +++ b/src/simulator/simulator.h @@ -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 - static EventId Schedule (Time const &time, void (T::*mem_ptr) (void), T *obj); + template + 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 - static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1), T* obj, T1 a1); + template + 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 - static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1,T2), T* obj, T1 a1, T2 a2); + template + 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 - static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3), T* obj, T1 a1, T2 a2, T3 a3); + template + 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 - 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 + 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 - 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 + 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 - static void ScheduleNow (void (T::*mem_ptr) (void), T *obj); + template + 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 - static void ScheduleNow (void (T::*mem_ptr) (T1), T* obj, T1 a1); + template + 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 - static void ScheduleNow (void (T::*mem_ptr) (T1,T2), T* obj, T1 a1, T2 a2); + template + 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 - static void ScheduleNow (void (T::*mem_ptr) (T1,T2,T3), T* obj, T1 a1, T2 a2, T3 a3); + template + 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 - static void ScheduleNow (void (T::*mem_ptr) (T1,T2,T3,T4), T* obj, + template + 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 - static void ScheduleNow (void (T::*mem_ptr) (T1,T2,T3,T4,T5), T* obj, + template + 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 - static void ScheduleDestroy (void (T::*mem_ptr) (void), T *obj); + template + 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 - static void ScheduleDestroy (void (T::*mem_ptr) (T1), T* obj, T1 a1); + template + 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 - static void ScheduleDestroy (void (T::*mem_ptr) (T1,T2), T* obj, T1 a1, T2 a2); + template + 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 - static void ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3), T* obj, T1 a1, T2 a2, T3 a3); + template + 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 - static void ScheduleDestroy (void (T::*mem_ptr) (T1,T2,T3,T4), T* obj, - T1 a1, T2 a2, T3 a3, T4 a4); + template + 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 - 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 + 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 - static EventImpl *MakeEvent (void (T::*mem_ptr) (void), T *obj); - template - static EventImpl *MakeEvent (void (T::*mem_ptr) (T1), T* obj, T1 a1); - template - static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2), T* obj, T1 a1, T2 a2); - template - static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2,T3), T* obj, T1 a1, T2 a2, T3 a3); - template - static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2,T3,T4), T* obj, T1 a1, T2 a2, T3 a3, T4 a4); - template - 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 + static EventImpl *MakeEvent (void (T::*mem_ptr) (void), OBJ obj); + template + static EventImpl *MakeEvent (void (T::*mem_ptr) (T1), OBJ obj, T1 a1); + template + static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2); + template + static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2,T3), OBJ obj, T1 a1, T2 a2, T3 a3); + template + static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2,T3,T4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4); + template + 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 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 -EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (void), T *obj) +struct EventMemberImplTraits; + +template +struct EventMemberImplTraits +{ + static T &GetReference (T *p) { + return *p; + } +}; + +template +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::GetReference (m_obj).*m_function) (); + } + OBJ m_obj; + F m_function; } *ev = new EventMemberImpl0 (obj, mem_ptr); return ev; } -template -EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1), T* obj, T1 a1) +template +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::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 -EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1,T2), T* obj, T1 a1, T2 a2) +template +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::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 -EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1,T2,T3), T* obj, T1 a1, T2 a2, T3 a3) +template +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::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 -EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1,T2,T3,T4), T* obj, T1 a1, T2 a2, T3 a3, T4 a4) +template +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::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 -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 +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::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 -EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (void), T *obj) +template +EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (void), OBJ obj) { return Schedule (time, MakeEvent (mem_ptr, obj)); } -template -EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1), T* obj, T1 a1) +template +EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1), OBJ obj, T1 a1) { return Schedule (time, MakeEvent (mem_ptr, obj, a1)); } -template -EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1,T2), T* obj, T1 a1, T2 a2) +template +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 -EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3), T* obj, T1 a1, T2 a2, T3 a3) +template +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 -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 +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 -EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1,T2,T3,T4,T5), T* obj, +template +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 +template 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 +template 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 +template 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 +template 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 +template 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 +template 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 +template 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 +template 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 +template 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 +template 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 +template 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 +template 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)); } diff --git a/src/simulator/time.cc b/src/simulator/time.cc index 184e57c99..9943269a0 100644 --- a/src/simulator/time.cc +++ b/src/simulator/time.cc @@ -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 + * TimeStep support by Emmanuelle Laprise */ -#include "time.h" -#include "simulator.h" +#include "nstime.h" #include "ns3/fatal-error.h" +#include "ns3/default-value.h" +#include 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 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 "<::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="< 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; }; diff --git a/src/wscript b/src/wscript index 614dccbae..551a26e1b 100644 --- a/src/wscript +++ b/src/wscript @@ -1,7 +1,14 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- +import os +import shutil + +import Action +import Common +import Object import Params + all_modules = [ 'core', 'common', @@ -15,29 +22,68 @@ all_modules = [ def set_options(opt): opt.sub_options('simulator') - opt.add_option('--disable-rpath', - help=("Don't link programs with rpath"), - action="store_true", default=False, - dest='disable_rpath') - - + def configure(conf): conf.sub_config('core') conf.sub_config('simulator') - conf.env['DISABLE_RPATH'] = Params.g_options.disable_rpath - def build(bld): + Object.register('ns3header', Ns3Header) + Action.Action('ns3_headers', func=_ns3_headers_inst, color='BLUE') - ## Add a global RPATH pointing to each module, so that programs can find the libs - ## Note: this is slightly evil; we get away because our programs - ## and libs are not supposed to be installed system wide. env = bld.env_of_name('default') - if not env['DISABLE_RPATH']: - for module in all_modules: - node = bld.m_curdirnode.find_dir(module) - env.append_value('RPATH', '-Wl,--rpath=%s' % (node.abspath(env),)) + for module in all_modules: + node = bld.m_curdirnode.find_dir(module) + node_path = node.abspath(env) + env.append_value('NS3_MODULE_PATH', node_path) bld.add_subdirs(all_modules) + +class Ns3Header(Object.genobj): + """A set of NS-3 header files""" + def __init__(self, env=None): + Object.genobj.__init__(self, 'other') + self.inst_var = 'INCLUDEDIR' + self.inst_dir = 'ns3' + self.env = env + if not self.env: + self.env = Params.g_build.m_allenvs['default'] + + def apply(self): + ns3_dir_node = Params.g_build.m_srcnode.find_dir("ns3") + inputs = [] + outputs = [] + for filename in self.to_list(self.source): + src_node = self.path.find_source(filename) + if src_node is None: + Params.fatal("source ns3 header file %s not found" % (filename,)) + dst_node = ns3_dir_node.find_build(os.path.basename(filename)) + assert dst_node is not None + inputs.append(src_node) + outputs.append(dst_node) + task = self.create_task('ns3_headers', self.env, 1) + task.set_inputs(inputs) + task.set_outputs(outputs) + + def install(self): + for i in self.m_tasks: + current = Params.g_build.m_curdirnode + lst = map(lambda a: a.relpath_gen(current), i.m_outputs) + Common.install_files(self.inst_var, self.inst_dir, lst) + +def _ns3_headers_inst(task): + assert len(task.m_inputs) == len(task.m_outputs) + inputs = [node.srcpath(task.m_env) for node in task.m_inputs] + outputs = [node.bldpath(task.m_env) for node in task.m_outputs] + for src, dst in zip(inputs, outputs): + try: + os.chmod(dst, 0600) + except OSError: + pass + shutil.copy2(src, dst) + ## make the headers in builddir read-only, to prevent + ## accidental modification + os.chmod(dst, 0400) + return 0 diff --git a/wscript b/wscript index a15f4e78a..7e12cd170 100644 --- a/wscript +++ b/wscript @@ -1,78 +1,30 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- import os +import sys +import shlex +import shutil import Params import Object -import Action -import Common -import shutil -import subprocess +import pproc as subprocess Params.g_autoconfig = 1 # the following two variables are used by the target "waf dist" -VERSION = '3.0.1' -APPNAME = 'ns-3-waf' +VERSION = file("VERSION").read().strip() +APPNAME = 'ns' # these variables are mandatory ('/' are converted automatically) srcdir = '.' blddir = 'build' -class Ns3Header(Object.genobj): - """A set of NS-3 header files""" - def __init__(self, env=None): - Object.genobj.__init__(self, 'other') - self.inst_var = 'INCLUDEDIR' - self.inst_dir = 'ns3' - self.env = env - if not self.env: - self.env = Params.g_build.m_allenvs['default'] - - def apply(self): - ns3_dir_node = Params.g_build.m_srcnode.find_dir("ns3") - inputs = [] - outputs = [] - for filename in self.to_list(self.source): - src_node = self.path.find_source(filename) - if src_node is None: - Params.fatal("source ns3 header file %s not found" % (filename,)) - dst_node = ns3_dir_node.find_build(os.path.basename(filename)) - assert dst_node is not None - inputs.append(src_node) - outputs.append(dst_node) - task = self.create_task('ns3_headers', self.env, 1) - task.set_inputs(inputs) - task.set_outputs(outputs) - - def install(self): - for i in self.m_tasks: - current = Params.g_build.m_curdirnode - lst = map(lambda a: a.relpath_gen(current), i.m_outputs) - Common.install_files(self.inst_var, self.inst_dir, lst) - -def _ns3_headers_inst(task): - assert len(task.m_inputs) == len(task.m_outputs) - inputs = [node.srcpath(task.m_env) for node in task.m_inputs] - outputs = [node.bldpath(task.m_env) for node in task.m_outputs] - for src, dst in zip(inputs, outputs): - try: - os.chmod(dst, 0600) - except OSError: - pass - shutil.copy2(src, dst) - ## make the headers in builddir read-only, to prevent - ## accidental modification - os.chmod(dst, 0400) - return 0 - -def init(): - Object.register('ns3header', Ns3Header) - Action.Action('ns3_headers', func=_ns3_headers_inst, color='BLUE') +def dist_hook(srcdir, blddir): + shutil.rmtree("doc/html") + shutil.rmtree("doc/latex") def set_options(opt): # options provided by the modules - if not opt.tool_options('msvc'): - opt.tool_options('g++') + opt.tool_options('compiler_cxx') opt.add_option('--enable-gcov', help=('Enable code coverage analysis'), @@ -90,14 +42,22 @@ def set_options(opt): action="store_true", default=False, dest='doxygen') + opt.add_option('--run', + help=('Run a locally built program'), + type="string", default='', dest='run') + + opt.add_option('--shell', + help=('Run a shell with an environment suitably modified to run locally built programs'), + action="store_true", default=False, + dest='shell') + # options provided in a script in a subdirectory named "src" opt.sub_options('src') def configure(conf): - if not conf.check_tool('msvc'): - if not conf.check_tool('g++'): - Params.fatal("No suitable compiler found") + if not conf.check_tool('compiler_cxx'): + Params.fatal("No suitable compiler found") # create the second environment, set the variant and set its name @@ -123,6 +83,9 @@ def configure(conf): variant_env.append_value('CXXDEFINES', 'NS3_DEBUG_ENABLE') variant_env.append_value('CXXDEFINES', 'NS3_ASSERT_ENABLE') + if sys.platform == 'win32': + variant_env.append_value("LINKFLAGS", "-Wl,--enable-runtime-pseudo-reloc") + conf.sub_config('src') @@ -136,48 +99,126 @@ def build(bld): def shutdown(): - import UnitTest - ut = UnitTest.unit_test() - ut.change_to_testfile_dir = True - ut.want_to_see_test_output = True - ut.want_to_see_test_error = True - ut.run() + #import UnitTest + #ut = UnitTest.unit_test() + #ut.change_to_testfile_dir = True + #ut.want_to_see_test_output = True + #ut.want_to_see_test_error = True + #ut.run() #ut.print_results() + if Params.g_commands['check']: + run_program('run-tests') + if Params.g_options.lcov_report: - env = Params.g_build.env_of_name('default') - variant_name = env['NS3_ACTIVE_VARIANT'] - - if 'gcov' not in variant_name: - Params.fatal("project not configured for code coverage;" - " reconfigure with --enable-gcov") - - os.chdir(blddir) - try: - lcov_report_dir = os.path.join(variant_name, 'lcov-report') - create_dir_command = "rm -rf " + lcov_report_dir - create_dir_command += " && mkdir " + lcov_report_dir + ";" - - if subprocess.Popen(create_dir_command, shell=True).wait(): - raise SystemExit(1) - - info_file = os.path.join(lcov_report_dir, variant_name + '.info') - lcov_command = "../utils/lcov/lcov -c -d . -o " + info_file - lcov_command += " --source-dirs=" + os.getcwd() - lcov_command += ":" + os.path.join( - os.getcwd(), variant_name, 'include') - if subprocess.Popen(lcov_command, shell=True).wait(): - raise SystemExit(1) - - genhtml_command = "../utils/lcov/genhtml -o " + lcov_report_dir - genhtml_command += " " + info_file - if subprocess.Popen(genhtml_command, shell=True).wait(): - raise SystemExit(1) - finally: - os.chdir("..") + lcov_report() if Params.g_options.doxygen: - doxygen_config = os.path.join('doc', 'doxygen.conf') - if subprocess.Popen(['doxygen', doxygen_config]).wait(): + doxygen() + + if Params.g_options.run: + run_program(Params.g_options.run) + + elif Params.g_options.shell: + run_shell() + +def _find_program(program_name): + for obj in Object.g_allobjs: + if obj.target == program_name: + return obj + raise ValueError("progam '%s' not found" % (program_name,)) + +def _run_argv(argv): + env = Params.g_build.env_of_name('default') + if sys.platform == 'linux2': + pathvar = 'LD_LIBRARY_PATH' + pathsep = ':' + elif sys.platform == 'darwin': + pathvar = 'DYLD_LIBRARY_PATH' + pathsep = ':' + elif sys.platform == 'win32': + pathvar = 'PATH' + pathsep = ';' + else: + Params.warning(("Don't know how to configure " + "dynamic library path for the platform '%s'") % (sys.platform,)) + pathvar = None + pathsep = None + + os_env = dict(os.environ) + if pathvar is not None: + if pathvar in os_env: + os_env[pathvar] = pathsep.join([os_env[pathvar]] + list(env['NS3_MODULE_PATH'])) + else: + os_env[pathvar] = pathsep.join(list(env['NS3_MODULE_PATH'])) + + retval = subprocess.Popen(argv, env=os_env).wait() + if retval: + raise SystemExit(retval) + + +def run_program(program_string): + env = Params.g_build.env_of_name('default') + argv = shlex.split(program_string) + program_name = argv[0] + + try: + program_obj = _find_program(program_name) + except ValueError: + Params.fatal("progam '%s' not found" % (program_name,)) + + try: + program_node, = program_obj.m_linktask.m_outputs + except AttributeError: + Params.fatal("%s does not appear to be a program" % (program_name,)) + + execvec = [program_node.abspath(env)] + argv[1:] + return _run_argv(execvec) + + +def run_shell(): + if sys.platform == 'win32': + shell = os.environ.get("COMSPEC", "cmd.exe") + else: + shell = os.environ.get("SHELL", "/bin/sh") + _run_argv([shell]) + + +def doxygen(): + doxygen_config = os.path.join('doc', 'doxygen.conf') + if subprocess.Popen(['doxygen', doxygen_config]).wait(): + raise SystemExit(1) + + +def lcov_report(): + env = Params.g_build.env_of_name('default') + variant_name = env['NS3_ACTIVE_VARIANT'] + + if 'gcov' not in variant_name: + Params.fatal("project not configured for code coverage;" + " reconfigure with --enable-gcov") + + os.chdir(blddir) + try: + lcov_report_dir = os.path.join(variant_name, 'lcov-report') + create_dir_command = "rm -rf " + lcov_report_dir + create_dir_command += " && mkdir " + lcov_report_dir + ";" + + if subprocess.Popen(create_dir_command, shell=True).wait(): raise SystemExit(1) + info_file = os.path.join(lcov_report_dir, variant_name + '.info') + lcov_command = "../utils/lcov/lcov -c -d . -o " + info_file + lcov_command += " --source-dirs=" + os.getcwd() + lcov_command += ":" + os.path.join( + os.getcwd(), variant_name, 'include') + if subprocess.Popen(lcov_command, shell=True).wait(): + raise SystemExit(1) + + genhtml_command = "../utils/lcov/genhtml -o " + lcov_report_dir + genhtml_command += " " + info_file + if subprocess.Popen(genhtml_command, shell=True).wait(): + raise SystemExit(1) + finally: + os.chdir("..") +