File: coding-style.rst

package info (click to toggle)
ns3 3.46-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 105,864 kB
  • sloc: cpp: 624,863; python: 14,863; ansic: 6,772; makefile: 1,950; sh: 987; javascript: 167; perl: 102
file content (2012 lines) | stat: -rw-r--r-- 63,300 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
.. include:: replace.txt
.. heading hierarchy:
   ------------- Chapter
   ************* Section (#.#)
   ============= Subsection (#.#.#)
   ############# Paragraph (no number)

.. _Coding style:

Coding style
------------

When writing code to be contributed to the |ns3| open source project, we
ask that you follow the coding standards, guidelines, and recommendations
found below.

Clang-format
************

The |ns3| project uses `clang-format <https://clang.llvm.org/docs/ClangFormat.html>`_
to define and enforce the C++ coding style. Clang-format can be easily integrated
with modern IDEs or run manually on the command-line.

Besides clang-format, |ns3| adopts other coding-style guidelines that are not covered
by clang-format, which are explained in this document.
Read the ``check-style-clang-format.py`` section below for information on how to
use this Python script to check and fix all formatting guidelines followed by |ns3|.

Clang-format installation
=========================

Clang-format can be installed using one of two methods.
Please note that you should install one of the supported versions of clang-format,
which are listed in the ``RELEASE_NOTES.md`` file.

The first method is to install clang-format using the package manager available in the
Linux distribution (e.g., Ubuntu's ``apt``).
For example, in Ubuntu 24.04, clang-format 20 can be installed with the following command:

.. sourcecode:: console

  sudo apt install clang-format-20

If the package manager does not provide one of the clang-format versions supported by |ns3|,
users can install clang-format using Python's pip tool.

The following command will install the latest version of clang-format:

.. sourcecode:: console

  pip3 install clang-format

To install a specific version of clang-format, use the following command:

.. sourcecode:: console

  pip3 install clang-format==<version_number>

where ``<version_number>`` is something like ``20.1.8`` (MAJOR.MINOR.PATCH).

Starting with Python 3.11, pip requires users to either create a virtual environment (venv)
or add the ``--break-system-packages`` flag to the installation commands above.

Supported versions of clang-format
==================================

Since each new major version of clang-format can add or modify properties,
newer versions of clang-format might produce different outputs compared to
previous versions.

The list of clang-format versions that are verified to produce consistent output
among themselves are listed in the ``RELEASE_NOTES.md`` document.

Integration with IDEs
=====================

Clang-format can be integrated with modern IDEs (e.g., VS Code) that are able to
read the ``.clang-format`` file and automatically format the code on save or on typing.

Please refer to the documentation of your IDE for more information.
Some examples of IDE integration are provided in
`clang-format documentation <https://clang.llvm.org/docs/ClangFormat.html>`_.

As an example, VS Code's `C/C++ extension <https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools>`_
contains the latest clang-format binary.
VS Code can be configured to automatically format code on save, on paste and on type by enabling the following settings:

.. sourcecode:: json

  {
    "editor.formatOnSave": true,
    "editor.formatOnPaste": true,
    "editor.formatOnType": true,
  }

Clang-format usage in the terminal
==================================

In addition to IDE support, clang-format can be manually run on the terminal.

To format a file in-place, run the following command:

.. sourcecode:: console

  clang-format -i $FILE

To check that a file is well formatted, run the following command on the terminal.
If the file is not well formatted, clang-format indicates the lines that need to be
formatted.

.. sourcecode:: console

  clang-format --dry-run $FILE

Clang-format Git integration
============================

Clang-format integrates with Git to format Git commits or changes not yet committed, such as
pending merge requests on the GitLab repository. The full documentation is available on
`clang-format Git integration <https://clang.llvm.org/docs/ClangFormat.html#git-integration>`_

To fix the formatting of files with Git, run the following commands in the |ns3| main directory.
These commands do not change past commits. Instead, the reformatted files are left in the
workspace. These changes should be squashed to the corresponding commits, in order to fix them.

.. sourcecode:: console

  # Fix all commits of the current branch, relative to the master branch
  git clang-format master

  # Fix all staged changes (i.e., changes that have been `git add`ed):
  git clang-format

  # Fix all changes staged and unstaged:
  git clang-format -f

  # Fix specific files:
  git clang-format path_to_file

  # Check what formatting changes are needed (if no files provided, check all staged files):
  git clang-format --diff

Note that this only fixes formatting issues related to clang-format.
For other |ns3| coding style guidelines, read the ``check-style-clang-format.py`` section below.

In addition to Git patches,
`clang-format-diff <https://clang.llvm.org/docs/ClangFormat.html#script-for-patch-reformatting>`_
can also be used to reformat existing patches produced with the ``diff`` tool.

Disable formatting in specific files or lines
=============================================

To disable formatting in specific lines, surround them with the following
C++ comments:

.. sourcecode:: cpp

  // clang-format off
  ...
  // clang-format on

To exclude an entire file from being formatted, surround the whole file with the
special comments.

check-style-clang-format.py
***************************

To facilitate checking and fixing source code files according to the |ns3| coding style,
|ns3| maintains the ``check-style-clang-format.py`` Python script (located in ``utils/``).
This script is a wrapper to clang-format and provides useful options to check and fix
source code files. Additionally, it performs other manual checks and fixes in text files
(described below).

We recommend running this script over your newly introduced C++ files prior to submission
as a Merge Request.

The script performs multiple style checks. It returns a zero exit code if all files adhere to these rules.
If there are files that do not comply with the rules, the process returns a non-zero
exit code and lists the respective files. This mode is useful for developers editing
their code and for the GitLab CI/CD pipeline to check if the codebase is well formatted.

The script runs the checks explained in the following table.
All checks are enabled by default.
Users can disable specific checks using the corresponding flags.

.. list-table::
  :header-rows: 1

  * - Check
    - Description
    - Flag to Disable Check
  * - Formatting
    - Check code formatting using clang-format. Respects clang-format guards.
    - ``--no-formatting``
  * - #include "ns3/" prefixes
    - Check if local ``#include`` headers do not use the "ns3/" prefix. Respects clang-format guards.
    - ``--no-include-prefixes``
  * - #include quotes
    - Check if ns-3 ``#include`` headers use quotes (``""``) instead of angle brackets (``<>``). Respects clang-format guards.
    - ``--no-include-quotes``
  * - Doxygen tags
    - Check if Doxygen tags use ``@`` rather than ``\\``. Respects clang-format guards.
    - ``--no-doxygen-tags``
  * - SPDX Licenses
    - Check if source code use SPDX licenses rather than GPL license text. Respects clang-format guards.
    - ``--no-licenses``
  * - Emacs comments
    - Check if source code does not have emacs file style comments. Respects clang-format guards.
    - ``--no-emacs``
  * - Trailing whitespace
    - Check if there are no trailing whitespace. Always checked.
    - ``--no-whitespace``
  * - Tabs
    - Check if there are no tabs. Respects clang-format guards.
    - ``--no-tabs``
  * - File encoding
    - Check if files have the correct encoding (UTF-8). Always checked.
    - ``--no-encoding``

Additional information about the formatting issues detected by the script can be enabled
by adding the ``-v, --verbose`` flag.

In addition to checking the files, the script can automatically fix detected issues in-place.
This mode is enabled by adding the ``--fix`` flag.

The formatting and tabs checks respect clang-format guards, which mark code blocks
that should not be checked. Trailing whitespace is always checked regardless of
clang-format guards.

The complete API of the ``check-style-clang-format.py`` script can be obtained with the
following command:

.. sourcecode:: console

  ./utils/check-style-clang-format.py --help

For quick-reference, the most used commands are listed below:

.. sourcecode:: console

  # Entire codebase (using paths relative to the ns-3 main directory)
  ./utils/check-style-clang-format.py --fix .

  # Entire codebase (using absolute paths)
  /path/to/utils/check-style-clang-format.py --fix /path/to/ns3

  # Specific directory or file
  /path/to/utils/check-style-clang-format.py --fix absolute_or_relative/path/to/directory_or_file

  # Files modified by the current branch, relative to the master branch
  git diff --name-only master | xargs ./utils/check-style-clang-format.py --fix

Clang-tidy
**********

The |ns3| project uses `clang-tidy <https://clang.llvm.org/extra/clang-tidy/>`_
to statically analyze (lint) C++ code and help developers write better code.
Clang-tidy can be easily integrated with modern IDEs or run manually on the command-line.

The list of clang-tidy checks currently enabled in the |ns3| project is saved on the
``.clang-tidy`` file. The full list of clang-tidy checks and their detailed explanations
can be seen in `Clang-tidy checks <https://clang.llvm.org/extra/clang-tidy/checks/list.html>`_.

Clang-tidy installation
=======================

Clang-format can be installed using your OS's package manager. Please note that you
should install one of the supported versions of clang-format, which are listed in the
following section.

Minimum clang-tidy version
==========================

Since clang-tidy is a linter that analyzes code and outputs errors found during
the analysis, developers can use different versions of clang-tidy on the workflow.
Newer versions of clang-tidy might produce better results than older versions.
Therefore, it is recommended to use the latest version available.

To ensure consistency among developers, |ns3| defines a minimum version of clang-tidy,
whose warnings must not be ignored. Therefore, developers should, at least, scan their
code with the minimum version of clang-tidy. However, more recent versions can be used,
which will produce better warnings.

The minimum version is clang-tidy-15.

Integration with IDEs
=====================

Clang-tidy automatically integrates with modern IDEs (e.g., VS Code) that read the
``.clang-tidy`` file and automatically checks the code of the currently open file.

Please refer to the documentation of your IDE for more information.
Some examples of IDE integration are provided in
`clang-tidy documentation <https://clang.llvm.org/extra/clang-tidy/Integrations.html>`_

Clang-tidy usage
================

In order to use clang-tidy, |ns3| must first be configured with the flag
``--enable-clang-tidy``. To configure |ns3| with tests, examples and clang-tidy enabled,
run the following command:

.. sourcecode:: console

  ./ns3 configure --enable-examples --enable-tests --enable-clang-tidy

Due to the integration of clang-tidy with CMake, clang-tidy can be run while building
|ns3|. In this way, clang-tidy errors will be shown alongside build errors on the terminal.
To build |ns3| and run clang-tidy, run the the following command:

.. sourcecode:: console

  ./ns3 build

To run clang-tidy without building |ns3|, use the following commands on the ns-3
main directory:

.. sourcecode:: console

  # Analyze (and fix) a single file with clang-tidy
  clang-tidy -p cmake-cache/ [--fix] [--format-style=file] [--quiet] $FILE

  # Analyze (and fix) multiple files in parallel
  run-clang-tidy -p cmake-cache/ [-fix] [-format] [-quiet] $FILE1 $FILE2 ...

  # Analyze (and fix) the entire ns-3 codebase in parallel
  run-clang-tidy -p cmake-cache/ [-fix] [-format] [-quiet]

When running clang-tidy, please note that:

- Clang-tidy only analyzes implementation files (i.e., ``*.cc`` files).
  Header files are analyzed when they are included by implementation files, with the
  ``#include "..."`` directive.

- Not all clang-tidy checks provide automatic fixes. For those cases, a manual fix
  must be made by the developer.

- Enabling clang-tidy will add time to the build process (in the order of minutes).

Disable clang-tidy analysis in specific lines
=============================================

To disable clang-tidy analysis of a particular rule in a specific function,
specific clang-tidy comments have to be added to the corresponding function.
Please refer to the `official clang-tidy documentation <https://clang.llvm.org/extra/clang-tidy/#suppressing-undesired-diagnostics>`_
for more information.

To disable ``modernize-use-override`` checking on ``func()`` only, use one of the
following two "special comment" syntaxes:

.. sourcecode:: cpp

  //
  // Syntax 1: Comment above the function
  //

  // NOLINTNEXTLINE(modernize-use-override)
  void func();

  //
  // Syntax 2: Trailing comment
  //

  void func(); // NOLINT(modernize-use-override)

To disable a specific clang-tidy check on a block of code, for instance the
``modernize-use-override`` check, surround the code block with the following
"special comments":

.. sourcecode:: cpp

  // NOLINTBEGIN(modernize-use-override)
  void func1();
  void func2();
  // NOLINTEND(modernize-use-override)


To disable all clang-tidy checks on a block of code, surround it with the
following "special comments":

.. sourcecode:: cpp

  // NOLINTBEGIN
  void func1();
  void func2();
  // NOLINTEND

To exclude an entire file from being checked, surround the whole file with the
"special comments".

Source code formatting
**********************

The |ns3| coding style was changed between the ns-3.36 and ns-3.37 release.
Prior to ns-3.37, |ns3| used a base GNU coding style. Since ns-3.37, |ns3| changed the
base coding style to what is known in the industry as Allman-style braces,
with four-space indentation. In clang-format, this is configured by selecting the
``Microsoft`` base style. The following examples illustrate the style.

Indentation
===========

Indent code with 4 spaces. When breaking statements into multiple lines, indent the
following lines with 4 spaces.

.. sourcecode:: cpp

  void
  Func()
  {
      int x = 1;
  }

Indent constructor's initialization list with 4 spaces.

.. sourcecode:: cpp

  MyClass::MyClass(int x, int y)
      : m_x(x),
        m_y(y)
  {
  }

Do not use tabs in source code. Always use spaces for indentation and alignment.

Line endings
============

Files use LF (``\n``) line endings.

Column limit
============

Code lines should not extend past 100 characters. This allows reading code in wide-screen
monitors without having to scroll horizontally, while also allowing editing two files
side-by-side.

Braces style
============

Braces should be formatted according to the Allman style.
Braces are always on a new line and aligned with the start of the corresponding block.
The main body is indented with 4 spaces.

Always surround conditional or loop blocks (e.g., ``if``, ``for``, ``while``)
with braces, and always add a space before the condition's opening parentheses.

.. sourcecode:: cpp

  void Foo()
  {
      if (condition)
      {
          // do stuff here
      }
      else
      {
          // do other stuff here
      }

      for (int i = 0; i < 100; i++)
      {
          // do loop
      }

      while (condition)
      {
          // do while
      }

      do
      {
          // do stuff
      } while (condition);
  }

Spacing
=======

To increase readability, functions, classes and namespaces are separated by one
new line. This spacing is optional when declaring variables or functions.
Declare one variable per line. Do not mix multiple statements on the same line.

Do not add a space between the function name and the opening parentheses.
This rule applies to both function (and method) declarations and invocations.

.. sourcecode:: cpp

  void Func(const T&);  // OK
  void Func (const T&); // Not OK

Trailing whitespace
===================

Source code and text files must not have trailing whitespace.

Code alignment
==============

To improve code readability, trailing comments should be aligned.

.. sourcecode:: cpp

  int varOne;    // Variable one
  double varTwo; // Variable two

The trailing ``\`` character of macros should be aligned to the far right
(equal to the column limit). This increases the readability of the macro's body,
without forcing unnecessary whitespace diffs on surrounding lines when only one
line is changed.

.. sourcecode:: cpp

  #define MY_MACRO(msg)                      \
      do                                     \
      {                                      \
          std::cout << msg << std::endl;     \
      } while (false);


Class members
=============

Definition blocks within a class should be organized in descending order of
public exposure, that is: ``static`` > ``public`` > ``protected`` > ``private``.
Separate each block with a new line.

.. sourcecode:: cpp

  class MyClass
  {
  public:
      static int m_counter = 0;

      MyClass(int x, int y);

  private:
      int x;
      int y;
  };

Function arguments bin packing
==============================

Function arguments should be declared in the same line as the function declaration.
If the arguments list does not fit the maximum column width, declare each one on a
separate line and align them vertically.

.. sourcecode:: cpp

  void ShortFunction(int x, int y);

  void VeryLongFunctionWithLongArgumentList(int x,
                                            int y,
                                            int z);


The constructor initializers are always declared one per line, with a trailing comma:

.. sourcecode:: cpp

  void
  MyClass::MyClass(int x, int y)
      : m_x(x),
        m_y(y)
  {
  }

Function return types
=====================

In function declarations, return types are declared on the same line.
In function implementations, return types are declared on a separate line.


.. sourcecode:: cpp

  // Function declaration
  void Func(int x, int y);

  // Function implementation
  void
  Func(int x, int y)
  {
      // (...)
  }

Templates
=========

Template definitions are always declared in a separate line from the main function
declaration:

.. sourcecode:: cpp

  template <class T>
  void Func(T t);

Naming
======

Name encoding
#############

Function, method, and type names should follow the
`CamelCase <https://en.wikipedia.org/wiki/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.
This applies also to two-letter acronyms, such as ``IP`` (which becomes
``Ip``). 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. Use PascalCasing (CamelCase with first letter capitalized)
for function, property, event, and class names.

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. Defined types will start
with an upper case letter, consist of upper and lower case letters, and may
optionally end with a ``_t``. Defined constants (such as static const class
members, or enum constants) will be all uppercase letters or numeric digits,
with an underscore character separating words. Otherwise, the underscore
character should not be used in a variable name. For example, you could
declare in your class header ``my-class.h``:

.. sourcecode:: cpp

  typedef int NewTypeOfInt_t;
  constexpr uint8_t PORT_NUMBER = 17;

  class MyClass
  {
      void MyMethod(int aVar);
      int m_aVar;
      static int m_anotherVar;
  };

and implement in your class file ``my-class.cc``:

.. sourcecode:: cpp

  int MyClass::m_anotherVar = 10;
  static int g_aStaticVar = 100;
  int g_aGlobalVar = 1000;

  void
  MyClass::MyMethod(int aVar)
  {
      m_aVar = aVar;
  }

As an exception to the above, the members of structures do not need to be
prefixed with an ``m_``.

Finally, do not use
`Hungarian notation <https://en.wikipedia.org/wiki/Hungarian_notation>`_, and
do not prefix enums, classes, or delegates with any letter.

Choosing names
##############

Variable, function, method, and type names should be based on the English
language, American spelling. 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 (e.g.,
use ``size`` over ``sz``). Do not use short inappropriate 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.

If you use predicates (that is, functions, variables or methods which return
a single boolean value), prefix the name with "is" or "has".

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 |ns3|
codebase to locate the source file relevant to a specific type.

Each ``my-class.h`` header should start with the following comment to 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.
Please do not add the "All Rights Reserved" phrase after the copyright
statement.

.. sourcecode:: cpp

  /*
   * Copyright (c) YEAR COPYRIGHTHOLDER
   *
   * SPDX-License-Identifier: GPL-2.0-only
   *
   * Author: MyName <myemail@example.com>
   */

Below these C-style comments, always include the following which defines a
set of header guards (``MY_CLASS_H``) used to avoid multiple header includes,
which ensures that your code is included in the |ns3| namespace and which
provides a set of Doxygen comments for the public part of your class API.
Detailed information on the set of tags available for doxygen documentation
is described in the `Doxygen website <https://www.doxygen.nl/index.html>`_.

.. sourcecode:: cpp

  #ifndef MY_CLASS_H
  #define MY_CLASS_H

  namespace ns3
  {

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

      /**
       * A detailed description of the purpose of the method.
       *
       * @param firstParam a short description of the purpose of this parameter
       * @return a short description of what is returned from this function.
       */
      int DoSomething(int firstParam);

  private:
      /**
       * Private method doxygen is also recommended
       */
      void MyPrivateMethod();

      int m_myPrivateMemberVariable; ///< Brief description of member variable
  };

  } // namespace ns3

  #endif // MY_CLASS_H

The ``my-class.cc`` file is structured similarly:

.. sourcecode:: cpp

  /*
   * Copyright (c) YEAR COPYRIGHTHOLDER
   *
   * SPDX-License-Identifier: GPL-2.0-only
   *
   * Author: MyName <myemail@foo.com>
   */

  #include "my-class.h"

  namespace ns3
  {

  MyClass::MyClass()
  {
  }

  ...

  } // namespace ns3

Header file includes
====================

Included header files should be organized by source location. The sorting order is
as follows:

.. sourcecode:: cpp

  // Header class (applicable for *.cc files)
  #include "my-class.h"

  // Includes from the same module
  #include "header-from-same-module.h"

  // Includes from other modules
  #include "ns3/header-from-different-module.h"

  // External headers (e.g., STL libraries)
  #include <iostream>

Groups should be separated by a new line. Within each group, headers should be
sorted alphabetically.

For standard headers, use the C++ style of inclusion:

.. sourcecode:: cpp

  #include <cstring>  // OK
  #include <string.h> // Avoid

- inside .h files, always use

  .. sourcecode:: cpp

    #include "ns3/header.h"

- inside .cc files, use

  .. sourcecode:: cpp

    #include "header.h"

  if file is in same directory, otherwise use

  .. sourcecode:: cpp

    #include "ns3/header.h"

Variables and constants
=======================

Each variable declaration is on a separate line.
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.

.. sourcecode:: cpp

  // Do not declare multiple variables per line
  int x, y;

  // Declare one variable per line and assign an initial value
  int x = 0;
  int y = 0;

Named constants defined in classes should be declared as ``static constexpr`` instead of
macros, const, or enums. Use of ``static constexpr`` allows a single instance to be
evaluated at compile-time. Declaring the constant in the class enables it to share the scope
of the class.

If the constant is only used in one file, consider declaring the constant in the implementation
file (``*.cc``).

.. sourcecode:: cpp

  // Avoid declaring constants as enum
  class LteRlcAmHeader : public Header
  {
      enum ControlPduType_t
      {
          STATUS_PDU = 000,
      };
  };

  // Prefer to declare them as static constexpr (in class)
  class LteRlcAmHeader : public Header
  {
      static constexpr uint8_t STATUS_PDU{0};
  };

  // Or as constexpr (in implementation files)
  constexpr uint8_t STATUS_PDU{0};

When declaring variables that are easily deducible from context, prefer to declare them
with ``auto`` instead of repeating the type name. Not only does this improve code readability,
by making lines shorter, but it also facilitates future code refactoring.

.. sourcecode:: cpp

  // Avoid repeating the type name when declaring iterators or pointers, and casting variables
  std::map<uint32_t, std::string>::const_iterator it = myMap.find(key);
  int* ptr = new int[10];
  uint8_t m = static_cast<uint8_t>(97 + (i % 26));

  // Prefer to declare them with auto
  auto it = myMap.find(key);
  auto* ptr = new int[10];
  auto m = static_cast<uint8_t>(97 + (i % 26));


Initialization
==============

When declaring variables, prefer to use direct-initialization, to avoid repeating the type name.

.. sourcecode:: cpp

  // Avoid splitting the declaration and initialization of variables
  Ipv4Address ipv4Address = Ipv4Address("192.168.0.1")

  // Prefer to use direct-initialization
  Ipv4Address ipv4Address("192.168.0.1")

Variables with no default constructor or of primitive types should be initialized when declared.

Variables with default constructors do not need to be explicitly initialized, since the compiler
already does that. An example of this is the ``ns3::Time`` class, which will initialize to zero.

Member variables of structs and classes should be initialized unless the member has a default
constructor that guarantees initialization.  Preferably, variables should be initialized together
with the declaration (in the header file). Alternatively, they can be initialized in the default
constructor (in the implementation file), and you may see instances of this in the codebase, but
direct initialization upon declaration is preferred going forward.

If all member variables of a class / struct are directly initialized (see above), they do not
require explicit default initialization. But if not all variables are initialized, those
non-initialized variables will contain garbage. Therefore, initializing the class object with
``{}`` allows all member variables to always be initialized -- either with the provided default
initialization or with the primitive type's default value (typically 0).

C++ supports two syntax choices for direct initialization, either ``()`` or ``{}``.  There are
various tradeoffs in the choices for more complicated types (consult the C++ literature on
brace vs. parentheses initialization), but for the fundamental types like ``double``, either is
acceptable (please use consistently within files).

Regarding ``ns3::Time``, do not initialize to non-zero integer values as follows, assuming
that it will be converted to nanoseconds:

.. sourcecode:: cpp

  Time t{1000000};  // This is disallowed

The value will be interpreted according to the current resolution, which is ambiguous.  A
user's program may have already changed the resolution from the default of nanoseconds to
something else by the time of this initialization, and it will be instead interpreted according
to 10^6 * the new resolution unit.

Time initialization to raw floating-point values is additionally fraught, because of rounding.  Doing
so with small values has led to bugs in practice such as timer timeout values of zero time.

When declaring or manipulating ``Time`` objects with known values, prefer to use integer-based representations and
arguments over floating-point fractions, where possible, because integer-based is faster.
This means preferring the use of ``NanoSeconds``, ``MicroSeconds``, and ``MilliSeconds`` over
``Seconds``.  For example, to represent a tenth of a second, prefer ``MilliSeconds(100)``
to ``Seconds(0.1)``.

To summarize Time declaration and initialization, consider the following examples and comments:

.. sourcecode:: cpp

  Time t;  // OK, will be value-initialized to integer zero
  Time t{MilliSeconds(100)};  // OK, fastest, no floating point involved
  Time t{"100ms"}; // OK, will perform a string conversion; integer would be faster
  Time t{Seconds(0.1)};  // OK, will invoke Seconds(double); integer would be faster
  Time t{100000000}; // NOT OK, is interpreted differently when ``Time::SetResolution()`` called
  Time t{0.1}; // NOT OK, will round to zero; see above and also merge request !2007

Comments
========

The project uses `Doxygen <https://www.doxygen.nl/index.html>`_ to document
the interfaces, and uses comments for improving the clarity of the code
internally. All classes, methods, and members should have Doxygen comments.
Doxygen comments should use the C-style comment (also known as Javadoc) style.
For comments that are intended to not be exposed publicly in the Doxygen output,
use the ``@internal`` and ``@endinternal`` tags.
Please use the ``@see`` tag for cross-referencing.
All parameters and return values should be documented. The |ns3| codebase prefers
the ``@`` character for tag identification. This character is recognized by clang-format
as the start of Doxygen tags, which enables it to keep tags properly formatted;
therefore please don't use ``\`` as the delimiter.

.. sourcecode:: cpp

  /**
   * MyClass description.
   */
  class MyClass
  {
      /**
       * Constructor.
       *
       * @param n Number of elements.
       */
      MyClass(int n);
  };

All the functions and variables must be documented, with the exception of
member functions inherited from parent classes (the documentation is copied
automatically from the parent class), and default constructor/destructor.

It is strongly suggested to use grouping to bind together logically related
classes (e.g., all the classes in a module). E.g.;

.. sourcecode:: cpp

  /**
   * @defgroup mynewmodule This is a new module
   */

  /**
   * @ingroup mynewmodule
   *
   * MyClassOne description.
   */
  class MyClassOne
  {
  };

  /**
   * @ingroup mynewmodule
   *
   * MyClassTwo description.
   */
  class MyClassTwo
  {
  };

In the tests for the module, it is suggested to add an ancillary group:

.. sourcecode:: cpp

  /**
   * @defgroup mynewmodule-test Tests for new module
   * @ingroup mynewmodule
   * @ingroup tests
   */

  /**
   * @ingroup mynewmodule-tests
   * @brief MyNewModule Test
   */
  class MyNewModuleTest : public TestCase
  {
  };

  /**
   * @ingroup mynewmodule-tests
   * @brief MyNewModule TestSuite
   */
  class MyNewModuleTestSuite : public TestSuite
  {
    public:
      MyNewModuleTestSuite();
  };

  /**
   * @ingroup mynewmodule-tests
   * Static variable for test initialization
   */
  static MyNewModuleTestSuite g_myNewModuleTestSuite;

As for comments within the code, comments should be used to describe intention
or algorithmic overview where is it not immediately obvious from reading the
code alone. There are no minimum comment requirements and small routines
probably need no commenting at all, but it is hoped that many larger
routines will have commenting to aid future maintainers. Please write
complete English sentences and capitalize the first word unless a lower-case
identifier begins the sentence. Two spaces after each sentence helps to make
emacs sentence commands work. Sometimes ``NS_LOG_DEBUG`` statements can
be also used in place of comments.

Short one-line comments and long comments can use the C++ comment style;
that is, ``//``, but longer comments may use C-style comments.
Use one space after ``//`` or ``/*``.

.. sourcecode:: cpp

  /*
   * A longer comment,
   * with multiple lines.
   */

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.

.. sourcecode:: cpp

  int nNodes = 3; // Number of nodes

  /// Node container with the Wi-Fi stations
  NodeContainer wifiStations(3);

Comments in closing braces are generally discouraged, to allow for consistent style
formatting across recent versions of clang-format (see MRs
`!1899 <https://gitlab.com/nsnam/ns-3-dev/-/merge_requests/1899>`_ and
`!2070 <https://gitlab.com/nsnam/ns-3-dev/-/merge_requests/2070>`_).
This rule may be overridden in cases where the comment improves the code's readability.
For example, in class declarations in files with multiple classes, classes within parent classes,
and inline class functions.
To ensure consistent style formatting, prefer placing the comment marking the end of the class
in a new line before the brace.

An exception to this rule are the comments in the closing brace of a namespace,
which identifies the corresponding namespace.

The following examples illustrate the above guidelines.

.. sourcecode:: cpp

  // File with only one class

  namespace ns3
  {

  int
  MyClass::Func(int x)
  {
      while (...)
      {
          if (...)
          {
          } // end if // Do not add this comment
      } // end while  // Do not add this comment
  } // end Func       // Do not add this comment

  } // namespace ns3  // Keep this comment

.. sourcecode:: cpp

  // Example of file with multiple classes, and classes within classes

  class MyClass
  {
      class InlineClass
      {
          ...
          int var; //!< Some variable

          // end of class InlineClass  // This comment is allowed
      };

      ...

      // end of class MyClass  // This comment is allowed
  };

Casts
=====

Where casts are necessary, use the Google C++ guidance:  "Use C++-style casts
like ``static_cast<float>(double_value)``, or brace initialization for
conversion of arithmetic types like ``int64 y = int64{1} << 42``."
Do not use C-style casts, since they can be unsafe.

Try to avoid (and remove current instances of) casting of ``uint8_t``
type to larger integers in our logging output by overriding these types
within the logging system itself. Also, the unary ``+`` operator can be used
to print the numeric value of any variable, such as:

.. sourcecode:: cpp

  uint8_t flags = 5;
  std::cout << "Flags numeric value: " << +flags << std::endl;

Avoid unnecessary casts if minor changes to variable declarations can solve
the issue. In the following example, ``x`` can be declared as ``float`` instead of
``int`` to avoid the cast, or write numbers in decimal format:

.. sourcecode:: cpp

  // Do not declare x as int, to avoid casting it to float
  int x = 3;
  float y = 1 / static_cast<float>(x);

  // Prefer to declare x as float
  float x = 3.0;
  float y = 1 / x;

  // Or use 1.0 instead of just 1
  int x = 3;
  float y = 1.0 / x;

Namespaces
==========

Code should always be included in a given namespace, namely ``ns3``.
In order to avoid exposing internal symbols, consider placing the code in an
anonymous namespace, which can only be accessed by functions in the same file.

Code within namespaces should not be indented. To more easily identify the end
of a namespace, add a trailing comment to its closing brace.

.. sourcecode:: cpp

  namespace ns3
  {

  // (...)

  } // namespace ns3

Namespace names should follow the snake_case convention.

Unused variables
================

Compilers will typically issue warnings on unused entities (e.g., variables,
function parameters). Use the ``[[maybe_unused]]`` attribute to suppress
such warnings when the entity may be unused depending on how the code
is compiled (e.g., if the entity is only used in a logging statement or
an assert statement).

The general guidelines are as follows:

- If a function's or a method's parameter is definitely unused,
  prefer to leave it unnamed. In the following example, the second
  parameter is unnamed.

  .. sourcecode:: cpp

    void
    UanMacAloha::RxPacketGood(Ptr<Packet> pkt, double, UanTxMode txMode)
    {
        UanHeaderCommon header;
        pkt->RemoveHeader(header);
        ...
    }

  In this case, the parameter is also not referenced by Doxygen; e.g.,:

  .. sourcecode:: cpp

    /**
     * Receive packet from lower layer (passed to PHY as callback).
     *
     * @param pkt Packet being received.
     * @param txMode Mode of received packet.
     */
    void RxPacketGood(Ptr<Packet> pkt, double, UanTxMode txMode);

  The omission is preferred to commenting out unused parameters, such as:

  .. sourcecode:: cpp

    void
    UanMacAloha::RxPacketGood(Ptr<Packet> pkt, double /*sinr*/, UanTxMode txMode)
    {
        UanHeaderCommon header;
        pkt->RemoveHeader(header);
        ...
    }

- If a function's parameter is only used in certain cases (e.g., logging),
  or it is part of the function's Doxygen, mark it as ``[[maybe_unused]]``.

  .. sourcecode:: cpp

    void
    TcpSocketBase::CompleteFork(Ptr<Packet> p [[maybe_unused]],
                                const TcpHeader& h,
                                const Address& fromAddress,
                                const Address& toAddress)
    {
        NS_LOG_FUNCTION(this << p << h << fromAddress << toAddress);

        // Remaining code that definitely uses 'h', 'fromAddress' and 'toAddress'
        ...
    }

- If a local variable saves the result of a function that must always run,
  but whose value may not be used, declare it ``[[maybe_unused]]``.

  .. sourcecode:: cpp

    void
    MyFunction()
    {
        int result [[maybe_unused]] = MandatoryFunction();
        NS_LOG_DEBUG("result = " << result);
    }

- If a local variable saves the result of a function that is only run in
  certain cases, prefer to not declare the variable and use the function's
  return value directly where needed. This avoids unnecessarily calling the
  function if its result is not used.

  .. sourcecode:: cpp

    void
    MyFunction()
    {
        // Prefer to call GetDebugInfo() directly on the log statement
        NS_LOG_DEBUG("Debug information: " << GetDebugInfo());

        // Avoid declaring a local variable with the result of GetDebugInfo()
        int debugInfo [[maybe_unused]] = GetDebugInfo();
        NS_LOG_DEBUG("Debug information: " << debugInfo);
    }

  If the calculation of the maybe unused variable is complex, consider wrapping
  the calculation of its value in a conditional block that is only run if the
  variable is used.

  .. sourcecode:: cpp

    if (g_log.IsEnabled(ns3::LOG_DEBUG))
    {
        auto debugInfo = GetDebugInfo();
        auto value = DoComplexCalculation(debugInfo);

        NS_LOG_DEBUG("The value is " << value);
    }

Unnecessary else after return
=============================

In order to increase readability and avoid deep code nests, consider not adding
an ``else`` block if the ``if`` block breaks the control flow (i.e., when using
``return``, ``break``, ``continue``, etc.).

For instance, the following code:

.. sourcecode:: cpp

  if (n < 0)
  {
      return false;
  }
  else
  {
      n += 3;
      return n;
  }

can be rewritten as:

.. sourcecode:: cpp

  if (n < 0)
  {
      return false;
  }

  n += 3;
  return n;

Boolean Simplifications
=======================

In order to increase readability and performance, avoid unnecessarily complex boolean
expressions in if statements and variable declarations.

For instance, the following code:

.. sourcecode:: cpp

  bool IsPositive(int n)
  {
      if (n > 0)
      {
          return true;
      }
      else
      {
          return false;
      }
  }

  void ProcessNumber(int n)
  {
      if (IsPositive(n) == true)
      {
          ...
      }
  }

can be rewritten as:

.. sourcecode:: cpp

  bool IsPositive(int n)
  {
      return n > 0;
  }

  void ProcessNumber(int n)
  {
      if (IsPositive(n))
      {
          ...
      }
  }

Smart pointer boolean comparisons
=================================

As explained in this `issue <https://gitlab.com/nsnam/ns-3-dev/-/merge_requests/732>`_,
the |ns3| smart pointer class ``Ptr`` should be used in boolean comparisons as follows:

.. sourcecode:: cpp

  for Ptr<> p, do not use:            use instead:
  ========================            =================================
  if (p != nullptr) {...}             if (p)      {...}
  if (p != NULL)    {...}
  if (p != 0)       {...}             if (p)      {...}

  if (p == nullptr) {...}             if (!p)     {...}
  if (p == NULL)    {...}
  if (p == 0)       {...}

  NS_ASSERT...(p != nullptr, ...)    NS_ASSERT...(p, ...)
  NS_ABORT... (p != nullptr, ...)    NS_ABORT... (p, ...)

  NS_ASSERT...(p == nullptr, ...)    NS_ASSERT...(!p, ...)
  NS_ABORT... (p == nullptr, ...)    NS_ABORT... (!p, ...)

  NS_TEST...  (p, nullptr, ...)      NS_TEST...  (p, nullptr, ...)

Code performance tips
=====================

While developing code, consider the following tips to improve the code's performance.
Some tips are general recommendations, but are not strictly enforced.
Other tips are enforced by clang-tidy. Please refer to the clang-tidy section below
for more details.

- Prefer to use ``.emplace_back()`` over ``.push_back()`` to optimize performance.

- When initializing STL containers (e.g., ``std::vector``) with known size,
  reserve memory to store all items, before pushing them in a loop.

  .. sourcecode:: cpp

    constexpr int N_ITEMS = 5;

    std::vector<int> myVector;
    myVector.reserve(N_ITEMS); // Reserve memory to store all items

    for (int i = 0; i < N_ITEMS; i++)
    {
        myVector.emplace_back(i);
    }

- Prefer to initialize STL containers (e.g., ``std::vector``, ``std::map``, etc.)
  directly through the constructor or with a braced-init-list, instead of pushing
  elements one-by-one.

  .. sourcecode:: cpp

    // Prefer to initialize containers directly
    std::vector<int> myVector1{1, 2, 3};
    std::vector<int> myVector2(myVector1.begin(), myVector1.end());
    std::vector<bool> myVector3(myVector2.size(), true);

    // Avoid pushing elements one-by-one
    std::vector<int> myVector1;
    myVector1.reserve(3);
    myVector1.emplace_back(1);
    myVector1.emplace_back(2);
    myVector1.emplace_back(3);

    std::vector<int> myVector2;
    myVector2.reserve(myVector1.size());
    for (const auto& v : myVector1)
    {
        myVector2.emplace_back(v);
    }

    std::vector<bool> myVector3;
    myVector3.reserve(myVector1.size());
    for (std::size_t i = 0; i < myVector1.size(); i++)
    {
        myVector3.emplace_back(true);
    }

- When looping through containers, prefer to use const-ref syntax over copying
  elements.

  .. sourcecode:: cpp

    std::vector<int> myVector{1, 2, 3};

    for (const auto& v : myVector) { ... }  // OK
    for (auto v : myVector) { ... }         // Avoid

- Prefer to use the ``empty()`` function of STL containers (e.g., ``std::vector``),
  instead of the condition ``size() > 0``, to avoid unnecessarily calculating the
  size of the container.

- Avoid unnecessary calls to the functions ``.c_str()`` and ``.data()`` of
  ``std::string``.

- Avoid unnecessarily dereferencing std smart pointers (``std::shared_ptr``,
  ``std::unique_ptr``) with calls to their member function ``.get()``.
  Prefer to use the std smart pointer directly where needed.

  .. sourcecode:: cpp

    auto ptr = std::make_shared<Node>();

    // OK
    if (ptr) { ... }

    // Avoid
    if (ptr.get()) { ... }

- Consider caching frequently-used results (especially expensive calculations,
  such as mathematical functions) in a temporary variable, instead of calculating
  them in every loop.

  .. sourcecode:: cpp

    // Prefer to cache intermediate results
    const double sinTheta = std::sin(theta);
    const double cosTheta = std::cos(theta);

    for (uint8_t i = 0; i < NUM_VALUES; i++)
    {
        double power = std::pow(2, i);

        array1[i] = (power * sinTheta) + cosTheta;
        array2[i] = (power * cosTheta) + sinTheta;
    }

    // Avoid repeating calculations
    for (uint8_t i = 0; i < NUM_VALUES; i++)
    {
        array1[i] = (std::pow(2, i) * std::sin(theta)) + std::cos(theta);
        array2[i] = (std::pow(2, i) * std::cos(theta)) + std::sin(theta);
    }

- Do not include inline implementations in header files; put all
  implementation in a ``.cc`` file (unless implementation in the header file
  brings demonstrable and significant performance improvement).

- Avoid declaring trivial destructors, to optimize performance.

.. _When an empty destructor is required: https://andreasfertig.com/blog/2023/12/when-an-empty-destructor-is-required/

- When declaring default destructors with ``~Class() = default;``, be aware
  that classes derived from ``SimpleRefCount<T>`` must have this declaration
  on the source file (``.cc``). The header file (``.h``) should contain
  the plain destructor declaration ``~Class();``. This is due to PIMPL's
  opaque pointer, as explained in Andrea Fertig's blog post
  `When an empty destructor is required`_.
  See class WifiPpdu's destructor for an example.

C++ standard
============

As of ns-3.36, |ns3| permits the use of C++-17 (or earlier) features
in the implementation files.

If a developer would like to propose to raise this bar to include more
features than this, please email the developers list. We will move this
language support forward as our minimally supported compiler moves forward.

Guidelines for using maps
=========================

Maps (associative containers) are used heavily in ns-3 models to store
key/value pairs.  The C++ standard, over time, has added various methods to
insert elements to maps, and the ns-3 codebase has made use of most or all
of these constructs.  For the sake of uniformity and readability, the
following guidelines are recommended for any new code.

Prefer the use of ``std::map`` to ``std::unordered_map`` unless there is
a measurable performance advantage.  Use ``std::unordered_map`` only for
use cases in which the map does not need to be iterated or the iteration
order does not affect the results of the operation (because different
implementations of the hash function may lead to different iteration orders
on different systems).

Keep in mind that C++ now allows several methods to insert values into
maps, and the behavior can be different when a value already exists for
a key.  If the intended behavior is that the insertion should not overwrite
an existing value for the key, ``try_emplace()`` can be a good choice.  If
the intention is to allow the overwriting of a key/value pair,
``insert_or_assign()`` can be a good choice.  Both of the above methods
provide return values that can be checked-- in the case of ``try_emplace()``,
whether the insertion succeeded or did not occur, and in the case of
``insert_or_assign()``, whether an insertion or assignment occurred.

Miscellaneous items
===================

- ``NS_LOG_COMPONENT_DEFINE("log-component-name");`` statements should be
  placed within ``namespace ns3`` (for module code) and after the
  ``using namespace ns3;``.  In examples,
  ``NS_OBJECT_ENSURE_REGISTERED()`` should also be placed within ``namespace ns3``.

- Pointers and references are left-aligned:

  .. sourcecode:: cpp

    int x = 1;
    int* ptr = &x;
    int& ref = x;

- Use a trailing comma in braced-init-lists, so that each item is positioned in a new line.

  .. sourcecode:: cpp

    const std::vector<std::string> myVector{
      "string-1",
      "string-2",
      "string-3",
    };

    const std::map<int, std::string> myMap{
      {1, "string-1"},
      {2, "string-2"},
      {3, "string-3"},
    };


- Const reference syntax:

  .. sourcecode:: cpp

    void MySub(const T& t);  // OK
    void MySub(T const& t);  // Not OK

- Do not use ``NULL``, ``nil`` or ``0`` constants; use ``nullptr`` (improves portability)

- Consider whether you want the default constructor, copy constructor, or assignment
  operator in your class. If not, explicitly mark them as deleted and make the
  declaration public:

  .. sourcecode:: cpp

    class MyClass
    {
      public:
        // Allowed constructors
        MyClass(int i);

        // Deleted constructors.
        // Explain why they are not supported.
        MyClass() = delete;
        MyClass(const MyClass&) = delete;
        MyClass& operator=(const MyClass&) = delete;
    };

- Avoid returning a reference to an internal or local member of an object:

  .. sourcecode:: cpp

    MyType& foo();        // Avoid. Prefer to return a pointer or an object.
    const MyType& foo();  // Same as above.

  This guidance does not apply to the use of references to implement operators.

- Expose class members through access functions, rather than direct access
  to a public object. The access functions are typically named ``Get`` and
  ``Set`` followed by the member's name. For example, a member ``m_delayTime``
  might have accessor functions ``GetDelayTime()`` and ``SetDelayTime()``.

- Do not bring the C++ standard library namespace into |ns3| source files by
  using the ``using namespace std;`` directive.

- Do not use the C++ ``goto`` statement.

- Do not add the ``enum`` or ``struct`` specifiers when declaring the variable's type.

- Do not unnecessarily add ``typedef`` to ``struct`` or ``enum``.

  .. sourcecode:: cpp

    // Avoid
    typedef struct
    {
        ...
    } MyStruct;

    // Prefer
    struct MyStruct
    {
        ...
    };

- When checking whether a Time value is zero, use ``Time::IsZero()`` rather than comparing it to a zero-valued time object with ``operator==``, to avoid construction of a temporary.  Similar guidance applies to the related functions ``Time::IsPositive()``, ``Time::IsNegative()``, ``Time::IsStrictlyPositive``, and ``Time::IsStrictlyNegative()``.

  .. sourcecode:: cpp

    Time t = ...;
    // prefer the below:
    if (t.IsStrictlyPositive())
    {...}
    // to this alternative:
    if (t > Seconds(0))
    {...}

Clang-tidy rules
================

Please refer to the ``.clang-tidy`` file in the |ns3| main directory for the full list
of rules that should be observed while developing code.

Some rules are explained in the corresponding sections above. The remaining rules are
explained here.

- Explicitly mark inherited functions with the ``override`` specifier.

- When creating STL smart pointers, prefer to use ``std::make_shared`` or
  ``std::make_unique``, instead of creating the smart pointer with ``new``.

  .. sourcecode:: cpp

    auto node = std::make_shared<Node>();           // OK
    auto node = std::shared_ptr<Node>(new Node());  // Avoid

- When looping through containers, prefer to use range-based for loops rather than
  index-based loops.

  .. sourcecode:: cpp

    std::vector<int> myVector{1, 2, 3};

    for (const auto& v : myVector) { ... }             // Prefer
    for (int i = 0; i < myVector.size(); i++) { ... }  // Avoid

- Avoid accessing class static functions and members through objects.
  Instead, prefer to access them through the class.

  .. sourcecode:: cpp

    // OK
    MyClass::StaticFunction();

    // Avoid
    MyClass myClass;
    MyClass.StaticFunction();

- Prefer using type traits in short form ``traits_t<...>`` and ``traits_v<...>``,
  instead of the long form ``traits<...>::type`` and ``traits<...>::value``, respectively.

  .. sourcecode:: cpp

    // Prefer using the shorter version of type traits
    std::is_same_v<int, float>
    std::is_integral_v<T>
    std::enable_if_t<std::is_integral_v<T>, Time>

    // Avoid the longer form of type traits
    std::is_same<int, float>::value
    std::is_integral<T>::value
    std::enable_if<std::is_integral<T>::value, Time>::type

- Avoid using integer values (``1`` or ``0``) to represent boolean variables
  (``true`` or ``false``), to improve code readability and avoid implicit conversions.

- Prefer to use ``static_assert()`` over ``NS_ASSERT()`` when conditions can be
  evaluated at compile-time.

- Prefer using transparent functors to non-transparent ones, to avoid repeating
  the type name. This improves readability and avoids errors when refactoring code.

  .. sourcecode:: cpp

    // Prefer using transparent functors
    std::map<MyClass, int, std::less<>> myMap;

    // Avoid repeating the type name "MyClass" in std::less<>
    std::map<MyClass, int, std::less<MyClass>> myMap;

- In conditional control blocks (i.e., if-else and switch-case), avoid declaring multiple
  branch conditions with the same content to avoid duplicating code.

  In if-else blocks, prefer grouping the identical bodies in a single if condition with a
  disjunction of the multiple conditions.

  .. sourcecode:: cpp

    if (condition1)
    {
        Foo();
    }
    else if (condition2)
    {
        // Same body as condition 1
        Foo();
    }
    else
    {
        Bar();
    }

    // Prefer grouping the two conditions
    if (condition1 || condition2)
    {
        Foo();
    }
    else
    {
        Bar();
    }

  In switch-case blocks, prefer grouping identical ``case`` labels by removing the duplicate
  bodies of the former ``case`` labels.

  .. sourcecode:: cpp

    switch (condition)
    {
    case 1:
        Foo();
        break;
    case 2: // case 2 has the same body as case 1
        Foo();
        break;
    case 3:
        Bar();
        break;
    }

    switch (condition)
    {
    // Group identical cases by removing the content of case 1 and letting it fallthrough to case 2
    case 1:
    case 2:
        Foo();
        break;
    case 3:
        Bar();
        break;
    }


CMake file formatting
*********************

The ``CMakeLists.txt`` and other ``*.cmake`` files follow the formatting rules defined in
``build-support/cmake-format.yaml`` and ``build-support/cmake-format-modules.yaml``.

The first set of rules applies to CMake files in all directories that are not modules,
while the second one applies to files within modules.

.. _cmake-format: https://cmake-format.readthedocs.io/en/latest/cmake-format.html

Those rules are enforced via the `cmake-format`_ tool, that can be installed via Pip.

.. sourcecode:: console

    pip install cmake-format pyyaml

After installing cmake-format, it can be called to fix the formatting of a CMake file
with the following command:

.. sourcecode:: console

    cmake-format -c ./build-support/cmake-format.yaml CMakeLists.txt

To check the formatting, add the `--check` option to the command, before specifying
the list of CMake files.

Instead of calling this command for every single CMake file, it is recommended to use
the ``ns3`` script to run the custom targets that do that automatically.

.. sourcecode:: console

    # Check CMake formatting
    ./ns3 build cmake-format-check

    # Check and fix CMake formatting
    ./ns3 build cmake-format

Custom functions and macros need to be explicitly configured in the ``cmake-format.yaml`` files,
otherwise their formatting will be broken.

Python file formatting
**********************

.. _Black: https://black.readthedocs.io/en/stable/index.html
.. _Isort: https://pycqa.github.io/isort/index.html
.. _Black current style: https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html

Python format style and rule enforcement is based on the default settings for the `Black`_
formatter tool and `Isort`_ import sorter tool. Black default format is detailed in `Black current style`_.

The custom settings for both tools are set in the ``pyproject.toml`` file.

These tools that can be installed via Pip, using the following command:

.. sourcecode:: console

    pip install black isort

To check the formatting, add the `--check` option to the command:

.. sourcecode:: console

    black --check .
    isort --check .

To check and fix the formatting, run the commands as follows:

.. sourcecode:: console

    black .
    isort .

.. _MS Black formatter: https://marketplace.visualstudio.com/items?itemName=ms-python.black-formatter
.. _MS Isort: https://marketplace.visualstudio.com/items?itemName=ms-python.isort

For VS Code users, `MS Black formatter`_ and `MS Isort`_ extensions, which repackage
Black and Isort for VS Code, can be installed to apply fixes regularly.
To configure VS Code to automatically format code when saving, editing or pasting code,
add the following configuration to ``.vscode/settings.json``:

.. sourcecode:: json

  {
    "editor.formatOnPaste": true,
    "editor.formatOnSave": true,
    "editor.formatOnType": true,
    "[python]": {
      "editor.defaultFormatter": "ms-python.black-formatter",
      "editor.codeActionsOnSave": {
          "source.organizeImports": "explicit",
      },
    },
    "black-formatter.args": [
      "--config",
      "pyproject.toml",
    ],
    "isort.check": true,
    "isort.args": [
      "--sp",
      "pyproject.toml",
    ],
  }

Markdown Lint
*************

.. _MarkdownLint: https://github.com/DavidAnson/MarkdownLint
.. _MarkdownLint Rules: https://github.com/DavidAnson/MarkdownLint/blob/main/doc/Rules.md
.. _MarkdownLint Installation: https://github.com/igorshubovych/markdownlint-cli?tab=readme-ov-file#installation
.. _MarkdownLint Configuration File: https://github.com/DavidAnson/MarkdownLint/blob/main/schema/.MarkdownLint.yaml
.. _MarkdownLint Docker: https://github.com/igorshubovych/MarkdownLint-cli/pkgs/container/MarkdownLint-cli
.. _MarkdownLint VS Code Extension: https://marketplace.visualstudio.com/items?itemName=DavidAnson.vscode-MarkdownLint

|ns3| uses `MarkdownLint`_ as a linter of Markdown files.
This linter checks if Markdown files follow a set of defined rules, in order to encourage
standardization and consistency of Markdown files across parsers.
It also ensures that Markdown files are correctly interpreted and rendered.

MarkdownLint detects linting issues and can fix most of them automatically.
Some issues may need to be manually fixed.

MarkdownLint configuration
==========================

MarkdownLint's settings are saved in the file ``.markdownlint.yml``.
This schema of this file is defined in `MarkdownLint Configuration File`_,
which explains how to customize the tool to enable / disable rules or customize its parameters.

The list of Markdown rules supported by MarkdownLint is available in `MarkdownLint Rules`_.

Install and Run MarkdownLint
============================

MarkdownLint is written in NodeJS. To run MarkdownLint, either use the official
MarkdownLint Docker image, install it natively in macOS via Homebrew,
or install MarkdownLint with NodeJS / npm.

Run MarkdownLint with Docker image
##################################

MarkdownLint has an official Docker image in `MarkdownLint Docker`_ with the tool
and all dependencies installed.

To run MarkdownLint in a Docker container, use the following command:

.. sourcecode:: console

  # Check all Markdown files in the current directory and subdirectories
  docker run --rm -v $PWD:/workdir ghcr.io/igorshubovych/markdownlint-cli:latest . [--fix]

  # Check specific Markdown file
  docker run --rm -v $PWD:/workdir ghcr.io/igorshubovych/markdownlint-cli:latest PATH_TO_FILE [--fix]

If the ``fix`` flag is used, the tool tries to automatically fix the detected issues.
Otherwise, it only reports the issues found.

Install and Run MarkdownLint natively
#####################################

To install MarkdownLint natively, either on macOS via Homebrew or using NodeJS / npm,
follow the instructions available in `MarkdownLint Installation`_.

To run MarkdownLint, use the following command:

.. sourcecode:: console

  # Check all Markdown files in the current directory and subdirectories
  markdownlint-cli . [--fix]

  # Check specific Markdown file
  markdownlint-cli PATH_TO_FILE [--fix]

VS Code Extension
=================

For VS Code users, the `MarkdownLint VS Code Extension`_ extension is available in the marketplace.
This extension uses the same engine and respects the configuration file.

The MarkdownLint extension automatically analyzes files open in the editor and provides inline hints
when issues are detected. It can automatically fix most issues related with formatting.
As explained in the "Integration with IDEs" section, VS Code can be configured to automatically
format code when saving, editing or pasting code.