diff --git a/.gitignore b/.gitignore index b1d072d..6c7f673 100644 --- a/.gitignore +++ b/.gitignore @@ -302,4 +302,10 @@ src/project4/analytical_comparison/ src/project4/main src/project4/analytical src/project4/single_threaded_performance -src/project4/multi_threaded_performance \ No newline at end of file +src/project4/multi_threaded_performance + +# Project 5 executables +src/project5/main +src/project5/debug +src/project5/*.bin +/build/ \ No newline at end of file diff --git a/projects/project4/main.pdf b/projects/project4/main.pdf index 1539ab2..3dd71a6 100644 Binary files a/projects/project4/main.pdf and b/projects/project4/main.pdf differ diff --git a/projects/project5/chapters/conclusion.tex b/projects/project5/chapters/conclusion.tex new file mode 100644 index 0000000..470eec4 --- /dev/null +++ b/projects/project5/chapters/conclusion.tex @@ -0,0 +1,11 @@ +This project successfully developed and implemented a numerical framework for solving the two-dimensional, time-dependent Schrödinger equation. Using the Crank–Nicolson finite difference scheme, we were able to simulate quantum wave packet dynamics stably and accurately. The implicit method enabled comparatively large time steps to be taken while maintaining second-order accuracy in both space and time. + +The C++ implementation leveraged the Armadillo library for efficient sparse linear algebra operations, enabling the simulation of systems with high spatial resolution. A key strength of the framework is its configurability via TOML input files, which allows for straightforward experimentation with various initial conditions, potential landscapes and discretisation parameters, eliminating the need for recompilation. + +Our results demonstrate the numerical robustness of the approach. The total probability was conserved to within an order of \num{e-15} over the simulation duration, indicating excellent numerical stability. The simulations correctly reproduced fundamental quantum mechanical phenomena, including the diffraction and interference of a wave packet passing through single, double, and triple slit potentials. The characteristic interference patterns observed on a virtual detector screen qualitatively match theoretical expectations, validating the physical correctness of the implementation. + +The framework's output of the complete wave function at each time step allows for maximum flexibility in post-processing. As demonstrated, this enables the computation of arbitrary observables, such as probability density slices at any spatial location, extending beyond the simple screen detection example. + +Several extensions are promising for future work. For example, the potential function could be generalised to model more complex systems, such as quantum dots, wells or tunnelling barriers. Implementing absorbing boundary conditions, such as complex absorbing potentials (CAP) or perfectly matched layers (PML), would enable the simulation of scattering problems and open systems without reflections. Furthermore, adapting the code to leverage GPU acceleration or parallel computing techniques would enable the simulation of larger domains or three-dimensional systems, significantly expanding the range of physically interesting problems that can be explored. + +In summary, this project provides a reliable and extensible foundation for the numerical investigation of time-dependent quantum mechanical phenomena in two dimensions, bridging the gap between theoretical concepts and computational experimentation. diff --git a/projects/project5/chapters/introduction.tex b/projects/project5/chapters/introduction.tex new file mode 100644 index 0000000..23048a7 --- /dev/null +++ b/projects/project5/chapters/introduction.tex @@ -0,0 +1,9 @@ +The Schrödinger equation, introduced in 1925, is a fundamental equation in quantum mechanics that describes how the quantum state of a physical system changes over time. It is a key result of wave mechanics, one of the two main formulations of quantum mechanics (the other being matrix mechanics). The equation is named after Erwin Schrödinger, who developed it and won the Nobel Prize in Physics in 1933 for his work. + +The time-dependent Schrödinger equation is given by: +\begin{equation} + i\hbar \frac{\partial}{\partial t} \psi = \hat{H} \psi, +\end{equation} +where \(i\) is the imaginary unit, \(\hbar\) is the reduced Planck constant, and \(\psi\) is the wave function of the quantum system. The Hamiltonian operator, \(\hat{H}\), represents the total energy of the system, i.e., the sum of kinetic and potential energies. + +In \cref{sec:methods}, we describe the numerical methods used to solve the two-dimensional Schrödinger equation. In \cref{sec:results_and_discussion}, we present and discuss the results obtained from our numerical simulations. Finally, in \cref{sec:conclusion}, we summarize our findings and discuss potential future work. diff --git a/projects/project5/chapters/methods.tex b/projects/project5/chapters/methods.tex new file mode 100644 index 0000000..39c6855 --- /dev/null +++ b/projects/project5/chapters/methods.tex @@ -0,0 +1,131 @@ +\subsection{Discretization of the Schrödinger equation} +All numerical methods for solving differential equations rely on the discretization of continuous variables. In this project, we will discretize both space and time. We will begin with the two-dimensional time-dependent Schrödinger equation: +\begin{align} + i\hbar \frac{\partial}{\partial t} \psi(x,y,t) &= -\frac{\hbar^2}{2m} \left( \frac{\partial^2}{\partial x^2} + \frac{\partial^2}{\partial y^2} \right) \psi(x,y,t) \nonumber\\&+ V(x,y) \psi(x,y,t). +\end{align} +We define a grid with spacing \(h\) in both the \(x\) and \(y\) directions to discretize space. The grid points are given by \(x_i = i h\) and \(y_j = j h\), where \(i\) and \(j\) are integers. The wave function at these grid points is denoted as \(\psi_{i,j}(t) = \psi(x_i, y_j, t)\) . We also discretize time with a time step of size \(\Delta t\), such that \(t_n = n \Delta t\), where \(n\) is an integer. The wave function at time \(t_n\) is denoted as \(\psi_{i,j}^n = \psi_{i,j}(t_n)\). +For simplicity, we set both \(\hbar = \qty{1}{\per \s}\) and \(m = 1\). This yields the dimensionless form of the Schrödinger equation: +\begin{align} + i \frac{\partial}{\partial t} u(x,y,t) &= - \frac{\partial^2}{\partial x^2} u(x,y,t) - \frac{\partial^2}{\partial y^2} u(x,y,t) \nonumber\\&+ v(x,y) u(x,y,t). +\end{align} +In this form, we substitute \(u\) for \(\psi\) and \(v\) for \(V\) to eliminate constants. We can then reobtain the physical probability density, $P = \psi^\ast \psi$, by appropriately normalizing the wave function: +\begin{equation} + P(x,y,t) = \frac{u^\ast(x,y,t) u(x,y,t)}{\int \int u^\ast(x,y,t) u(x,y,t) \, dx \, dy}. +\end{equation} +In practice, the integral in the denominator is equal to the sum of all grid points multiplied by the area element \(h^2\). + +Using the Crank-Nicolson scheme, we can approximate the time evolution of the wave function. The Crank-Nicolson method is a second-order accurate, unconditionally stable implicit finite difference method in both space and time. The update rule for the wave function using the Crank-Nicolson scheme is given by the following formula \cite{liuCrankNicolsonMethod2022}: +\begin{equation} + \left( I + \frac{i \Delta t}{2} H \right) u^{n+1} = \left( I - \frac{i \Delta t}{2} H \right) u^n, +\end{equation} +where \(I\) is the identity matrix, \(H\) is the discretized Hamiltonian operator, and \(u^n\) and \(u^{n+1}\) are the wave functions at time steps \(n\) and \(n+1\), respectively. The Hamiltonian operator \(H\) can be discretized using finite difference approximations for the second derivatives: +\begin{align} + H_{i,j} &= -\frac{1}{h^2} \left( u_{i+1,j} + u_{i-1,j} + u_{i,j+1} + u_{i,j-1} - 4u_{i,j} \right) \nonumber\\&+ v_{i,j} u_{i,j}. +\end{align} +By defining the constant as \(r \equiv \frac{i \Delta t}{2 h^2}\), we can rewrite the update rule as follows: +\begin{align} + &u_{i,j}^{n+1} + r \left( u_{i+1,j}^{n+1} + u_{i-1,j}^{n+1} + u_{i,j+1}^{n+1} + u_{i,j-1}^{n+1} - 4u_{i,j}^{n+1} \right) \nonumber\\&= u_{i,j}^n - r \left( u_{i+1,j}^n + u_{i-1,j}^n + u_{i,j+1}^n + u_{i,j-1}^n - 4u_{i,j}^n \right)\nonumber\\& - i \Delta t v_{i,j} \frac{u_{i,j}^{n+1} + u_{i,j}^n}{2}. +\end{align} +We can rearrange this equation to form a linear system that can be solved for \(u^{n+1}\) at each time step. We define the index mapping \(k = i + j M\), where \(M\) is the number of grid points in one dimension and \(M = \frac{1}{h} + 1\). This allows us to rewrite the two-dimensional grid as a one-dimensional array \cite{anderskvellestadProject5FYS3150}. The resulting linear system can be expressed in matrix form as follows: +\begin{equation} + A u^{n+1} = B u^n, +\end{equation} +where \(A\) and \(B\) are matrices that depend on the discretization parameters and the potential \(v\). Only the internal points of the problem are contained in \(A,\,B,\,u^n\). Boundary conditions are applied separately. For this project, we will use Dirichlet boundary conditions and set the wave function to zero at the grid boundaries. +Matrix \(A\) is tridiagonal with additional diagonals due to the two-dimensional nature of the problem. The matrix \(B\) has a similar structure. To solve for \(u^{n+1}\), first calculate $b^n = B u^n$, then solve the linear system \(A u^{n+1} = b^n\) using an appropriate numerical method, such as LU decomposition or iterative solvers. + +\subsection{Initial conditions and potential} +To simulate the time evolution of the wave function, we must specify the initial conditions and the potential, \(v(x,y)\). A common choice for the initial wave function is a Gaussian wave packet, defined as follows \cite{anderskvellestadProject5FYS3150}: +\begin{align} + u(x,y,0) &= \exp\left( -\frac{(x-x_C)^2}{2\sigma_x^2} - \frac{(y-y_C)^2}{2\sigma_y^2}\right) \nonumber\\&\cdot \exp \left( i(p_x x + p_y y) \right), +\end{align} +where \((x_C, y_C)\) is the center of the wave packet and where \(\sigma_x, \sigma_y)\) are the widths of the packet in the \(x\) and \(y\) directions, respectively, and where the initial momenta in the respective directions are represented by \((p_x, p_y)\). The potential, \(v(x,y)\), can be chosen based on the physical system being modeled. For example, a double-slit-like potential can be used. To implement slits in the potential grid, we use the algorithm outlined in \cref{alg:add_slits}. This algorithm modifies the potential grid, \(V\), by adding walls of a specified thickness and position while leaving apertures for the slits. An initialization function finalizes the potential setup by calculating the matrices \(A\) and \(B\) based on the modified potential. + + +\begin{algorithm}[H] +\caption{Add Slits to Potential Grid} +\label{alg:add_slits} +\begin{algorithmic}[1] +\Require $h$, $M$, $V$, $V_{\text{wall}}$, $ \text{wall\_thickness}$, $\text{wall\_position}$, $\text{slit\_aperture}$, $\text{slit\_separation}$, $\text{num\_slits}$ +\State $x_{\text{start}} \gets \left\lfloor \dfrac{\text{wall\_position} - 0.5\,\text{wall\_thickness}}{h} \right\rfloor$ +\State $x_{\text{end}} \gets \left\lfloor \dfrac{\text{wall\_position} + 0.5\,\text{wall\_thickness}}{h} \right\rfloor$ +\State $y_c \gets M/2$ +\State $\text{slit\_half} \gets \left\lfloor \dfrac{0.5\,\text{slit\_aperture}}{h} \right\rfloor$ +\State $\text{pitch} \gets \text{slit\_aperture} + \text{slit\_separation}$ +\State $\text{pitch}_{\text{idx}} \gets \text{pitch}/h$ + +\For{$i = x_{\text{start}}$ \textbf{to} $x_{\text{end}}$} + \For{$j = 0$ \textbf{to} $M-1$} + \State $\text{in\_slit} \gets \text{false}$ + \For{$s = 0$ \textbf{to} $\text{num\_slits}-1$} + \State $\Delta \gets \left(s - \dfrac{\text{num\_slits}-1}{2}\right)\,\text{pitch}_{\text{idx}}$ + \State $c_s \gets \left\lfloor y_c + \Delta + 0.5 \right\rfloor$ \Comment{rounded center index} + \If{$j \in [\,c_s - \text{slit\_half}, \; c_s + \text{slit\_half}\,]$} + \State $\text{in\_slit} \gets \text{true}$ + \State \textbf{break} + \EndIf + \EndFor + \If{\textbf{not} $\text{in\_slit}$} + \State $V[i,j] \gets V_{\text{wall}}$ + \EndIf + \EndFor +\EndFor + +\State \Call{initialize\_potential}{} + +\end{algorithmic} +\end{algorithm} + +\subsection{Implementation details} +To optimize performance, the numerical methods were implemented in C++, compiled with optimization flags, and compiled using the \texttt{g++} compiler. Version \texttt{g++ (GCC) 15.2.1 20251111 (Red Hat 15.2.1-4)} was used for compilation. The Armadillo library \cite{sandersonArmadilloEfficientFramework2025,sandersonPracticalSparseMatrices2019} was used for all linear algebra operations because it provides efficient implementations of matrix and vector operations. Matrices \(A\) and \(B\) are constructed as sparse \cite{sandersonPracticalSparseMatrices2019}, complex matrices to save memory and improve computational efficiency. We solved the linear system \(A u^{n+1} = b^n\) using the \texttt{spsolve} function from the Armadillo library. This function is optimized for sparse matrices and uses an implementation provided by SuperLU \cite{demmelSuperLUUsersGuide1999}. + +To allow for easy experimentation with different parameters, the program reads a configuration file in TOML format during runtime. The configuration file specifies parameters in four main categories: +Discretization parameters: \(h, \Delta t\), and total simulation time \(T\); Initial wave packet parameters (center position, width, and momentum); Potential parameters (wall height, wall thickness, slit aperture, slit separation, and number of slits); Output parameters (output file name). The program uses Armadillo's built-in functions to parse the wave function results at each time step and write them to a file in \texttt{arma\_ascii} format. + +All analyses and visualizations of the results are performed in Python using the NumPy \cite{harrisArrayProgrammingNumPy2020} and Matplotlib \cite{hunterMatplotlib2DGraphics2007} libraries. The probability density is computed from the wave function data, and various plots are generated to illustrate the time evolution of the wave packet and the effects of the potential. A self-developed parser for the Armadillo ASCII format reads the output files generated by the C++ program, as described in \cref{alg:pythonparser}. + +\begin{algorithm}[H] +\caption{Load Armadillo ASCII Complex Cube}\label{alg:pythonparser} +\begin{algorithmic}[1] + +\Procedure{LoadCube}{path, slices\_first} + + \State txt $\gets$ read file at \textit{path} + \State lines $\gets$ split(txt) + \State header $\gets$ first two lines + \State $(n_{\text{rows}}, n_{\text{cols}}, n_{\text{slices}}) \gets$ parse(header[1]) + + \State rest $\gets$ remaining lines + + \For{each line in rest} + \State remove all ``('' and ``)'' + \State apply regex + \[ + \texttt{([+-]?\d[\d.eE+-]*)\ ,\ ([+-]?\d[\d.eE+-]*)} + \] + which captures two floating-point values \(r\) and \(i\), possibly with + signs or scientific notation + \State replace with + \[ + \texttt{\$1+\$2j} + \] + yielding Python-style complex numbers \(r + ij\) + \State append transformed line to fixed + \EndFor + + \State arr$_{2D}$ $\gets$ \Call{numpy.loadtxt}{fixed} + \State arr$_{3D}$ $\gets$ reshape(arr$_{2D}$, $(n_{\text{slices}}, n_{\text{cols}}, n_{\text{rows}})$) + + \If{slices\_first} + \State \Return arr$_{3D}$ + \Else + \State \Return transpose(arr$_{3D}$) + \EndIf + +\EndProcedure + +\end{algorithmic} +\end{algorithm} + +\subsubsection*{Use of Artificial Intelligence} +In this project, artificial intelligence in the form of large language models (LLMs) was employed to assist with various stages of the research and development process. The LLMs generated initial drafts of code snippets that the researcher reviewed and refined for correctness and efficiency. GitHub Copilot, an LLM, was used for this task. LLMs were also used to edit the report's language by providing grammar and style suggestions. For this task, the DeepL Write service by DeepL GmbH was used. + diff --git a/projects/project5/chapters/results.tex b/projects/project5/chapters/results.tex new file mode 100644 index 0000000..edf59e3 --- /dev/null +++ b/projects/project5/chapters/results.tex @@ -0,0 +1,30 @@ +We evaluate the accuracy of the resulting solutions by assessing the conservation of probability in the system with and without a double slit, i.e., with \(V_\text{wall} = 0\) and in the presence of such a potential. We simulate the systems for a total time of \qty{0.008}{\s} in steps of \(\Delta t = \qty{2.5e-5}{\s}\). Spatial discretization is carried out using a step size of \(h = \num{0.005}\). In the setup with a non-zero potential wall, the initial wave packet is centered at \(x=\num{0.25}\) and \(y=\num{0.5}\), with widths of \(\sigma_x=\num{0.05}\) and \(\sigma_y=\num{0.10}\), respectively. Its momenta are \(p_x=\num{200.0}\) and \(p_y=\num{0.0}\), resulting in strongly directed motion along \(x\). +A double-slit barrier with a thickness of \(\num{0.02}\) is placed at \(x=\num{0.5}\). +Each slit has an aperture of \(\num{0.05}\) and is separated by \(\num{0.05}\). The wall potential is effectively infinite at \(V_{\text{wall}}=\num{1.0e10}\). In the case of a constant potential, the wave packet has widths of \(\sigma = \num{0.05}\) in both \(x\) and \(y\). Otherwise, the setup is identical. The resulting wave functions are evaluated for loss of probability. +\begin{equation} + \delta = 1 - \iint u^\ast(x,y,t) u(x,y,t) \mathrm{d}x \mathrm{d}y, +\end{equation} +where \(\iint u^\ast(x,y,0) u(x,y,0) \mathrm{d}x \mathrm{d}y = 1\) was fixed using normalization. In a perfect physical system, this quantity is conserved; however, due to limited numerical accuracy, especially in the derivatives and solving of the linear system, it is not conserved. Therefore, it is a good indication of the algorithm's potential accuracy. \Cref{fig:prob_conservation} shows the resulting analysis. The maximum deviation is about \num{2e-15}, demonstrating performance that is only one order of magnitude worse than floating-point precision. Notably, the accuracy of the system without a double slit is lower than the corresponding values with the perturbation. Additionally, the simulation's dependence on potential is evident, precluding any general attestation of performance for arbitrary potentials. Nevertheless, it can be assumed that the simulation will produce very accurate results for many potentials, attesting to the numerical accuracy of the results. + +\begin{figure} + \centering + \includegraphics[width=\columnwidth]{include/probability_conservation.pdf} + \caption{Loss of total probability $\delta$ in dependence on the simulation duration for two systems of different potential.} + \label{fig:prob_conservation} +\end{figure} + +In addition to the quantitative evaluation of performance, we conduct a qualitative analysis of the system's evolution. To correctly assess the evolution of the wave packet, we perform a double slit experiment on a system for a total duration of \qty{0.002}{\s}. Three time points are sampled to demonstrate the wave packet's interference with itself behind the double slit. The results of this analysis are presented in \cref{fig:t_0_evolution,fig:t_1_evolution,fig:t_2_evolution} in Appendix \cref{app:evolv}. +We observe the expected qualitative behavior with respect to interference and the correct diffusion of the wave function. Therefore, we can conclude that the simulation framework behaves correctly. To evaluate the evolution of the probability distribution, we produced animations of the entire runtime for each simulation. These animations can be accessed via the repository of this paper, though they are not essential to understanding the paper. + +Lastly, we demonstrate the flexibility of our approach to simulating the numerical evolution of such a system by simulating the probability of detecting a particle on a screen inserted into the system at a specific time. We computed the probability density function (PDF) for a screen position of \(y = \num{0.8}\) at \(T = \qty{0.002}{\s}\) for three systems: a single slit, a double slit, and a triple slit. The detection PDF is given by the slice +\begin{equation} + P(x) = \frac{u^\ast(x,\num{0.8},\qty{0.002}{\s}) u(x,\num{0.8},\qty{0.002}{\s})}{\int \mathrm{d}x u^\ast(x,\num{0.8},\qty{0.002}{\s}) u(x,\num{0.8},\qty{0.002}{\s})}, +\end{equation} +where the integral is evaluated as a sum over the total time slice. The resulting PDF is displayed in \cref{fig:screen}. Once again, the interference of the wave packet with itself is clearly visible, leading to the expected result. More importantly, this shows how such a numerical simulation can be used to compute arbitrary metrics because the entire numerical solution of the wave function is saved to a file that can be repurposed in multiple ways. + +\begin{figure} + \centering + \includegraphics[width=\columnwidth]{include/detector_screens.pdf} + \caption{PDF of detecting the wave packet at a certain position on a screen inserted at $y=\num{0.8}$ and $T = \qty{0.002}{\s}$.} + \label{fig:screen} +\end{figure} \ No newline at end of file diff --git a/projects/project5/include/project5.bib b/projects/project5/include/project5.bib new file mode 100644 index 0000000..0ba78bc --- /dev/null +++ b/projects/project5/include/project5.bib @@ -0,0 +1,102 @@ +@misc{anderskvellestadProject5FYS3150, + title = {Project 5 --- {{FYS3150}}/{{FYS4150}} Course Material}, + author = {{Anders Kvellestad}}, + urldate = {2025-12-09}, + howpublished = {https://anderkve.github.io/FYS3150/book/projects/project5.html}, + file = {/home/lars/Zotero/storage/IVLD4EHN/project5.html} +} + +@techreport{demmelSuperLUUsersGuide1999, + title = {{{SuperLU}} Users' Guide}, + author = {Demmel, James W. and Gilbert, John R. and Li, Xiaoye S.}, + year = 1999, + month = nov, + number = {LBNL--44289, 751785}, + pages = {LBNL--44289, 751785}, + doi = {10.2172/751785}, + urldate = {2025-12-09}, + langid = {english}, + file = {/home/lars/Zotero/storage/8FELF93A/Demmel et al. - 1999 - SuperLU users' guide.pdf} +} + +@article{harrisArrayProgrammingNumPy2020, + title = {Array Programming with {{NumPy}}}, + author = {Harris, Charles R. and Millman, K. Jarrod and van der Walt, St{\'e}fan J. and Gommers, Ralf and Virtanen, Pauli and Cournapeau, David and Wieser, Eric and Taylor, Julian and Berg, Sebastian and Smith, Nathaniel J. and Kern, Robert and Picus, Matti and Hoyer, Stephan and van Kerkwijk, Marten H. and Brett, Matthew and Haldane, Allan and del R{\'i}o, Jaime Fern{\'a}ndez and Wiebe, Mark and Peterson, Pearu and {G{\'e}rard-Marchant}, Pierre and Sheppard, Kevin and Reddy, Tyler and Weckesser, Warren and Abbasi, Hameer and Gohlke, Christoph and Oliphant, Travis E.}, + year = 2020, + month = sep, + journal = {Nature}, + volume = {585}, + number = {7825}, + pages = {357--362}, + publisher = {{Springer Science and Business Media LLC}}, + doi = {10.1038/s41586-020-2649-2} +} + +@article{hunterMatplotlib2DGraphics2007, + title = {Matplotlib: {{A 2D}} Graphics Environment}, + author = {Hunter, J. D.}, + year = 2007, + journal = {Computing in Science \& Engineering}, + volume = {9}, + number = {3}, + pages = {90--95}, + publisher = {IEEE COMPUTER SOC}, + doi = {10.1109/MCSE.2007.55}, + abstract = {Matplotlib is a 2D graphics package used for Python for application development, interactive scripting, and publication-quality image generation across user interfaces and operating systems.} +} + +@article{liuCrankNicolsonMethod2022, + title = {Crank--{{Nicolson}} Method for Solving Uncertain Heat Equation}, + author = {Liu, Jin and Hao, Yifei}, + year = 2022, + month = feb, + journal = {Soft Computing}, + volume = {26}, + number = {3}, + pages = {937--945}, + issn = {1433-7479}, + doi = {10.1007/s00500-021-06565-9}, + urldate = {2025-12-09}, + abstract = {For usual uncertain heat equations, it is challenging to acquire their analytic solutions. A forward difference Euler method has been used to compute the uncertain heat equations' numerical solutions. Nevertheless, the Euler scheme is instability in some cases. This paper proposes an implicit task to overcome this disadvantage, namely the Crank--Nicolson method, which is unconditional stability. An example shows that the Crank--Nicolson scheme is more stable than the previous scheme (Euler scheme). Moreover, the Crank--Nicolson method is also applied to compute two characteristics of uncertain heat equation's solution---expected value and extreme value. Some examples of uncertain heat equations are designed to show the availability of the Crank--Nicolson method.}, + langid = {english}, + keywords = {Crank-Nicolson method,Heat equation,Liu process,Numerical solution}, + file = {/home/lars/Zotero/storage/Y67L5UFB/Liu and Hao - 2022 - Crank–Nicolson method for solving uncertain heat equation.pdf} +} + +@inproceedings{sandersonArmadilloEfficientFramework2025, + title = {Armadillo: {{An Efficient Framework}} for {{Numerical Linear Algebra}}}, + shorttitle = {Armadillo}, + booktitle = {2025 17th {{International Conference}} on {{Computer}} and {{Automation Engineering}} ({{ICCAE}})}, + author = {Sanderson, Conrad and Curtin, Ryan}, + year = 2025, + month = mar, + eprint = {2502.03000}, + primaryclass = {cs}, + pages = {303--307}, + doi = {10.1109/ICCAE64891.2025.10980539}, + urldate = {2025-10-16}, + abstract = {A major challenge in the deployment of scientific software solutions is the adaptation of research prototypes to production-grade code. While high-level languages like MATLAB are useful for rapid prototyping, they lack the resource efficiency required for scalable production applications, necessitating translation into lower level languages like C++. Further, for machine learning and signal processing applications, the underlying linear algebra primitives, generally provided by the standard BLAS and LAPACK libraries, are unwieldy and difficult to use, requiring manual memory management and other tedium. To address this challenge, the Armadillo C++ linear algebra library provides an intuitive interface for writing linear algebra expressions that are easily compiled into efficient production-grade implementations. We describe the expression optimisations we have implemented in Armadillo, exploiting template metaprogramming. We demonstrate that these optimisations result in considerable efficiency gains on a variety of benchmark linear algebra expressions.}, + archiveprefix = {arXiv}, + keywords = {Computer Science - Mathematical Software}, + file = {/home/lars/Zotero/storage/UNJD6AR5/Sanderson and Curtin - 2025 - Armadillo An Efficient Framework for Numerical Linear Algebra.pdf;/home/lars/Zotero/storage/RHNN68A2/2502.html} +} + +@article{sandersonPracticalSparseMatrices2019, + title = {Practical {{Sparse Matrices}} in {{C}}++ with {{Hybrid Storage}} and {{Template-Based Expression Optimisation}}}, + author = {Sanderson, Conrad and Curtin, Ryan}, + year = 2019, + month = jul, + journal = {Mathematical and Computational Applications}, + volume = {24}, + number = {3}, + eprint = {1811.08768}, + primaryclass = {cs}, + pages = {70}, + issn = {2297-8747}, + doi = {10.3390/mca24030070}, + urldate = {2025-10-16}, + abstract = {Despite the importance of sparse matrices in numerous fields of science, software implementations remain difficult to use for non-expert users, generally requiring the understanding of underlying details of the chosen sparse matrix storage format. In addition, to achieve good performance, several formats may need to be used in one program, requiring explicit selection and conversion between the formats. This can be both tedious and error-prone, especially for non-expert users. Motivated by these issues, we present a user-friendly and open-source sparse matrix class for the C++ language, with a high-level application programming interface deliberately similar to the widely used MATLAB language. This facilitates prototyping directly in C++ and aids the conversion of research code into production environments. The class internally uses two main approaches to achieve efficient execution: (i) a hybrid storage framework, which automatically and seamlessly switches between three underlying storage formats (compressed sparse column, Red-Black tree, coordinate list) depending on which format is best suited and/or available for specific operations, and (ii) a template-based meta-programming framework to automatically detect and optimise execution of common expression patterns. Empirical evaluations on large sparse matrices with various densities of non-zero elements demonstrate the advantages of the hybrid storage framework and the expression optimisation mechanism.}, + archiveprefix = {arXiv}, + keywords = {Computer Science - Mathematical Software}, + file = {/home/lars/Zotero/storage/PZ5ZIXJU/Sanderson and Curtin - 2019 - Practical Sparse Matrices in C++ with Hybrid Storage and Template-Based Expression Optimisation.pdf;/home/lars/Zotero/storage/CQNT3AKH/1811.html} +} diff --git a/projects/project5/main.pdf b/projects/project5/main.pdf new file mode 100644 index 0000000..96cd51e Binary files /dev/null and b/projects/project5/main.pdf differ diff --git a/projects/project5/main.tex b/projects/project5/main.tex new file mode 100644 index 0000000..2eab3c9 --- /dev/null +++ b/projects/project5/main.tex @@ -0,0 +1,155 @@ +% USEFUL LINKS: +% ------------- +% +% - UiO LaTeX guides: https://www.mn.uio.no/ifi/tjenester/it/hjelp/latex/ +% - Mathematics: https://en.wikibooks.org/wiki/LaTeX/Mathematics +% - Physics: https://ctan.uib.no/macros/latex/contrib/physics/physics.pdf +% - Basics of Tikz: https://en.wikibooks.org/wiki/LaTeX/PGF/Tikz +% - All the colors! https://en.wikibooks.org/wiki/LaTeX/Colors +% - How to make tables: https://en.wikibooks.org/wiki/LaTeX/Tables +% - Code listing styles: https://en.wikibooks.org/wiki/LaTeX/Source_Code_Listings +% - \includegraphics https://en.wikibooks.org/wiki/LaTeX/Importing_Graphics +% - Learn more about figures: https://en.wikibooks.org/wiki/LaTeX/Floats,_Figures_and_Captions +% - Automagic bibliography: https://en.wikibooks.org/wiki/LaTeX/Bibliography_Management (this one is kinda difficult the first time) +% +% (This document is of class "revtex4-1", the REVTeX Guide explains how the class works) +% REVTeX Guide: http://www.physics.csbsju.edu/370/papers/Journal_Style_Manuals/auguide4-1.pdf +% +% +% COMPILING THE .pdf FILE IN THE LINUX TERMINAL +% --------------------------------------------- +% +% [terminal]$ pdflatex report_example.tex +% +% Run the command twice, always. +% +% When using references, footnotes, etc. you should run the following chain of commands: +% +% [terminal]$ pdflatex report_example.tex +% [terminal]$ bibtex report_example +% [terminal]$ pdflatex report_example.tex +% [terminal]$ pdflatex report_example.tex +% +% This series of commands can of course be gathered into a single-line command: +% [terminal]$ pdflatex report_example.tex && bibtex report_example.aux && pdflatex report_example.tex && pdflatex report_example.tex +% +% ---------------------------------------------------- + + + +% \documentclass[english,notitlepage,reprint,nofootinbib]{revtex4-2} % defines the basic parameters of the document +\documentclass[english,notitlepage,reprint,nofootinbib]{revtex4-2} % defines the basic parameters of the document +% If you want a single-column, remove "reprint" +\usepackage{silence} +\WarningFilter{revtex4-2}{Repair the float} + +% Allows special characters (including æøå) +\usepackage[utf8]{inputenc} +\usepackage[english]{babel} + +% Note that you may need to download some of these packages manually, it depends on your setup. +% It may be usefult to download TeXMaker, because it includes a large library of the most common packages. + +\usepackage{amssymb} % mathematical symbols (physics imports amsmath) +\usepackage{amsmath} +\usepackage{graphicx} % include graphics such as plots +\usepackage{xcolor} % set colors +\usepackage{hyperref} % automagic cross-referencing +\usepackage{listings} % display code +\usepackage{subfigure} % imports a lot of cool and useful figure commands +\usepackage{float} +%\usepackage[section]{placeins} +\usepackage{algorithm} +\usepackage{booktabs} +\usepackage[noend]{algpseudocode} +\usepackage{subfigure} +\usepackage{tikz} +\usepackage[noabbrev,nameinlink]{cleveref} +\usepackage[separate-uncertainty=true]{siunitx} +% Define amu = Dalton +\DeclareSIUnit\amu{u} + +\usepackage{todonotes} +\usetikzlibrary{quantikz} +% defines the color of hyperref objects +% Blending two colors: blue!80!black = 80% blue and 20% black +\hypersetup{ % this is just my personal choice, feel free to change things + colorlinks, + linkcolor={red!50!black}, + citecolor={blue!50!black}, + urlcolor={blue!80!black}} + + +% =========================================== + +\newcommand{\expect}[1]{\left\langle#1\right\rangle} + +\begin{document} + +\title{Solving the Two-dimensional Schrödinger Equation Numerically} % self-explanatory +\author{Lars Bogner} % self-explanatory +\date{\today} % self-explanatory +\affiliation{{\url{https://github.uio.no/larsbog/FYS4150}}} % ignore this, but keep it. + +%This is how we create an abstract section. +\begin{abstract} +We present a numerical framework for solving the two-dimensional, time-dependent Schrödinger equation. Our method uses the unconditionally stable, second-order accurate in both space and time Crank-Nicolson finite difference scheme. We implement the discretized system efficiently in C++ using the Armadillo linear algebra library to handle sparse matrix operations. Our framework is highly configurable and allows us to simulate various potentials, with a specific focus on modeling single- and multiple-slit experiments. Our results demonstrate excellent numerical accuracy, maintaining probability conservation to within an order of \num{e-15}. The simulations successfully reproduce key quantum mechanical phenomena, including wave packet diffraction and the characteristic interference patterns from double and triple slits. Additionally, we demonstrate the approach's flexibility by computing the probability distribution of particle detection on a virtual screen. This work establishes a robust, extensible foundation for computational exploration of two-dimensional time-dependent quantum dynamics. +\end{abstract} + +\maketitle +\tableofcontents + + +% =========================================== +\section{Introduction} +\input{chapters/introduction.tex} + + +% =========================================== +\section{Methods}\label{sec:methods} +\input{chapters/methods.tex} + +% =========================================== +\section{Results and discussion}\label{sec:results_and_discussion} +% +\input{chapters/results.tex} + + +% =========================================== +\section{Conclusion}\label{sec:conclusion} +\input{chapters/conclusion.tex} + + +% =========================================== +\appendix +\section{Evolution of wave function in presence of a double slit} \label{app:evolv} +The simulation uses a grid spacing \(h = \num{0.005}\) and a time step of \(\Delta t = \num{2.5e-5}\,\mathrm{s}\). The double slit has a thickness of \(\num{0.02}\), an aperture of \(\num{0.05}\), a separation of \(\num{0.05}\), and a barrier potential \(V_\mathrm{wall} = \num{1.0e10}\). The wave packet is initially broader in the \(y\)-direction to enhance the visibility of interference effects. Each figure displays three subplots: the probability density in 2D, and the real and imaginary parts of the wave function \(u\), illustrating the full complex evolution of the quantum state. +The time evolution of the wave function in the double-slit setup is illustrated in \cref{fig:t_0_evolution,fig:t_1_evolution,fig:t_2_evolution}. Initially, as shown in \cref{fig:t_0_evolution}, the wave packet is localized before the barrier, with its probability distribution concentrated around the initial position and negligible interference structure. By the intermediate time in \cref{fig:t_1_evolution}, the wave packet has reached the slits, and partial transmission has produced oscillations in the real and imaginary components, while faint interference fringes start forming in the probability distribution. Finally, after the wave has passed the slits, \cref{fig:t_2_evolution} shows well-developed interference fringes in $|u|^2$, and alternating positive and negative regions in the real and imaginary parts, reflecting the coherent superposition of the two transmitted components. +\begin{figure}[ht] + \centering + \includegraphics[width=\columnwidth]{include/wavefunction_t_0.000s.pdf} + \caption{Initial state of the double-slit simulation at $t = \num{0.000}\,\mathrm{s}$. The three panels show (from top to bottom) the probability distribution $|u|^2$, the real part of the wave function $\mathrm{Re}(u)$, and the imaginary part $\mathrm{Im}(u)$. The wave packet is initially centered at $\left(x_c, y_c\right) = \left(\num{0.25}, \num{0.5}\right)$ with widths $\sigma_x = \num{0.05}$ and $\sigma_y = \num{0.20}$, moving primarily in the $x$-direction with momentum $p_x = \num{200.0}$.} + \label{fig:t_0_evolution} +\end{figure} + +\begin{figure}[ht] + \centering + \includegraphics[width=\columnwidth]{include/wavefunction_t_0.001s.pdf} + \caption{Evolution of the wave function at $t = \num{0.001}\,\mathrm{s}$. The wave packet approaches the double slit located at $x = \num{0.5}$. The interference pattern begins to emerge in the probability distribution $|u|^2$, while the real and imaginary parts of the wave function start to show oscillatory structure due to partial transmission through the slits.} + \label{fig:t_1_evolution} +\end{figure} + +\begin{figure}[ht] + \centering + \includegraphics[width=\columnwidth]{include/wavefunction_t_0.002s.pdf} + \caption{Wave function after passing the slits at $t = \num{0.002}\,\mathrm{s}$. Clear interference fringes are visible in the probability distribution $|u|^2$, indicating coherent superposition of the transmitted wave packets. The real and imaginary components exhibit alternating regions of positive and negative amplitude, reflecting the phase differences between the paths through the two slits.} + \label{fig:t_2_evolution} +\end{figure} + +\onecolumngrid +% \bibliographystyle{apalike} +\bibliographystyle{unsrt} +\bibliography{include/project5} + + +\end{document} \ No newline at end of file diff --git a/projects/project5/mainNotes.bib b/projects/project5/mainNotes.bib new file mode 100644 index 0000000..e69de29 diff --git a/src/project5/CMakeLists.txt b/src/project5/CMakeLists.txt new file mode 100644 index 0000000..a4a679f --- /dev/null +++ b/src/project5/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.16) +project(SchrodingerSim LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_BUILD_TYPE Release) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3") + +include_directories(${CMAKE_SOURCE_DIR}/include) + +# Gather sources +file(GLOB SRC_FILES ${CMAKE_SOURCE_DIR}/src/*.cpp) + +add_executable(main ${SRC_FILES} main.cpp) +add_executable(debug ${SRC_FILES} debug.cpp) + +# Find Armadillo and link it +find_package(Armadillo REQUIRED) +target_link_libraries(main PRIVATE armadillo) + diff --git a/src/project5/config.toml b/src/project5/config.toml new file mode 100644 index 0000000..d2cf68d --- /dev/null +++ b/src/project5/config.toml @@ -0,0 +1,24 @@ +[system] +h = 0.05 +delta_t = 2.5e-5 +T = 0.002 + +[initial_state] +x_c = 0.25 +y_c = 0.5 +sigma_x = 0.05 +# broader in y for this run +sigma_y = 0.10 +p_x = 200.0 +p_y = 0.0 + +[slit] +wall_thickness = 0.02 +wall_position = 0.5 +slit_aperture = 0.05 +slit_separation = 0.05 +num_slits = 2 +V_wall = 1.0e10 + +[output] +filename = "wavefunction_evolution.bin" diff --git a/src/project5/config/problem7_double_slit.toml b/src/project5/config/problem7_double_slit.toml new file mode 100644 index 0000000..2b8cde6 --- /dev/null +++ b/src/project5/config/problem7_double_slit.toml @@ -0,0 +1,24 @@ +[system] +h = 0.005 +delta_t = 2.5e-5 +T = 0.008 + +[initial_state] +x_c = 0.25 +y_c = 0.5 +sigma_x = 0.05 +# broader in y for this run +sigma_y = 0.10 +p_x = 200.0 +p_y = 0.0 + +[slit] +wall_thickness = 0.02 +wall_position = 0.5 +slit_aperture = 0.05 +slit_separation = 0.05 +num_slits = 2 +V_wall = 1.0e10 + +[output] +filename = "problem7_double_slit.bin" diff --git a/src/project5/config/problem7_no_slit.toml b/src/project5/config/problem7_no_slit.toml new file mode 100644 index 0000000..43e8b60 --- /dev/null +++ b/src/project5/config/problem7_no_slit.toml @@ -0,0 +1,24 @@ +[system] +h = 0.005 +delta_t = 2.5e-5 +T = 0.008 + +[initial_state] +x_c = 0.25 +y_c = 0.5 +sigma_x = 0.05 +sigma_y = 0.05 +p_x = 200.0 +p_y = 0.0 + +[slit] +# No barrier for this run +wall_thickness = 0.02 +wall_position = 0.5 +slit_aperture = 0.05 +slit_separation = 0.05 +num_slits = 0 +V_wall = 0.0 + +[output] +filename = "problem7_no_wall.bin" diff --git a/src/project5/config/problem8_double_slit.toml b/src/project5/config/problem8_double_slit.toml new file mode 100644 index 0000000..770db1a --- /dev/null +++ b/src/project5/config/problem8_double_slit.toml @@ -0,0 +1,23 @@ +[system] +h = 0.005 +delta_t = 2.5e-5 +T = 0.002 + +[initial_state] +x_c = 0.25 +y_c = 0.5 +sigma_x = 0.05 +sigma_y = 0.20 +p_x = 200.0 +p_y = 0.0 + +[slit] +wall_thickness = 0.02 +wall_position = 0.5 +slit_aperture = 0.05 +slit_separation = 0.05 +num_slits = 2 +V_wall = 1.0e10 + +[output] +filename = "problem8_double_slit.bin" diff --git a/src/project5/config/problem9_double_slit.toml b/src/project5/config/problem9_double_slit.toml new file mode 100644 index 0000000..de619e1 --- /dev/null +++ b/src/project5/config/problem9_double_slit.toml @@ -0,0 +1,23 @@ +[system] +h = 0.005 +delta_t = 2.5e-5 +T = 0.002 + +[initial_state] +x_c = 0.25 +y_c = 0.5 +sigma_x = 0.05 +sigma_y = 0.20 +p_x = 200.0 +p_y = 0.0 + +[slit] +wall_thickness = 0.02 +wall_position = 0.5 +slit_aperture = 0.05 +slit_separation = 0.05 +num_slits = 2 +V_wall = 1.0e10 + +[output] +filename = "problem9_double_slit.bin" diff --git a/src/project5/config/problem9_single_slit.toml b/src/project5/config/problem9_single_slit.toml new file mode 100644 index 0000000..07ac5f2 --- /dev/null +++ b/src/project5/config/problem9_single_slit.toml @@ -0,0 +1,24 @@ +[system] +h = 0.005 +delta_t = 2.5e-5 +T = 0.002 + +[initial_state] +x_c = 0.25 +y_c = 0.5 +sigma_x = 0.05 +sigma_y = 0.20 +p_x = 200.0 +p_y = 0.0 + +[slit] +wall_thickness = 0.02 +wall_position = 0.5 +slit_aperture = 0.05 +# For single-slit, slit_separation is irrelevant but kept for parser stability +slit_separation = 0.05 +num_slits = 1 +V_wall = 1.0e10 + +[output] +filename = "problem9_single_slit.bin" diff --git a/src/project5/config/problem9_triple_slit.toml b/src/project5/config/problem9_triple_slit.toml new file mode 100644 index 0000000..259c1b6 --- /dev/null +++ b/src/project5/config/problem9_triple_slit.toml @@ -0,0 +1,24 @@ +[system] +h = 0.005 +delta_t = 2.5e-5 +T = 0.002 + +[initial_state] +x_c = 0.25 +y_c = 0.5 +sigma_x = 0.05 +sigma_y = 0.20 +p_x = 200.0 +p_y = 0.0 + +[slit] +wall_thickness = 0.02 +wall_position = 0.5 +slit_aperture = 0.05 +# centre-to-centre spacing between adjacent slits (approx); adjust parser if you want inner-edge spacing +slit_separation = 0.05 +num_slits = 3 +V_wall = 1.0e10 + +[output] +filename = "problem9_triple_slit.bin" diff --git a/src/project5/debug.cpp b/src/project5/debug.cpp new file mode 100644 index 0000000..b52e731 --- /dev/null +++ b/src/project5/debug.cpp @@ -0,0 +1,7 @@ +#include "schroding.hpp" + +int main(){ + DoubleSlitBox box(0.005, 1e-5, 0.001, 0.25, 0.5, 0.05, 0.05, 0.0, 0.0); + box.add_slits(0.02, 0.5, 0.05, 0.1, 2, 1e6); + box.save_potential("potential_debug.txt"); +} \ No newline at end of file diff --git a/src/project5/generate_results.sh b/src/project5/generate_results.sh new file mode 100755 index 0000000..dcfbbe8 --- /dev/null +++ b/src/project5/generate_results.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +cmake --build ../../build --target main +EXECUTABLE=../../build/main +CONFIG_DIR=./config + +for CONFIG_FILE in $CONFIG_DIR/*.toml; do + echo "Running simulation with config: $CONFIG_FILE" + $EXECUTABLE $CONFIG_FILE +done \ No newline at end of file diff --git a/src/project5/include/schroding.hpp b/src/project5/include/schroding.hpp new file mode 100644 index 0000000..9204848 --- /dev/null +++ b/src/project5/include/schroding.hpp @@ -0,0 +1,82 @@ +#ifndef SCHRODING_HPP +#define SCHRODING_HPP +#define ARMA_USE_SUPERLU + +#if defined(SCHRODING_DEBUG) + #define SCHRODING_DEBUG_FREQ 1 +#else + #define SCHRODING_DEBUG_FREQ 100 +#endif + +#include +#include +#include +#include +#include + +class DoubleSlitBox { +public: + DoubleSlitBox(double h, double delta_t, double T, double x_c, double y_c, double sigma_x, double sigma_y, double p_x, double p_y); + void add_slits(double wall_thickness = 0.02, double wall_position = 0.5, double slit_aperture = 0.05, double slit_separation = 0.1, int num_slits = 2, double V_wall = 1e6); + void print_matrices() const; + void run_simulation(); + arma::cx_mat get_wavefunction_at_time(double time) const { + int time_index = static_cast(time / delta_t_); + return psi_time_evolution_.slice(time_index); + } + void save(const std::string& filename) const { + psi_time_evolution_.save(filename, arma::arma_ascii); + } + void save_potential(const std::string& filename) const { + V_.save(filename, arma::arma_ascii); + } +private: + double h_; // Spatial step + int M_; // Number of spatial points per dimension + double delta_t_; // Time step + double T_; // Total time + double x_c_; // Initial x center + double y_c_; // Initial y center + double sigma_x_; // Initial x width + double sigma_y_; // Initial y width + double p_x_; // Initial x momentum + double p_y_; // Initial y momentum + + std::complex r_; // Coefficient for matrices + + arma::cx_mat psi_; // Wavefunction + arma::mat V_; // Potential + arma::sp_cx_mat A_; // Matrix A + arma::sp_cx_mat B_; // Matrix B + + arma::cx_cube psi_time_evolution_; // To store wavefunction at each time step + + void initialize_wavefunction(); + void initialize_potential(); + + int get_vector_index(const int i, const int j) const { + // Maps 2D grid indices to 1D vector index, excluding boundary points + return i * (M_ - 2) + j; + } + + arma::sp_cx_mat construct_A_matrix(const std::complex r, const arma::cx_vec& a) const; + arma::sp_cx_mat construct_B_matrix(const std::complex r, const arma::cx_vec& b) const; + void add_diagonal(arma::sp_cx_mat& mat, const arma::cx_vec& diag_elements, const int i, const int j, const int N) const; + void add_diagonal(arma::sp_cx_mat& mat, const std::complex diag_element, const int i, const int j, const int N) const; + void add_offdiagonal(arma::sp_cx_mat& mat, const std::complex offdiag_element, const int i, const int j, const int N, const int offset) const; + void add_center_matrix(arma::sp_cx_mat& mat, const std::complex offdiag_element, const int i, const int j, const int N) const { + add_offdiagonal(mat, offdiag_element, i, j, N, 1); + add_offdiagonal(mat, offdiag_element, i, j, N, -1); + } + void construct_matrices(arma::sp_cx_mat& mat, const std::complex offdiag_element, const arma::cx_vec& diag_elements) const; + + void time_step(); + +}; + + + +void print_sp_matrix_structure(const arma::sp_cx_mat& A); + + +#endif // SCHRODING_HPP \ No newline at end of file diff --git a/src/project5/include/toml++/toml.hpp b/src/project5/include/toml++/toml.hpp new file mode 100644 index 0000000..c01a208 --- /dev/null +++ b/src/project5/include/toml++/toml.hpp @@ -0,0 +1,17888 @@ +//---------------------------------------------------------------------------------------------------------------------- +// +// toml++ v3.4.0 +// https://github.com/marzer/tomlplusplus +// SPDX-License-Identifier: MIT +// +//---------------------------------------------------------------------------------------------------------------------- +// +// - THIS FILE WAS ASSEMBLED FROM MULTIPLE HEADER FILES BY A SCRIPT - PLEASE DON'T EDIT IT DIRECTLY - +// +// If you wish to submit a contribution to toml++, hooray and thanks! Before you crack on, please be aware that this +// file was assembled from a number of smaller files by a python script, and code contributions should not be made +// against it directly. You should instead make your changes in the relevant source file(s). The file names of the files +// that contributed to this header can be found at the beginnings and ends of the corresponding sections of this file. +// +//---------------------------------------------------------------------------------------------------------------------- +// +// TOML Language Specifications: +// latest: https://github.com/toml-lang/toml/blob/master/README.md +// v1.0.0: https://toml.io/en/v1.0.0 +// v0.5.0: https://toml.io/en/v0.5.0 +// changelog: https://github.com/toml-lang/toml/blob/master/CHANGELOG.md +// +//---------------------------------------------------------------------------------------------------------------------- +// +// MIT License +// +// Copyright (c) Mark Gillard +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +// Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +//---------------------------------------------------------------------------------------------------------------------- +#ifndef TOMLPLUSPLUS_HPP +#define TOMLPLUSPLUS_HPP + +#define INCLUDE_TOMLPLUSPLUS_H // old guard name used pre-v3 +#define TOMLPLUSPLUS_H // guard name used in the legacy toml.h + +//******** impl/preprocessor.hpp ************************************************************************************* + +#ifndef __cplusplus +#error toml++ is a C++ library. +#endif + +#ifndef TOML_CPP +#ifdef _MSVC_LANG +#if _MSVC_LANG > __cplusplus +#define TOML_CPP _MSVC_LANG +#endif +#endif +#ifndef TOML_CPP +#define TOML_CPP __cplusplus +#endif +#if TOML_CPP >= 202900L +#undef TOML_CPP +#define TOML_CPP 29 +#elif TOML_CPP >= 202600L +#undef TOML_CPP +#define TOML_CPP 26 +#elif TOML_CPP >= 202302L +#undef TOML_CPP +#define TOML_CPP 23 +#elif TOML_CPP >= 202002L +#undef TOML_CPP +#define TOML_CPP 20 +#elif TOML_CPP >= 201703L +#undef TOML_CPP +#define TOML_CPP 17 +#elif TOML_CPP >= 201402L +#undef TOML_CPP +#define TOML_CPP 14 +#elif TOML_CPP >= 201103L +#undef TOML_CPP +#define TOML_CPP 11 +#else +#undef TOML_CPP +#define TOML_CPP 0 +#endif +#endif + +#if !TOML_CPP +#error toml++ requires C++17 or higher. For a pre-C++11 TOML library see https://github.com/ToruNiina/Boost.toml +#elif TOML_CPP < 17 +#error toml++ requires C++17 or higher. For a C++11 TOML library see https://github.com/ToruNiina/toml11 +#endif + +#ifndef TOML_MAKE_VERSION +#define TOML_MAKE_VERSION(major, minor, patch) (((major)*10000) + ((minor)*100) + ((patch))) +#endif + +#ifndef TOML_INTELLISENSE +#ifdef __INTELLISENSE__ +#define TOML_INTELLISENSE 1 +#else +#define TOML_INTELLISENSE 0 +#endif +#endif + +#ifndef TOML_DOXYGEN +#if defined(DOXYGEN) || defined(__DOXYGEN) || defined(__DOXYGEN__) || defined(__doxygen__) || defined(__POXY__) \ + || defined(__poxy__) +#define TOML_DOXYGEN 1 +#else +#define TOML_DOXYGEN 0 +#endif +#endif + +#ifndef TOML_CLANG +#ifdef __clang__ +#define TOML_CLANG __clang_major__ +#else +#define TOML_CLANG 0 +#endif + +// special handling for apple clang; see: +// - https://github.com/marzer/tomlplusplus/issues/189 +// - https://en.wikipedia.org/wiki/Xcode +// - +// https://stackoverflow.com/questions/19387043/how-can-i-reliably-detect-the-version-of-clang-at-preprocessing-time +#if TOML_CLANG && defined(__apple_build_version__) +#undef TOML_CLANG +#define TOML_CLANG_VERSION TOML_MAKE_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) +#if TOML_CLANG_VERSION >= TOML_MAKE_VERSION(15, 0, 0) +#define TOML_CLANG 16 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(14, 3, 0) +#define TOML_CLANG 15 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(14, 0, 0) +#define TOML_CLANG 14 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(13, 1, 6) +#define TOML_CLANG 13 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(13, 0, 0) +#define TOML_CLANG 12 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(12, 0, 5) +#define TOML_CLANG 11 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(12, 0, 0) +#define TOML_CLANG 10 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(11, 0, 3) +#define TOML_CLANG 9 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(11, 0, 0) +#define TOML_CLANG 8 +#elif TOML_CLANG_VERSION >= TOML_MAKE_VERSION(10, 0, 1) +#define TOML_CLANG 7 +#else +#define TOML_CLANG 6 // not strictly correct but doesn't matter below this +#endif +#undef TOML_CLANG_VERSION +#endif +#endif + +#ifndef TOML_ICC +#ifdef __INTEL_COMPILER +#define TOML_ICC __INTEL_COMPILER +#ifdef __ICL +#define TOML_ICC_CL TOML_ICC +#else +#define TOML_ICC_CL 0 +#endif +#else +#define TOML_ICC 0 +#define TOML_ICC_CL 0 +#endif +#endif + +#ifndef TOML_MSVC_LIKE +#ifdef _MSC_VER +#define TOML_MSVC_LIKE _MSC_VER +#else +#define TOML_MSVC_LIKE 0 +#endif +#endif + +#ifndef TOML_MSVC +#if TOML_MSVC_LIKE && !TOML_CLANG && !TOML_ICC +#define TOML_MSVC TOML_MSVC_LIKE +#else +#define TOML_MSVC 0 +#endif +#endif + +#ifndef TOML_GCC_LIKE +#ifdef __GNUC__ +#define TOML_GCC_LIKE __GNUC__ +#else +#define TOML_GCC_LIKE 0 +#endif +#endif + +#ifndef TOML_GCC +#if TOML_GCC_LIKE && !TOML_CLANG && !TOML_ICC +#define TOML_GCC TOML_GCC_LIKE +#else +#define TOML_GCC 0 +#endif +#endif + +#ifndef TOML_CUDA +#if defined(__CUDACC__) || defined(__CUDA_ARCH__) || defined(__CUDA_LIBDEVICE__) +#define TOML_CUDA 1 +#else +#define TOML_CUDA 0 +#endif +#endif + +#ifndef TOML_NVCC +#ifdef __NVCOMPILER_MAJOR__ +#define TOML_NVCC __NVCOMPILER_MAJOR__ +#else +#define TOML_NVCC 0 +#endif +#endif + +#ifndef TOML_ARCH_ITANIUM +#if defined(__ia64__) || defined(__ia64) || defined(_IA64) || defined(__IA64__) || defined(_M_IA64) +#define TOML_ARCH_ITANIUM 1 +#define TOML_ARCH_BITNESS 64 +#else +#define TOML_ARCH_ITANIUM 0 +#endif +#endif + +#ifndef TOML_ARCH_AMD64 +#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) +#define TOML_ARCH_AMD64 1 +#define TOML_ARCH_BITNESS 64 +#else +#define TOML_ARCH_AMD64 0 +#endif +#endif + +#ifndef TOML_ARCH_X86 +#if defined(__i386__) || defined(_M_IX86) +#define TOML_ARCH_X86 1 +#define TOML_ARCH_BITNESS 32 +#else +#define TOML_ARCH_X86 0 +#endif +#endif + +#ifndef TOML_ARCH_ARM +#if defined(__aarch64__) || defined(__ARM_ARCH_ISA_A64) || defined(_M_ARM64) || defined(__ARM_64BIT_STATE) \ + || defined(_M_ARM64EC) +#define TOML_ARCH_ARM32 0 +#define TOML_ARCH_ARM64 1 +#define TOML_ARCH_ARM 1 +#define TOML_ARCH_BITNESS 64 +#elif defined(__arm__) || defined(_M_ARM) || defined(__ARM_32BIT_STATE) +#define TOML_ARCH_ARM32 1 +#define TOML_ARCH_ARM64 0 +#define TOML_ARCH_ARM 1 +#define TOML_ARCH_BITNESS 32 +#else +#define TOML_ARCH_ARM32 0 +#define TOML_ARCH_ARM64 0 +#define TOML_ARCH_ARM 0 +#endif +#endif + +#ifndef TOML_ARCH_BITNESS +#define TOML_ARCH_BITNESS 0 +#endif + +#ifndef TOML_ARCH_X64 +#if TOML_ARCH_BITNESS == 64 +#define TOML_ARCH_X64 1 +#else +#define TOML_ARCH_X64 0 +#endif +#endif + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || defined(__CYGWIN__) +#define TOML_WINDOWS 1 +#else +#define TOML_WINDOWS 0 +#endif + +#ifdef __unix__ +#define TOML_UNIX 1 +#else +#define TOML_UNIX 0 +#endif + +#ifdef __linux__ +#define TOML_LINUX 1 +#else +#define TOML_LINUX 0 +#endif + +// TOML_HAS_INCLUDE +#ifndef TOML_HAS_INCLUDE +#ifdef __has_include +#define TOML_HAS_INCLUDE(header) __has_include(header) +#else +#define TOML_HAS_INCLUDE(header) 0 +#endif +#endif + +// TOML_HAS_BUILTIN +#ifndef TOML_HAS_BUILTIN +#ifdef __has_builtin +#define TOML_HAS_BUILTIN(name) __has_builtin(name) +#else +#define TOML_HAS_BUILTIN(name) 0 +#endif +#endif + +// TOML_HAS_FEATURE +#ifndef TOML_HAS_FEATURE +#ifdef __has_feature +#define TOML_HAS_FEATURE(name) __has_feature(name) +#else +#define TOML_HAS_FEATURE(name) 0 +#endif +#endif + +// TOML_HAS_ATTR +#ifndef TOML_HAS_ATTR +#ifdef __has_attribute +#define TOML_HAS_ATTR(attr) __has_attribute(attr) +#else +#define TOML_HAS_ATTR(attr) 0 +#endif +#endif + +// TOML_HAS_CPP_ATTR +#ifndef TOML_HAS_CPP_ATTR +#ifdef __has_cpp_attribute +#define TOML_HAS_CPP_ATTR(attr) __has_cpp_attribute(attr) +#else +#define TOML_HAS_CPP_ATTR(attr) 0 +#endif +#endif + +// TOML_ATTR (gnu attributes) +#ifndef TOML_ATTR +#if TOML_CLANG || TOML_GCC_LIKE +#define TOML_ATTR(...) __attribute__((__VA_ARGS__)) +#else +#define TOML_ATTR(...) +#endif +#endif + +// TOML_DECLSPEC (msvc attributes) +#ifndef TOML_DECLSPEC +#if TOML_MSVC_LIKE +#define TOML_DECLSPEC(...) __declspec(__VA_ARGS__) +#else +#define TOML_DECLSPEC(...) +#endif +#endif + +// TOML_COMPILER_HAS_EXCEPTIONS +#ifndef TOML_COMPILER_HAS_EXCEPTIONS +#if defined(__EXCEPTIONS) || defined(_CPPUNWIND) || defined(__cpp_exceptions) +#define TOML_COMPILER_HAS_EXCEPTIONS 1 +#else +#define TOML_COMPILER_HAS_EXCEPTIONS 0 +#endif +#endif + +// TOML_COMPILER_HAS_RTTI +#ifndef TOML_COMPILER_HAS_RTTI +#if defined(_CPPRTTI) || defined(__GXX_RTTI) || TOML_HAS_FEATURE(cxx_rtti) +#define TOML_COMPILER_HAS_RTTI 1 +#else +#define TOML_COMPILER_HAS_RTTI 0 +#endif +#endif + +// TOML_CONCAT +#define TOML_CONCAT_1(x, y) x##y +#define TOML_CONCAT(x, y) TOML_CONCAT_1(x, y) + +// TOML_MAKE_STRING +#define TOML_MAKE_STRING_1(s) #s +#define TOML_MAKE_STRING(s) TOML_MAKE_STRING_1(s) + +// TOML_PRAGMA_XXXX (compiler-specific pragmas) +#if TOML_CLANG +#define TOML_PRAGMA_CLANG(decl) _Pragma(TOML_MAKE_STRING(clang decl)) +#else +#define TOML_PRAGMA_CLANG(decl) +#endif +#if TOML_CLANG >= 8 +#define TOML_PRAGMA_CLANG_GE_8(decl) TOML_PRAGMA_CLANG(decl) +#else +#define TOML_PRAGMA_CLANG_GE_8(decl) +#endif +#if TOML_CLANG >= 9 +#define TOML_PRAGMA_CLANG_GE_9(decl) TOML_PRAGMA_CLANG(decl) +#else +#define TOML_PRAGMA_CLANG_GE_9(decl) +#endif +#if TOML_CLANG >= 10 +#define TOML_PRAGMA_CLANG_GE_10(decl) TOML_PRAGMA_CLANG(decl) +#else +#define TOML_PRAGMA_CLANG_GE_10(decl) +#endif +#if TOML_CLANG >= 11 +#define TOML_PRAGMA_CLANG_GE_11(decl) TOML_PRAGMA_CLANG(decl) +#else +#define TOML_PRAGMA_CLANG_GE_11(decl) +#endif +#if TOML_GCC +#define TOML_PRAGMA_GCC(decl) _Pragma(TOML_MAKE_STRING(GCC decl)) +#else +#define TOML_PRAGMA_GCC(decl) +#endif +#if TOML_MSVC +#define TOML_PRAGMA_MSVC(...) __pragma(__VA_ARGS__) +#else +#define TOML_PRAGMA_MSVC(...) +#endif +#if TOML_ICC +#define TOML_PRAGMA_ICC(...) __pragma(__VA_ARGS__) +#else +#define TOML_PRAGMA_ICC(...) +#endif + +// TOML_ALWAYS_INLINE +#ifndef TOML_ALWAYS_INLINE +#ifdef _MSC_VER +#define TOML_ALWAYS_INLINE __forceinline +#elif TOML_GCC || TOML_CLANG || TOML_HAS_ATTR(__always_inline__) +#define TOML_ALWAYS_INLINE \ + TOML_ATTR(__always_inline__) \ + inline +#else +#define TOML_ALWAYS_INLINE inline +#endif +#endif + +// TOML_NEVER_INLINE +#ifndef TOML_NEVER_INLINE +#ifdef _MSC_VER +#define TOML_NEVER_INLINE TOML_DECLSPEC(noinline) +#elif TOML_CUDA // https://gitlab.gnome.org/GNOME/glib/-/issues/2555 +#define TOML_NEVER_INLINE TOML_ATTR(noinline) +#else +#if TOML_GCC || TOML_CLANG || TOML_HAS_ATTR(__noinline__) +#define TOML_NEVER_INLINE TOML_ATTR(__noinline__) +#endif +#endif +#ifndef TOML_NEVER_INLINE +#define TOML_NEVER_INLINE +#endif +#endif + +// MSVC attributes +#ifndef TOML_ABSTRACT_INTERFACE +#define TOML_ABSTRACT_INTERFACE TOML_DECLSPEC(novtable) +#endif +#ifndef TOML_EMPTY_BASES +#define TOML_EMPTY_BASES TOML_DECLSPEC(empty_bases) +#endif + +// TOML_TRIVIAL_ABI +#ifndef TOML_TRIVIAL_ABI +#if TOML_CLANG || TOML_HAS_ATTR(__trivial_abi__) +#define TOML_TRIVIAL_ABI TOML_ATTR(__trivial_abi__) +#else +#define TOML_TRIVIAL_ABI +#endif +#endif + +// TOML_NODISCARD +#ifndef TOML_NODISCARD +#if TOML_CPP >= 17 && TOML_HAS_CPP_ATTR(nodiscard) >= 201603 +#define TOML_NODISCARD [[nodiscard]] +#elif TOML_CLANG || TOML_GCC || TOML_HAS_ATTR(__warn_unused_result__) +#define TOML_NODISCARD TOML_ATTR(__warn_unused_result__) +#else +#define TOML_NODISCARD +#endif +#endif + +// TOML_NODISCARD_CTOR +#ifndef TOML_NODISCARD_CTOR +#if TOML_CPP >= 17 && TOML_HAS_CPP_ATTR(nodiscard) >= 201907 +#define TOML_NODISCARD_CTOR [[nodiscard]] +#else +#define TOML_NODISCARD_CTOR +#endif +#endif + +// pure + const +#ifndef TOML_PURE +#ifdef NDEBUG +#define TOML_PURE \ + TOML_DECLSPEC(noalias) \ + TOML_ATTR(pure) +#else +#define TOML_PURE +#endif +#endif +#ifndef TOML_CONST +#ifdef NDEBUG +#define TOML_CONST \ + TOML_DECLSPEC(noalias) \ + TOML_ATTR(const) +#else +#define TOML_CONST +#endif +#endif +#ifndef TOML_INLINE_GETTER +#define TOML_INLINE_GETTER \ + TOML_NODISCARD \ + TOML_ALWAYS_INLINE +#endif +#ifndef TOML_PURE_GETTER +#define TOML_PURE_GETTER \ + TOML_NODISCARD \ + TOML_PURE +#endif +#ifndef TOML_PURE_INLINE_GETTER +#define TOML_PURE_INLINE_GETTER \ + TOML_NODISCARD \ + TOML_ALWAYS_INLINE \ + TOML_PURE +#endif +#ifndef TOML_CONST_GETTER +#define TOML_CONST_GETTER \ + TOML_NODISCARD \ + TOML_CONST +#endif +#ifndef TOML_CONST_INLINE_GETTER +#define TOML_CONST_INLINE_GETTER \ + TOML_NODISCARD \ + TOML_ALWAYS_INLINE \ + TOML_CONST +#endif + +// TOML_ASSUME +#ifndef TOML_ASSUME +#ifdef _MSC_VER +#define TOML_ASSUME(expr) __assume(expr) +#elif TOML_ICC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_assume) +#define TOML_ASSUME(expr) __builtin_assume(expr) +#elif TOML_HAS_CPP_ATTR(assume) >= 202207 +#define TOML_ASSUME(expr) [[assume(expr)]] +#elif TOML_HAS_ATTR(__assume__) +#define TOML_ASSUME(expr) __attribute__((__assume__(expr))) +#else +#define TOML_ASSUME(expr) static_cast(0) +#endif +#endif + +// TOML_UNREACHABLE +#ifndef TOML_UNREACHABLE +#ifdef _MSC_VER +#define TOML_UNREACHABLE __assume(0) +#elif TOML_ICC || TOML_CLANG || TOML_GCC || TOML_HAS_BUILTIN(__builtin_unreachable) +#define TOML_UNREACHABLE __builtin_unreachable() +#else +#define TOML_UNREACHABLE static_cast(0) +#endif +#endif + +// TOML_LIKELY +#if TOML_CPP >= 20 && TOML_HAS_CPP_ATTR(likely) >= 201803 +#define TOML_LIKELY(...) (__VA_ARGS__) [[likely]] +#define TOML_LIKELY_CASE [[likely]] +#elif TOML_GCC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_expect) +#define TOML_LIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 1)) +#else +#define TOML_LIKELY(...) (__VA_ARGS__) +#endif +#ifndef TOML_LIKELY_CASE +#define TOML_LIKELY_CASE +#endif + +// TOML_UNLIKELY +#if TOML_CPP >= 20 && TOML_HAS_CPP_ATTR(unlikely) >= 201803 +#define TOML_UNLIKELY(...) (__VA_ARGS__) [[unlikely]] +#define TOML_UNLIKELY_CASE [[unlikely]] +#elif TOML_GCC || TOML_CLANG || TOML_HAS_BUILTIN(__builtin_expect) +#define TOML_UNLIKELY(...) (__builtin_expect(!!(__VA_ARGS__), 0)) +#else +#define TOML_UNLIKELY(...) (__VA_ARGS__) +#endif +#ifndef TOML_UNLIKELY_CASE +#define TOML_UNLIKELY_CASE +#endif + +// TOML_FLAGS_ENUM +#if TOML_CLANG || TOML_HAS_ATTR(flag_enum) +#define TOML_FLAGS_ENUM __attribute__((flag_enum)) +#else +#define TOML_FLAGS_ENUM +#endif + +// TOML_OPEN_ENUM + TOML_CLOSED_ENUM +#if TOML_CLANG || TOML_HAS_ATTR(enum_extensibility) +#define TOML_OPEN_ENUM __attribute__((enum_extensibility(open))) +#define TOML_CLOSED_ENUM __attribute__((enum_extensibility(closed))) +#else +#define TOML_OPEN_ENUM +#define TOML_CLOSED_ENUM +#endif + +// TOML_OPEN_FLAGS_ENUM + TOML_CLOSED_FLAGS_ENUM +#define TOML_OPEN_FLAGS_ENUM TOML_OPEN_ENUM TOML_FLAGS_ENUM +#define TOML_CLOSED_FLAGS_ENUM TOML_CLOSED_ENUM TOML_FLAGS_ENUM + +// TOML_MAKE_FLAGS +#define TOML_MAKE_FLAGS_2(T, op, linkage) \ + TOML_CONST_INLINE_GETTER \ + linkage constexpr T operator op(T lhs, T rhs) noexcept \ + { \ + using under = std::underlying_type_t; \ + return static_cast(static_cast(lhs) op static_cast(rhs)); \ + } \ + \ + linkage constexpr T& operator TOML_CONCAT(op, =)(T & lhs, T rhs) noexcept \ + { \ + return lhs = (lhs op rhs); \ + } \ + \ + static_assert(true) +#define TOML_MAKE_FLAGS_1(T, linkage) \ + static_assert(std::is_enum_v); \ + \ + TOML_MAKE_FLAGS_2(T, &, linkage); \ + TOML_MAKE_FLAGS_2(T, |, linkage); \ + TOML_MAKE_FLAGS_2(T, ^, linkage); \ + \ + TOML_CONST_INLINE_GETTER \ + linkage constexpr T operator~(T val) noexcept \ + { \ + using under = std::underlying_type_t; \ + return static_cast(~static_cast(val)); \ + } \ + \ + TOML_CONST_INLINE_GETTER \ + linkage constexpr bool operator!(T val) noexcept \ + { \ + using under = std::underlying_type_t; \ + return !static_cast(val); \ + } \ + \ + static_assert(true) +#define TOML_MAKE_FLAGS(T) TOML_MAKE_FLAGS_1(T, ) + +#define TOML_UNUSED(...) static_cast(__VA_ARGS__) + +#define TOML_DELETE_DEFAULTS(T) \ + T(const T&) = delete; \ + T(T&&) = delete; \ + T& operator=(const T&) = delete; \ + T& operator=(T&&) = delete + +#define TOML_ASYMMETRICAL_EQUALITY_OPS(LHS, RHS, ...) \ + __VA_ARGS__ TOML_NODISCARD \ + friend bool operator==(RHS rhs, LHS lhs) noexcept \ + { \ + return lhs == rhs; \ + } \ + __VA_ARGS__ TOML_NODISCARD \ + friend bool operator!=(LHS lhs, RHS rhs) noexcept \ + { \ + return !(lhs == rhs); \ + } \ + __VA_ARGS__ TOML_NODISCARD \ + friend bool operator!=(RHS rhs, LHS lhs) noexcept \ + { \ + return !(lhs == rhs); \ + } \ + static_assert(true) + +#define TOML_EVAL_BOOL_1(T, F) T +#define TOML_EVAL_BOOL_0(T, F) F + +#if !defined(__POXY__) && !defined(POXY_IMPLEMENTATION_DETAIL) +#define POXY_IMPLEMENTATION_DETAIL(...) __VA_ARGS__ +#endif + +// COMPILER-SPECIFIC WARNING MANAGEMENT + +#if TOML_CLANG + +#define TOML_PUSH_WARNINGS \ + TOML_PRAGMA_CLANG(diagnostic push) \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wunknown-warning-option") \ + static_assert(true) + +#define TOML_DISABLE_SWITCH_WARNINGS \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wswitch") \ + static_assert(true) + +#define TOML_DISABLE_ARITHMETIC_WARNINGS \ + TOML_PRAGMA_CLANG_GE_10(diagnostic ignored "-Wimplicit-int-float-conversion") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wfloat-equal") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wdouble-promotion") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wchar-subscripts") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wshift-sign-overflow") \ + static_assert(true) + +#define TOML_DISABLE_SPAM_WARNINGS \ + TOML_PRAGMA_CLANG_GE_8(diagnostic ignored "-Wdefaulted-function-deleted") \ + TOML_PRAGMA_CLANG_GE_9(diagnostic ignored "-Wctad-maybe-unsupported") \ + TOML_PRAGMA_CLANG_GE_10(diagnostic ignored "-Wzero-as-null-pointer-constant") \ + TOML_PRAGMA_CLANG_GE_11(diagnostic ignored "-Wsuggest-destructor-override") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wweak-vtables") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wweak-template-vtables") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wdouble-promotion") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wchar-subscripts") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wmissing-field-initializers") \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Wpadded") \ + static_assert(true) + +#define TOML_POP_WARNINGS \ + TOML_PRAGMA_CLANG(diagnostic pop) \ + static_assert(true) + +#define TOML_DISABLE_WARNINGS \ + TOML_PRAGMA_CLANG(diagnostic push) \ + TOML_PRAGMA_CLANG(diagnostic ignored "-Weverything") \ + static_assert(true, "") + +#define TOML_ENABLE_WARNINGS \ + TOML_PRAGMA_CLANG(diagnostic pop) \ + static_assert(true) + +#define TOML_SIMPLE_STATIC_ASSERT_MESSAGES 1 + +#elif TOML_MSVC + +#define TOML_PUSH_WARNINGS \ + __pragma(warning(push)) \ + static_assert(true) + +#if TOML_HAS_INCLUDE() +#pragma warning(push, 0) +#include +#pragma warning(pop) +#define TOML_DISABLE_CODE_ANALYSIS_WARNINGS \ + __pragma(warning(disable : ALL_CODE_ANALYSIS_WARNINGS)) \ + static_assert(true) +#else +#define TOML_DISABLE_CODE_ANALYSIS_WARNINGS static_assert(true) +#endif + +#define TOML_DISABLE_SWITCH_WARNINGS \ + __pragma(warning(disable : 4061)) \ + __pragma(warning(disable : 4062)) \ + __pragma(warning(disable : 4063)) \ + __pragma(warning(disable : 5262)) /* switch-case implicit fallthrough (false-positive) */ \ + __pragma(warning(disable : 26819)) /* cg: unannotated fallthrough */ \ + static_assert(true) + +#define TOML_DISABLE_SPAM_WARNINGS \ + __pragma(warning(disable : 4127)) /* conditional expr is constant */ \ + __pragma(warning(disable : 4324)) /* structure was padded due to alignment specifier */ \ + __pragma(warning(disable : 4348)) \ + __pragma(warning(disable : 4464)) /* relative include path contains '..' */ \ + __pragma(warning(disable : 4505)) /* unreferenced local function removed */ \ + __pragma(warning(disable : 4514)) /* unreferenced inline function has been removed */ \ + __pragma(warning(disable : 4582)) /* constructor is not implicitly called */ \ + __pragma(warning(disable : 4619)) /* there is no warning number 'XXXX' */ \ + __pragma(warning(disable : 4623)) /* default constructor was implicitly defined as deleted */ \ + __pragma(warning(disable : 4625)) /* copy constructor was implicitly defined as deleted */ \ + __pragma(warning(disable : 4626)) /* assignment operator was implicitly defined as deleted */ \ + __pragma(warning(disable : 4710)) /* function not inlined */ \ + __pragma(warning(disable : 4711)) /* function selected for automatic expansion */ \ + __pragma(warning(disable : 4820)) /* N bytes padding added */ \ + __pragma(warning(disable : 4946)) /* reinterpret_cast used between related classes */ \ + __pragma(warning(disable : 5026)) /* move constructor was implicitly defined as deleted */ \ + __pragma(warning(disable : 5027)) /* move assignment operator was implicitly defined as deleted */ \ + __pragma(warning(disable : 5039)) /* potentially throwing function passed to 'extern "C"' function */ \ + __pragma(warning(disable : 5045)) /* Compiler will insert Spectre mitigation */ \ + __pragma(warning(disable : 5264)) /* const variable is not used (false-positive) */ \ + __pragma(warning(disable : 26451)) \ + __pragma(warning(disable : 26490)) \ + __pragma(warning(disable : 26495)) \ + __pragma(warning(disable : 26812)) \ + __pragma(warning(disable : 26819)) \ + static_assert(true) + +#define TOML_DISABLE_ARITHMETIC_WARNINGS \ + __pragma(warning(disable : 4365)) /* argument signed/unsigned mismatch */ \ + __pragma(warning(disable : 4738)) /* storing 32-bit float result in memory */ \ + __pragma(warning(disable : 5219)) /* implicit conversion from integral to float */ \ + static_assert(true) + +#define TOML_POP_WARNINGS \ + __pragma(warning(pop)) \ + static_assert(true) + +#define TOML_DISABLE_WARNINGS \ + __pragma(warning(push, 0)) \ + __pragma(warning(disable : 4348)) \ + __pragma(warning(disable : 4668)) \ + __pragma(warning(disable : 5105)) \ + __pragma(warning(disable : 5264)) \ + TOML_DISABLE_CODE_ANALYSIS_WARNINGS; \ + TOML_DISABLE_SWITCH_WARNINGS; \ + TOML_DISABLE_SPAM_WARNINGS; \ + TOML_DISABLE_ARITHMETIC_WARNINGS; \ + static_assert(true) + +#define TOML_ENABLE_WARNINGS TOML_POP_WARNINGS + +#elif TOML_ICC + +#define TOML_PUSH_WARNINGS \ + __pragma(warning(push)) \ + static_assert(true) + +#define TOML_DISABLE_SPAM_WARNINGS \ + __pragma(warning(disable : 82)) /* storage class is not first */ \ + __pragma(warning(disable : 111)) /* statement unreachable (false-positive) */ \ + __pragma(warning(disable : 869)) /* unreferenced parameter */ \ + __pragma(warning(disable : 1011)) /* missing return (false-positive) */ \ + __pragma(warning(disable : 2261)) /* assume expr side-effects discarded */ \ + static_assert(true) + +#define TOML_POP_WARNINGS \ + __pragma(warning(pop)) \ + static_assert(true) + +#define TOML_DISABLE_WARNINGS \ + __pragma(warning(push, 0)) \ + TOML_DISABLE_SPAM_WARNINGS + +#define TOML_ENABLE_WARNINGS \ + __pragma(warning(pop)) \ + static_assert(true) + +#elif TOML_GCC + +#define TOML_PUSH_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic push) \ + static_assert(true) + +#define TOML_DISABLE_SWITCH_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch-enum") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wswitch-default") \ + static_assert(true) + +#define TOML_DISABLE_ARITHMETIC_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wfloat-equal") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wsign-conversion") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wchar-subscripts") \ + static_assert(true) + +#define TOML_DISABLE_SUGGEST_ATTR_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wsuggest-attribute=const") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wsuggest-attribute=pure") \ + static_assert(true) + +#define TOML_DISABLE_SPAM_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wpadded") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wcast-align") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wcomment") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wtype-limits") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wuseless-cast") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wchar-subscripts") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wsubobject-linkage") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wmissing-field-initializers") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wmaybe-uninitialized") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wnoexcept") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wnull-dereference") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wduplicated-branches") \ + static_assert(true) + +#define TOML_POP_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic pop) \ + static_assert(true) + +#define TOML_DISABLE_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic push) \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wall") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wextra") \ + TOML_PRAGMA_GCC(diagnostic ignored "-Wpedantic") \ + TOML_DISABLE_SWITCH_WARNINGS; \ + TOML_DISABLE_ARITHMETIC_WARNINGS; \ + TOML_DISABLE_SUGGEST_ATTR_WARNINGS; \ + TOML_DISABLE_SPAM_WARNINGS; \ + static_assert(true) + +#define TOML_ENABLE_WARNINGS \ + TOML_PRAGMA_GCC(diagnostic pop) \ + static_assert(true) + +#endif + +#ifndef TOML_PUSH_WARNINGS +#define TOML_PUSH_WARNINGS static_assert(true) +#endif +#ifndef TOML_DISABLE_CODE_ANALYSIS_WARNINGS +#define TOML_DISABLE_CODE_ANALYSIS_WARNINGS static_assert(true) +#endif +#ifndef TOML_DISABLE_SWITCH_WARNINGS +#define TOML_DISABLE_SWITCH_WARNINGS static_assert(true) +#endif +#ifndef TOML_DISABLE_SUGGEST_ATTR_WARNINGS +#define TOML_DISABLE_SUGGEST_ATTR_WARNINGS static_assert(true) +#endif +#ifndef TOML_DISABLE_SPAM_WARNINGS +#define TOML_DISABLE_SPAM_WARNINGS static_assert(true) +#endif +#ifndef TOML_DISABLE_ARITHMETIC_WARNINGS +#define TOML_DISABLE_ARITHMETIC_WARNINGS static_assert(true) +#endif +#ifndef TOML_POP_WARNINGS +#define TOML_POP_WARNINGS static_assert(true) +#endif +#ifndef TOML_DISABLE_WARNINGS +#define TOML_DISABLE_WARNINGS static_assert(true) +#endif +#ifndef TOML_ENABLE_WARNINGS +#define TOML_ENABLE_WARNINGS static_assert(true) +#endif +#ifndef TOML_SIMPLE_STATIC_ASSERT_MESSAGES +#define TOML_SIMPLE_STATIC_ASSERT_MESSAGES 0 +#endif + +#ifdef TOML_CONFIG_HEADER +#include TOML_CONFIG_HEADER +#endif + +// is the library being built as a shared lib/dll using meson and friends? +#ifndef TOML_SHARED_LIB +#define TOML_SHARED_LIB 0 +#endif + +// header-only mode +#if !defined(TOML_HEADER_ONLY) && defined(TOML_ALL_INLINE) // was TOML_ALL_INLINE pre-2.0 +#define TOML_HEADER_ONLY TOML_ALL_INLINE +#endif +#if !defined(TOML_HEADER_ONLY) || (defined(TOML_HEADER_ONLY) && TOML_HEADER_ONLY) || TOML_INTELLISENSE +#undef TOML_HEADER_ONLY +#define TOML_HEADER_ONLY 1 +#endif +#if TOML_DOXYGEN || TOML_SHARED_LIB +#undef TOML_HEADER_ONLY +#define TOML_HEADER_ONLY 0 +#endif + +// internal implementation switch +#if defined(TOML_IMPLEMENTATION) || TOML_HEADER_ONLY +#undef TOML_IMPLEMENTATION +#define TOML_IMPLEMENTATION 1 +#else +#define TOML_IMPLEMENTATION 0 +#endif + +// dll/shared lib function exports (legacy - TOML_API was the old name for this setting) +#if !defined(TOML_EXPORTED_MEMBER_FUNCTION) && !defined(TOML_EXPORTED_STATIC_FUNCTION) \ + && !defined(TOML_EXPORTED_FREE_FUNCTION) && !defined(TOML_EXPORTED_CLASS) && defined(TOML_API) +#define TOML_EXPORTED_MEMBER_FUNCTION TOML_API +#define TOML_EXPORTED_STATIC_FUNCTION TOML_API +#define TOML_EXPORTED_FREE_FUNCTION TOML_API +#endif + +// dll/shared lib exports +#if TOML_SHARED_LIB +#undef TOML_API +#undef TOML_EXPORTED_CLASS +#undef TOML_EXPORTED_MEMBER_FUNCTION +#undef TOML_EXPORTED_STATIC_FUNCTION +#undef TOML_EXPORTED_FREE_FUNCTION +#if TOML_WINDOWS +#if TOML_IMPLEMENTATION +#define TOML_EXPORTED_CLASS __declspec(dllexport) +#define TOML_EXPORTED_FREE_FUNCTION __declspec(dllexport) +#else +#define TOML_EXPORTED_CLASS __declspec(dllimport) +#define TOML_EXPORTED_FREE_FUNCTION __declspec(dllimport) +#endif +#ifndef TOML_CALLCONV +#define TOML_CALLCONV __cdecl +#endif +#elif defined(__GNUC__) && __GNUC__ >= 4 +#define TOML_EXPORTED_CLASS __attribute__((visibility("default"))) +#define TOML_EXPORTED_MEMBER_FUNCTION __attribute__((visibility("default"))) +#define TOML_EXPORTED_STATIC_FUNCTION __attribute__((visibility("default"))) +#define TOML_EXPORTED_FREE_FUNCTION __attribute__((visibility("default"))) +#endif +#endif +#ifndef TOML_EXPORTED_CLASS +#define TOML_EXPORTED_CLASS +#endif +#ifndef TOML_EXPORTED_MEMBER_FUNCTION +#define TOML_EXPORTED_MEMBER_FUNCTION +#endif +#ifndef TOML_EXPORTED_STATIC_FUNCTION +#define TOML_EXPORTED_STATIC_FUNCTION +#endif +#ifndef TOML_EXPORTED_FREE_FUNCTION +#define TOML_EXPORTED_FREE_FUNCTION +#endif + +// experimental language features +#if !defined(TOML_ENABLE_UNRELEASED_FEATURES) && defined(TOML_UNRELEASED_FEATURES) // was TOML_UNRELEASED_FEATURES + // pre-3.0 +#define TOML_ENABLE_UNRELEASED_FEATURES TOML_UNRELEASED_FEATURES +#endif +#if (defined(TOML_ENABLE_UNRELEASED_FEATURES) && TOML_ENABLE_UNRELEASED_FEATURES) || TOML_INTELLISENSE +#undef TOML_ENABLE_UNRELEASED_FEATURES +#define TOML_ENABLE_UNRELEASED_FEATURES 1 +#endif +#ifndef TOML_ENABLE_UNRELEASED_FEATURES +#define TOML_ENABLE_UNRELEASED_FEATURES 0 +#endif + +// parser +#if !defined(TOML_ENABLE_PARSER) && defined(TOML_PARSER) // was TOML_PARSER pre-3.0 +#define TOML_ENABLE_PARSER TOML_PARSER +#endif +#if !defined(TOML_ENABLE_PARSER) || (defined(TOML_ENABLE_PARSER) && TOML_ENABLE_PARSER) || TOML_INTELLISENSE +#undef TOML_ENABLE_PARSER +#define TOML_ENABLE_PARSER 1 +#endif + +// formatters +#if !defined(TOML_ENABLE_FORMATTERS) || (defined(TOML_ENABLE_FORMATTERS) && TOML_ENABLE_FORMATTERS) || TOML_INTELLISENSE +#undef TOML_ENABLE_FORMATTERS +#define TOML_ENABLE_FORMATTERS 1 +#endif + +// SIMD +#if !defined(TOML_ENABLE_SIMD) || (defined(TOML_ENABLE_SIMD) && TOML_ENABLE_SIMD) || TOML_INTELLISENSE +#undef TOML_ENABLE_SIMD +#define TOML_ENABLE_SIMD 1 +#endif + +// windows compat +#if !defined(TOML_ENABLE_WINDOWS_COMPAT) && defined(TOML_WINDOWS_COMPAT) // was TOML_WINDOWS_COMPAT pre-3.0 +#define TOML_ENABLE_WINDOWS_COMPAT TOML_WINDOWS_COMPAT +#endif +#if !defined(TOML_ENABLE_WINDOWS_COMPAT) || (defined(TOML_ENABLE_WINDOWS_COMPAT) && TOML_ENABLE_WINDOWS_COMPAT) \ + || TOML_INTELLISENSE +#undef TOML_ENABLE_WINDOWS_COMPAT +#define TOML_ENABLE_WINDOWS_COMPAT 1 +#endif + +#if !TOML_WINDOWS +#undef TOML_ENABLE_WINDOWS_COMPAT +#define TOML_ENABLE_WINDOWS_COMPAT 0 +#endif + +#ifndef TOML_INCLUDE_WINDOWS_H +#define TOML_INCLUDE_WINDOWS_H 0 +#endif + +// custom optional +#ifdef TOML_OPTIONAL_TYPE +#define TOML_HAS_CUSTOM_OPTIONAL_TYPE 1 +#else +#define TOML_HAS_CUSTOM_OPTIONAL_TYPE 0 +#endif + +// exceptions (library use) +#if TOML_COMPILER_HAS_EXCEPTIONS +#if !defined(TOML_EXCEPTIONS) || (defined(TOML_EXCEPTIONS) && TOML_EXCEPTIONS) +#undef TOML_EXCEPTIONS +#define TOML_EXCEPTIONS 1 +#endif +#else +#if defined(TOML_EXCEPTIONS) && TOML_EXCEPTIONS +#error TOML_EXCEPTIONS was explicitly enabled but exceptions are disabled/unsupported by the compiler. +#endif +#undef TOML_EXCEPTIONS +#define TOML_EXCEPTIONS 0 +#endif + +// calling convention for static/free/friend functions +#ifndef TOML_CALLCONV +#define TOML_CALLCONV +#endif + +#ifndef TOML_UNDEF_MACROS +#define TOML_UNDEF_MACROS 1 +#endif + +#ifndef TOML_MAX_NESTED_VALUES +#define TOML_MAX_NESTED_VALUES 256 +// this refers to the depth of nested values, e.g. inline tables and arrays. +// 256 is crazy high! if you're hitting this limit with real input, TOML is probably the wrong tool for the job... +#endif + +#ifndef TOML_MAX_DOTTED_KEYS_DEPTH +#define TOML_MAX_DOTTED_KEYS_DEPTH 1024 +#endif + +#ifdef TOML_CHAR_8_STRINGS +#if TOML_CHAR_8_STRINGS +#error TOML_CHAR_8_STRINGS was removed in toml++ 2.0.0; all value setters and getters now work with char8_t strings implicitly. +#endif +#endif + +#ifdef TOML_LARGE_FILES +#if !TOML_LARGE_FILES +#error Support for !TOML_LARGE_FILES (i.e. 'small files') was removed in toml++ 3.0.0. +#endif +#endif + +#ifndef TOML_LIFETIME_HOOKS +#define TOML_LIFETIME_HOOKS 0 +#endif + +#ifdef NDEBUG +#undef TOML_ASSERT +#define TOML_ASSERT(expr) static_assert(true) +#endif +#ifndef TOML_ASSERT +#ifndef assert +TOML_DISABLE_WARNINGS; +#include +TOML_ENABLE_WARNINGS; +#endif +#define TOML_ASSERT(expr) assert(expr) +#endif +#ifdef NDEBUG +#define TOML_ASSERT_ASSUME(expr) TOML_ASSUME(expr) +#else +#define TOML_ASSERT_ASSUME(expr) TOML_ASSERT(expr) +#endif + +#ifndef TOML_ENABLE_FLOAT16 +#define TOML_ENABLE_FLOAT16 0 +#endif + +#ifndef TOML_DISABLE_CONDITIONAL_NOEXCEPT_LAMBDA +#define TOML_DISABLE_CONDITIONAL_NOEXCEPT_LAMBDA 0 +#endif + +#ifndef TOML_DISABLE_NOEXCEPT_NOEXCEPT +#define TOML_DISABLE_NOEXCEPT_NOEXCEPT 0 + #ifdef _MSC_VER + #if _MSC_VER <= 1943 // Up to Visual Studio 2022 Version 17.13.6 + #undef TOML_DISABLE_NOEXCEPT_NOEXCEPT + #define TOML_DISABLE_NOEXCEPT_NOEXCEPT 1 + #endif + #endif +#endif + +#if !defined(TOML_FLOAT_CHARCONV) && (TOML_GCC || TOML_CLANG || (TOML_ICC && !TOML_ICC_CL)) +// not supported by any version of GCC or Clang as of 26/11/2020 +// not supported by any version of ICC on Linux as of 11/01/2021 +#define TOML_FLOAT_CHARCONV 0 +#endif +#if !defined(TOML_INT_CHARCONV) && (defined(__EMSCRIPTEN__) || defined(__APPLE__)) +// causes link errors on emscripten +// causes Mac OS SDK version errors on some versions of Apple Clang +#define TOML_INT_CHARCONV 0 +#endif +#ifndef TOML_INT_CHARCONV +#define TOML_INT_CHARCONV 1 +#endif +#ifndef TOML_FLOAT_CHARCONV +#define TOML_FLOAT_CHARCONV 1 +#endif +#if (TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV) && !TOML_HAS_INCLUDE() +#undef TOML_INT_CHARCONV +#undef TOML_FLOAT_CHARCONV +#define TOML_INT_CHARCONV 0 +#define TOML_FLOAT_CHARCONV 0 +#endif + +#if defined(__cpp_concepts) && __cpp_concepts >= 201907 +#define TOML_REQUIRES(...) requires(__VA_ARGS__) +#else +#define TOML_REQUIRES(...) +#endif +#define TOML_ENABLE_IF(...) , typename std::enable_if<(__VA_ARGS__), int>::type = 0 +#define TOML_CONSTRAINED_TEMPLATE(condition, ...) \ + template <__VA_ARGS__ TOML_ENABLE_IF(condition)> \ + TOML_REQUIRES(condition) +#define TOML_HIDDEN_CONSTRAINT(condition, ...) TOML_CONSTRAINED_TEMPLATE(condition, __VA_ARGS__) + +#if defined(__SIZEOF_FLOAT128__) && defined(__FLT128_MANT_DIG__) && defined(__LDBL_MANT_DIG__) \ + && __FLT128_MANT_DIG__ > __LDBL_MANT_DIG__ +#define TOML_FLOAT128 __float128 +#endif + +#ifdef __SIZEOF_INT128__ +#define TOML_INT128 __int128_t +#define TOML_UINT128 __uint128_t +#endif + +// clang-format off + +//******** impl/version.hpp ****************************************************************************************** + +#define TOML_LIB_MAJOR 3 +#define TOML_LIB_MINOR 4 +#define TOML_LIB_PATCH 0 + +#define TOML_LANG_MAJOR 1 +#define TOML_LANG_MINOR 0 +#define TOML_LANG_PATCH 0 + +//******** impl/preprocessor.hpp ************************************************************************************* + +#define TOML_LIB_SINGLE_HEADER 1 + +#if TOML_ENABLE_UNRELEASED_FEATURES + #define TOML_LANG_EFFECTIVE_VERSION \ + TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH+1) +#else + #define TOML_LANG_EFFECTIVE_VERSION \ + TOML_MAKE_VERSION(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH) +#endif + +#define TOML_LANG_HIGHER_THAN(major, minor, patch) \ + (TOML_LANG_EFFECTIVE_VERSION > TOML_MAKE_VERSION(major, minor, patch)) + +#define TOML_LANG_AT_LEAST(major, minor, patch) \ + (TOML_LANG_EFFECTIVE_VERSION >= TOML_MAKE_VERSION(major, minor, patch)) + +#define TOML_LANG_UNRELEASED \ + TOML_LANG_HIGHER_THAN(TOML_LANG_MAJOR, TOML_LANG_MINOR, TOML_LANG_PATCH) + +#ifndef TOML_ABI_NAMESPACES + #if TOML_DOXYGEN + #define TOML_ABI_NAMESPACES 0 + #else + #define TOML_ABI_NAMESPACES 1 + #endif +#endif +#if TOML_ABI_NAMESPACES + #define TOML_NAMESPACE_START namespace toml { inline namespace TOML_CONCAT(v, TOML_LIB_MAJOR) + #define TOML_NAMESPACE_END } static_assert(true) + #define TOML_NAMESPACE ::toml::TOML_CONCAT(v, TOML_LIB_MAJOR) + #define TOML_ABI_NAMESPACE_START(name) inline namespace name { static_assert(true) + #define TOML_ABI_NAMESPACE_BOOL(cond, T, F) TOML_ABI_NAMESPACE_START(TOML_CONCAT(TOML_EVAL_BOOL_, cond)(T, F)) + #define TOML_ABI_NAMESPACE_END } static_assert(true) +#else + #define TOML_NAMESPACE_START namespace toml + #define TOML_NAMESPACE_END static_assert(true) + #define TOML_NAMESPACE toml + #define TOML_ABI_NAMESPACE_START(...) static_assert(true) + #define TOML_ABI_NAMESPACE_BOOL(...) static_assert(true) + #define TOML_ABI_NAMESPACE_END static_assert(true) +#endif +#define TOML_IMPL_NAMESPACE_START TOML_NAMESPACE_START { namespace impl +#define TOML_IMPL_NAMESPACE_END } TOML_NAMESPACE_END +#if TOML_HEADER_ONLY + #define TOML_ANON_NAMESPACE_START static_assert(TOML_IMPLEMENTATION); TOML_IMPL_NAMESPACE_START + #define TOML_ANON_NAMESPACE_END TOML_IMPL_NAMESPACE_END + #define TOML_ANON_NAMESPACE TOML_NAMESPACE::impl + #define TOML_EXTERNAL_LINKAGE inline + #define TOML_INTERNAL_LINKAGE inline +#else + #define TOML_ANON_NAMESPACE_START static_assert(TOML_IMPLEMENTATION); \ + using namespace toml; \ + namespace + #define TOML_ANON_NAMESPACE_END static_assert(true) + #define TOML_ANON_NAMESPACE + #define TOML_EXTERNAL_LINKAGE + #define TOML_INTERNAL_LINKAGE static +#endif + +// clang-format on + +// clang-format off + +#if TOML_SIMPLE_STATIC_ASSERT_MESSAGES + + #define TOML_SA_NEWLINE " " + #define TOML_SA_LIST_SEP ", " + #define TOML_SA_LIST_BEG " (" + #define TOML_SA_LIST_END ")" + #define TOML_SA_LIST_NEW " " + #define TOML_SA_LIST_NXT ", " + +#else + + #define TOML_SA_NEWLINE "\n| " + #define TOML_SA_LIST_SEP TOML_SA_NEWLINE " - " + #define TOML_SA_LIST_BEG TOML_SA_LIST_SEP + #define TOML_SA_LIST_END + #define TOML_SA_LIST_NEW TOML_SA_NEWLINE TOML_SA_NEWLINE + #define TOML_SA_LIST_NXT TOML_SA_LIST_NEW + +#endif + +#define TOML_SA_NATIVE_VALUE_TYPE_LIST \ + TOML_SA_LIST_BEG "std::string" \ + TOML_SA_LIST_SEP "int64_t" \ + TOML_SA_LIST_SEP "double" \ + TOML_SA_LIST_SEP "bool" \ + TOML_SA_LIST_SEP "toml::date" \ + TOML_SA_LIST_SEP "toml::time" \ + TOML_SA_LIST_SEP "toml::date_time" \ + TOML_SA_LIST_END + +#define TOML_SA_NODE_TYPE_LIST \ + TOML_SA_LIST_BEG "toml::table" \ + TOML_SA_LIST_SEP "toml::array" \ + TOML_SA_LIST_SEP "toml::value" \ + TOML_SA_LIST_SEP "toml::value" \ + TOML_SA_LIST_SEP "toml::value" \ + TOML_SA_LIST_SEP "toml::value" \ + TOML_SA_LIST_SEP "toml::value" \ + TOML_SA_LIST_SEP "toml::value" \ + TOML_SA_LIST_SEP "toml::value" \ + TOML_SA_LIST_END + +#define TOML_SA_UNWRAPPED_NODE_TYPE_LIST \ + TOML_SA_LIST_NEW "A native TOML value type" \ + TOML_SA_NATIVE_VALUE_TYPE_LIST \ + \ + TOML_SA_LIST_NXT "A TOML node type" \ + TOML_SA_NODE_TYPE_LIST + +// clang-format on + +TOML_PUSH_WARNINGS; +TOML_DISABLE_SPAM_WARNINGS; +TOML_DISABLE_SWITCH_WARNINGS; +TOML_DISABLE_SUGGEST_ATTR_WARNINGS; + +// misc warning false-positives +#if TOML_MSVC +#pragma warning(disable : 5031) // #pragma warning(pop): likely mismatch +#if TOML_SHARED_LIB +#pragma warning(disable : 4251) // dll exports for std lib types +#endif +#elif TOML_CLANG +TOML_PRAGMA_CLANG(diagnostic ignored "-Wheader-hygiene") +#if TOML_CLANG >= 12 +TOML_PRAGMA_CLANG(diagnostic ignored "-Wc++20-extensions") +#endif +#if TOML_CLANG == 13 +TOML_PRAGMA_CLANG(diagnostic ignored "-Wreserved-identifier") +#endif +#endif + +//******** impl/std_new.hpp ****************************************************************************************** + +TOML_DISABLE_WARNINGS; +#include +TOML_ENABLE_WARNINGS; + +#if (!defined(__apple_build_version__) && TOML_CLANG >= 8) || TOML_GCC >= 7 || TOML_ICC >= 1910 || TOML_MSVC >= 1914 +#define TOML_LAUNDER(x) __builtin_launder(x) +#elif defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606 +#define TOML_LAUNDER(x) std::launder(x) +#else +#define TOML_LAUNDER(x) x +#endif + +//******** impl/std_string.hpp *************************************************************************************** + +TOML_DISABLE_WARNINGS; +#include +#include +TOML_ENABLE_WARNINGS; + +#if TOML_DOXYGEN \ + || (defined(__cpp_char8_t) && __cpp_char8_t >= 201811 && defined(__cpp_lib_char8_t) \ + && __cpp_lib_char8_t >= 201907) +#define TOML_HAS_CHAR8 1 +#else +#define TOML_HAS_CHAR8 0 +#endif + +namespace toml // non-abi namespace; this is not an error +{ + using namespace std::string_literals; + using namespace std::string_view_literals; +} + +#if TOML_ENABLE_WINDOWS_COMPAT + +TOML_IMPL_NAMESPACE_START +{ + TOML_NODISCARD + TOML_EXPORTED_FREE_FUNCTION + std::string narrow(std::wstring_view); + + TOML_NODISCARD + TOML_EXPORTED_FREE_FUNCTION + std::wstring widen(std::string_view); + +#if TOML_HAS_CHAR8 + + TOML_NODISCARD + TOML_EXPORTED_FREE_FUNCTION + std::wstring widen(std::u8string_view); + +#endif +} +TOML_IMPL_NAMESPACE_END; + +#endif // TOML_ENABLE_WINDOWS_COMPAT + +//******** impl/std_optional.hpp ************************************************************************************* + +TOML_DISABLE_WARNINGS; +#if !TOML_HAS_CUSTOM_OPTIONAL_TYPE +#include +#endif +TOML_ENABLE_WARNINGS; + +TOML_NAMESPACE_START +{ +#if TOML_HAS_CUSTOM_OPTIONAL_TYPE + + template + using optional = TOML_OPTIONAL_TYPE; + +#else + + template + using optional = std::optional; + +#endif +} +TOML_NAMESPACE_END; + +//******** impl/forward_declarations.hpp ***************************************************************************** + +TOML_DISABLE_WARNINGS; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +TOML_ENABLE_WARNINGS; +TOML_PUSH_WARNINGS; +#ifdef _MSC_VER +#ifndef __clang__ +#pragma inline_recursion(on) +#endif +#pragma push_macro("min") +#pragma push_macro("max") +#undef min +#undef max +#endif + +#ifndef TOML_DISABLE_ENVIRONMENT_CHECKS +#define TOML_ENV_MESSAGE \ + "If you're seeing this error it's because you're building toml++ for an environment that doesn't conform to " \ + "one of the 'ground truths' assumed by the library. Essentially this just means that I don't have the " \ + "resources to test on more platforms, but I wish I did! You can try disabling the checks by defining " \ + "TOML_DISABLE_ENVIRONMENT_CHECKS, but your mileage may vary. Please consider filing an issue at " \ + "https://github.com/marzer/tomlplusplus/issues to help me improve support for your target environment. " \ + "Thanks!" + +static_assert(CHAR_BIT == 8, TOML_ENV_MESSAGE); +#ifdef FLT_RADIX +static_assert(FLT_RADIX == 2, TOML_ENV_MESSAGE); +#endif +static_assert('A' == 65, TOML_ENV_MESSAGE); +static_assert(sizeof(double) == 8, TOML_ENV_MESSAGE); +static_assert(std::numeric_limits::is_iec559, TOML_ENV_MESSAGE); +static_assert(std::numeric_limits::digits == 53, TOML_ENV_MESSAGE); +static_assert(std::numeric_limits::digits10 == 15, TOML_ENV_MESSAGE); +static_assert(std::numeric_limits::radix == 2, TOML_ENV_MESSAGE); + +#undef TOML_ENV_MESSAGE +#endif // !TOML_DISABLE_ENVIRONMENT_CHECKS + +// undocumented forward declarations are hidden from doxygen because they fuck it up =/ + +namespace toml // non-abi namespace; this is not an error +{ + using ::std::size_t; + using ::std::intptr_t; + using ::std::uintptr_t; + using ::std::ptrdiff_t; + using ::std::nullptr_t; + using ::std::int8_t; + using ::std::int16_t; + using ::std::int32_t; + using ::std::int64_t; + using ::std::uint8_t; + using ::std::uint16_t; + using ::std::uint32_t; + using ::std::uint64_t; + using ::std::uint_least32_t; + using ::std::uint_least64_t; +} + +TOML_NAMESPACE_START +{ + struct date; + struct time; + struct time_offset; + + TOML_ABI_NAMESPACE_BOOL(TOML_HAS_CUSTOM_OPTIONAL_TYPE, custopt, stdopt); + struct date_time; + TOML_ABI_NAMESPACE_END; + + struct source_position; + struct source_region; + + class node; + template + class node_view; + + class key; + class array; + class table; + template + class value; + + class path; + + class toml_formatter; + class json_formatter; + class yaml_formatter; + + TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, ex, noex); +#if TOML_EXCEPTIONS + using parse_result = table; +#else + class parse_result; +#endif + TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS +} +TOML_NAMESPACE_END; + +TOML_IMPL_NAMESPACE_START +{ + using node_ptr = std::unique_ptr; + + TOML_ABI_NAMESPACE_BOOL(TOML_EXCEPTIONS, impl_ex, impl_noex); + class parser; + TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS + + // clang-format off + + inline constexpr std::string_view control_char_escapes[] = + { + "\\u0000"sv, + "\\u0001"sv, + "\\u0002"sv, + "\\u0003"sv, + "\\u0004"sv, + "\\u0005"sv, + "\\u0006"sv, + "\\u0007"sv, + "\\b"sv, + "\\t"sv, + "\\n"sv, + "\\u000B"sv, + "\\f"sv, + "\\r"sv, + "\\u000E"sv, + "\\u000F"sv, + "\\u0010"sv, + "\\u0011"sv, + "\\u0012"sv, + "\\u0013"sv, + "\\u0014"sv, + "\\u0015"sv, + "\\u0016"sv, + "\\u0017"sv, + "\\u0018"sv, + "\\u0019"sv, + "\\u001A"sv, + "\\u001B"sv, + "\\u001C"sv, + "\\u001D"sv, + "\\u001E"sv, + "\\u001F"sv, + }; + + inline constexpr std::string_view node_type_friendly_names[] = + { + "none"sv, + "table"sv, + "array"sv, + "string"sv, + "integer"sv, + "floating-point"sv, + "boolean"sv, + "date"sv, + "time"sv, + "date-time"sv + }; + + // clang-format on +} +TOML_IMPL_NAMESPACE_END; + +#if TOML_ABI_NAMESPACES +#if TOML_EXCEPTIONS +#define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::impl_ex::parser +#else +#define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::impl_noex::parser +#endif +#else +#define TOML_PARSER_TYPENAME TOML_NAMESPACE::impl::parser +#endif + +namespace toml +{ +} + +TOML_NAMESPACE_START // abi namespace +{ + inline namespace literals + { + } + + enum class TOML_CLOSED_ENUM node_type : uint8_t + { + none, + table, + array, + string, + integer, + floating_point, + boolean, + date, + time, + date_time + }; + + template + inline std::basic_ostream& operator<<(std::basic_ostream& lhs, node_type rhs) + { + const auto str = impl::node_type_friendly_names[static_cast>(rhs)]; + using str_char_t = decltype(str)::value_type; + if constexpr (std::is_same_v) + return lhs << str; + else + { + if constexpr (sizeof(Char) == sizeof(str_char_t)) + return lhs << std::basic_string_view{ reinterpret_cast(str.data()), str.length() }; + else + return lhs << str.data(); + } + } + + enum class TOML_OPEN_FLAGS_ENUM value_flags : uint16_t // being an "OPEN" flags enum is not an error + { + none, + format_as_binary = 1, + format_as_octal = 2, + format_as_hexadecimal = 3, + }; + TOML_MAKE_FLAGS(value_flags); + + inline constexpr value_flags preserve_source_value_flags = + POXY_IMPLEMENTATION_DETAIL(value_flags{ static_cast>(-1) }); + + enum class TOML_CLOSED_FLAGS_ENUM format_flags : uint64_t + { + none, + quote_dates_and_times = (1ull << 0), + quote_infinities_and_nans = (1ull << 1), + allow_literal_strings = (1ull << 2), + allow_multi_line_strings = (1ull << 3), + allow_real_tabs_in_strings = (1ull << 4), + allow_unicode_strings = (1ull << 5), + allow_binary_integers = (1ull << 6), + allow_octal_integers = (1ull << 7), + allow_hexadecimal_integers = (1ull << 8), + indent_sub_tables = (1ull << 9), + indent_array_elements = (1ull << 10), + indentation = indent_sub_tables | indent_array_elements, + relaxed_float_precision = (1ull << 11), + terse_key_value_pairs = (1ull << 12), + force_multiline_arrays = (1ull << 13), + }; + TOML_MAKE_FLAGS(format_flags); + + template + struct TOML_TRIVIAL_ABI inserter + { + static_assert(std::is_reference_v); + + T value; + }; + template + inserter(T&&) -> inserter; + template + inserter(T&) -> inserter; + + using default_formatter = toml_formatter; +} +TOML_NAMESPACE_END; + +TOML_IMPL_NAMESPACE_START +{ + template + using remove_cvref = std::remove_cv_t>; + + template + using common_signed_type = std::common_type_t...>; + + template + inline constexpr bool is_one_of = (false || ... || std::is_same_v); + + template + inline constexpr bool all_integral = (std::is_integral_v && ...); + + template + inline constexpr bool is_cvref = std::is_reference_v || std::is_const_v || std::is_volatile_v; + + template + inline constexpr bool is_wide_string = + is_one_of, const wchar_t*, wchar_t*, std::wstring_view, std::wstring>; + + template + inline constexpr bool value_retrieval_is_nothrow = !std::is_same_v, std::string> +#if TOML_HAS_CHAR8 + && !std::is_same_v, std::u8string> +#endif + + && !is_wide_string; + + template + struct copy_ref_; + template + using copy_ref = typename copy_ref_::type; + + template + struct copy_ref_ + { + using type = Dest; + }; + + template + struct copy_ref_ + { + using type = std::add_lvalue_reference_t; + }; + + template + struct copy_ref_ + { + using type = std::add_rvalue_reference_t; + }; + + template + struct copy_cv_; + template + using copy_cv = typename copy_cv_::type; + + template + struct copy_cv_ + { + using type = Dest; + }; + + template + struct copy_cv_ + { + using type = std::add_const_t; + }; + + template + struct copy_cv_ + { + using type = std::add_volatile_t; + }; + + template + struct copy_cv_ + { + using type = std::add_cv_t; + }; + + template + using copy_cvref = + copy_ref, std::remove_reference_t>, Dest>, Src>; + + template + inline constexpr bool always_false = false; + + template + inline constexpr bool first_is_same = false; + template + inline constexpr bool first_is_same = true; + + template > + struct underlying_type_ + { + using type = std::underlying_type_t; + }; + template + struct underlying_type_ + { + using type = T; + }; + template + using underlying_type = typename underlying_type_::type; + + // general value traits + // (as they relate to their equivalent native TOML type) + struct default_value_traits + { + using native_type = void; + static constexpr bool is_native = false; + static constexpr bool is_losslessly_convertible_to_native = false; + static constexpr bool can_represent_native = false; + static constexpr bool can_partially_represent_native = false; + static constexpr auto type = node_type::none; + }; + + template + struct value_traits; + + template > + struct value_traits_base_selector + { + static_assert(!is_cvref); + + using type = default_value_traits; + }; + template + struct value_traits_base_selector + { + static_assert(!is_cvref); + + using type = value_traits>; + }; + + template + struct value_traits : value_traits_base_selector::type + {}; + template + struct value_traits : value_traits + {}; + template + struct value_traits : value_traits + {}; + template + struct value_traits : value_traits + {}; + template + struct value_traits : value_traits + {}; + template + struct value_traits : value_traits + {}; + + // integer value_traits specializations - standard types + template + struct integer_limits + { + static constexpr T min = T{ (std::numeric_limits>::min)() }; + static constexpr T max = T{ (std::numeric_limits>::max)() }; + }; + template + struct integer_traits_base : integer_limits + { + using native_type = int64_t; + static constexpr bool is_native = std::is_same_v, native_type>; + static constexpr bool is_signed = static_cast>(-1) < underlying_type{}; + static constexpr auto type = node_type::integer; + static constexpr bool can_partially_represent_native = true; + }; + template + struct unsigned_integer_traits : integer_traits_base + { + static constexpr bool is_losslessly_convertible_to_native = + integer_limits>::max <= 9223372036854775807ULL; + static constexpr bool can_represent_native = false; + }; + template + struct signed_integer_traits : integer_traits_base + { + using native_type = int64_t; + static constexpr bool is_losslessly_convertible_to_native = + integer_limits>::min >= (-9223372036854775807LL - 1LL) + && integer_limits>::max <= 9223372036854775807LL; + static constexpr bool can_represent_native = + integer_limits>::min <= (-9223372036854775807LL - 1LL) + && integer_limits>::max >= 9223372036854775807LL; + }; + template ::is_signed> + struct integer_traits : signed_integer_traits + {}; + template + struct integer_traits : unsigned_integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; + static_assert(value_traits::is_native); + static_assert(value_traits::is_signed); + static_assert(value_traits::is_losslessly_convertible_to_native); + static_assert(value_traits::can_represent_native); + static_assert(value_traits::can_partially_represent_native); + + // integer value_traits specializations - non-standard types +#ifdef TOML_INT128 + template <> + struct integer_limits + { + static constexpr TOML_INT128 max = + static_cast((TOML_UINT128{ 1u } << ((__SIZEOF_INT128__ * CHAR_BIT) - 1)) - 1); + static constexpr TOML_INT128 min = -max - TOML_INT128{ 1 }; + }; + template <> + struct integer_limits + { + static constexpr TOML_UINT128 min = TOML_UINT128{}; + static constexpr TOML_UINT128 max = (2u * static_cast(integer_limits::max)) + 1u; + }; + template <> + struct value_traits : integer_traits + {}; + template <> + struct value_traits : integer_traits + {}; +#endif +#ifdef TOML_SMALL_INT_TYPE + template <> + struct value_traits : signed_integer_traits + {}; +#endif + + // floating-point traits base + template + struct float_traits_base + { + static constexpr auto type = node_type::floating_point; + using native_type = double; + static constexpr bool is_native = std::is_same_v; + static constexpr bool is_signed = true; + + static constexpr int bits = static_cast(sizeof(T) * CHAR_BIT); + static constexpr int digits = MantissaDigits; + static constexpr int digits10 = DecimalDigits; + + static constexpr bool is_losslessly_convertible_to_native = bits <= 64 // + && digits <= 53 // DBL_MANT_DIG + && digits10 <= 15; // DBL_DIG + + static constexpr bool can_represent_native = digits >= 53 // DBL_MANT_DIG + && digits10 >= 15; // DBL_DIG + + static constexpr bool can_partially_represent_native = digits > 0 && digits10 > 0; + }; + template + struct float_traits : float_traits_base::digits, std::numeric_limits::digits10> + {}; +#if TOML_ENABLE_FLOAT16 + template <> + struct float_traits<_Float16> : float_traits_base<_Float16, __FLT16_MANT_DIG__, __FLT16_DIG__> + {}; +#endif +#ifdef TOML_FLOAT128 + template <> + struct float_traits : float_traits_base + {}; +#endif + + // floating-point traits + template <> + struct value_traits : float_traits + {}; + template <> + struct value_traits : float_traits + {}; + template <> + struct value_traits : float_traits + {}; +#if TOML_ENABLE_FLOAT16 + template <> + struct value_traits<_Float16> : float_traits<_Float16> + {}; +#endif +#ifdef TOML_FLOAT128 + template <> + struct value_traits : float_traits + {}; +#endif +#ifdef TOML_SMALL_FLOAT_TYPE + template <> + struct value_traits : float_traits + {}; +#endif + static_assert(value_traits::is_native); + static_assert(value_traits::is_losslessly_convertible_to_native); + static_assert(value_traits::can_represent_native); + static_assert(value_traits::can_partially_represent_native); + + // string value_traits specializations - char-based strings + template + struct string_traits + { + using native_type = std::string; + static constexpr bool is_native = std::is_same_v; + static constexpr bool is_losslessly_convertible_to_native = true; + static constexpr bool can_represent_native = + !std::is_array_v && (!std::is_pointer_v || std::is_const_v>); + static constexpr bool can_partially_represent_native = can_represent_native; + static constexpr auto type = node_type::string; + }; + template <> + struct value_traits : string_traits + {}; + template <> + struct value_traits : string_traits + {}; + template <> + struct value_traits : string_traits + {}; + template + struct value_traits : string_traits + {}; + template <> + struct value_traits : string_traits + {}; + template + struct value_traits : string_traits + {}; + + // string value_traits specializations - char8_t-based strings +#if TOML_HAS_CHAR8 + template <> + struct value_traits : string_traits + {}; + template <> + struct value_traits : string_traits + {}; + template <> + struct value_traits : string_traits + {}; + template + struct value_traits : string_traits + {}; + template <> + struct value_traits : string_traits + {}; + template + struct value_traits : string_traits + {}; +#endif + + // string value_traits specializations - wchar_t-based strings on Windows +#if TOML_ENABLE_WINDOWS_COMPAT + template + struct wstring_traits + { + using native_type = std::string; + static constexpr bool is_native = false; + static constexpr bool is_losslessly_convertible_to_native = true; // narrow + static constexpr bool can_represent_native = std::is_same_v; // widen + static constexpr bool can_partially_represent_native = can_represent_native; + static constexpr auto type = node_type::string; + }; + template <> + struct value_traits : wstring_traits + {}; + template <> + struct value_traits : wstring_traits + {}; + template <> + struct value_traits : wstring_traits + {}; + template + struct value_traits : wstring_traits + {}; + template <> + struct value_traits : wstring_traits + {}; + template + struct value_traits : wstring_traits + {}; +#endif + + // other 'native' value_traits specializations + template + struct native_value_traits + { + using native_type = T; + static constexpr bool is_native = true; + static constexpr bool is_losslessly_convertible_to_native = true; + static constexpr bool can_represent_native = true; + static constexpr bool can_partially_represent_native = true; + static constexpr auto type = NodeType; + }; + template <> + struct value_traits : native_value_traits + {}; + template <> + struct value_traits : native_value_traits + {}; + template <> + struct value_traits