In our recent paper we have quite a few figures that contained two code snippets side by side. Every single one was a pain, because I somehow couldn't figure out how to center such a figure properly. The paper employs multiple solutions, because they were all suboptimal, for various small reasons that I unfortunately can't recall. Today I ran into this yet again, so I took another half hour to try and find a proper solution to this problem. Lo and behold, I did! At least, partially. It still requires specifying the width of the code listings up front, but that's not too bad. This method also has a nice additional feature: if it goes beyond a specified width, it scales down the contents. This might not be a general solution, but I'm sure this would've been nice to have while writing the previous paper!
\begin{figure}[t]
\begin{adjustbox}{max width=1.4\linewidth,center}
\centering
\begin{subfigure}[t]{0.45\textwidth}
\begin{lstlisting}[style=pvl, xleftmargin=0.7cm]
(Left)
\end{lstlisting}
\end{subfigure}
\qquad
\begin{subfigure}[t]{0.7\textwidth}
\begin{lstlisting}[style=pvl, xleftmargin=0.7cm]
(Right)
\end{lstlisting}
\end{subfigure}
\end{adjustbox}
\end{figure}
This solution is due to "user11232" over at tex.stackexchange. Somehow I was unable to find this post even though it solves exactly my problem. At least I can use it now!
The only problem left to solve is to somehow make this process of determining the width to set easier. I use the mdframed environment for this, because a plain fbox{...} command around the lstlisting environment breaks for some reason. By wrapping the lstlisting in an mdframed environment, a border is drawn around the code listing, allowing me to check if the code overflows the box anywhere. If so, the size needs to be incremented. If not, the size can be made smaller, or be left alone if I like how it looks. It's not as good as automating determining the size, but it's also simple and maintainable.
Here is a complete example, with some code fluff adde in to show the code overflowing:
\documentclass{article}
\usepackage{
listings, % lstlisting environment
adjustbox, % adjustbox environment
subcaption, % subfigure environment
mdframed, % mdframed environment
}
% Remove all margins in mdframed environment
\mdfsetup{
skipabove=0pt,
skipbelow=0pt,
leftmargin=0pt,
rightmargin=0pt,
innerleftmargin=0pt,
innerrightmargin=0pt,
innertopmargin=0pt,
innerbottommargin=0pt
}
\begin{document}
\begin{figure}[t]
\begin{adjustbox}{max width=1.4\linewidth,center}
\centering
\begin{subfigure}[t]{0.45\textwidth}
\begin{mdframed}
\begin{lstlisting}
choreography increment(Store s) {
endpoint a = Role(s);
endpoint b = Role(null);
requires Perm[a](a.s, 1\2) ** Perm[a](a.s.x, 1) ** a.s.x > 0;
ensures Perm[a](a.s, 1\2) ** Perm[a](a.s.x, 1) ** a.s.x > 2;
run {
a: a.s.x := a.s.x + 1;
channel_invariant Perm(a.s, 1\2) ** Perm(a.s.x, 1) ** a.s.x > 1;
communicate a: a.s -> b: b.s;
assert Perm[b](a.s, 1\2) ** Perm[b](a.s.x, 1);
b: a.s.x := a.s.x + 1;
channel_invariant Perm(a.s, 1\2) ** Perm(a.s.x, 1\2) ** a.s.x > 2;
communicate b: b.s -> a: a.s;
} }
\end{lstlisting}
\end{mdframed}
\end{subfigure}
\qquad % Add space to taste
\begin{subfigure}[t]{0.7\textwidth}
\begin{mdframed}
\begin{lstlisting}
choreography increment(Store s) {
endpoint a = Role(s);
endpoint b = Role(null);
requires Perm[a](a.s, 1\2) ** Perm[a](a.s.x, 1) ** a.s.x > 0;
ensures Perm[a](a.s, 1\2) ** Perm[a](a.s.x, 1) ** a.s.x > 2;
run {
a: a.s.x := a.s.x + 1;
channel_invariant Perm(a.s, 1\2) ** Perm(a.s.x, 1) ** a.s.x > 1;
communicate a: a.s -> b: b.s;
assert Perm[b](a.s, 1\2) ** Perm[b](a.s.x, 1);
b: a.s.x := a.s.x + 1;
channel_invariant Perm(a.s, 1\2) ** Perm(a.s.x, 1\2) ** a.s.x > 2;
communicate b: b.s -> a: a.s;
} }
\end{lstlisting}
\end{mdframed}
\end{subfigure}
\end{adjustbox}
\caption{Overflowing}
\end{figure}
\begin{figure}[t]
\begin{adjustbox}{max width=1.4\linewidth,center}
\centering
\begin{subfigure}[t]{0.6\textwidth}
\begin{mdframed}
\begin{lstlisting}[breaklines]
choreography increment(Store s) {
endpoint a = Role(s);
endpoint b = Role(null);
requires Perm[a](a.s, 1\2) ** Perm[a](a.s.x, 1) ** a.s.x > 0;
ensures Perm[a](a.s, 1\2) ** Perm[a](a.s.x, 1) ** a.s.x > 2;
run {
a: a.s.x := a.s.x + 1;
channel_invariant Perm(a.s, 1\2) ** Perm(a.s.x, 1) ** a.s.x > 1;
communicate a: a.s -> b: b.s;
assert Perm[b](a.s, 1\2) ** Perm[b](a.s.x, 1);
b: a.s.x := a.s.x + 1;
channel_invariant Perm(a.s, 1\2) ** Perm(a.s.x, 1\2) ** a.s.x > 2;
communicate b: b.s -> a: a.s;
} }
\end{lstlisting}
\end{mdframed}
\end{subfigure}
\qquad % Add space to taste
\begin{subfigure}[t]{0.9\textwidth}
\begin{mdframed}
\begin{lstlisting}[breaklines]
choreography increment(Store s) {
endpoint a = Role(s);
endpoint b = Role(null);
requires Perm[a](a.s, 1\2) ** Perm[a](a.s.x, 1) ** a.s.x > 0;
ensures Perm[a](a.s, 1\2) ** Perm[a](a.s.x, 1) ** a.s.x > 2;
run {
a: a.s.x := a.s.x + 1;
channel_invariant Perm(a.s, 1\2) ** Perm(a.s.x, 1) ** a.s.x > 1;
communicate a: a.s -> b: b.s;
assert Perm[b](a.s, 1\2) ** Perm[b](a.s.x, 1);
b: a.s.x := a.s.x + 1;
channel_invariant Perm(a.s, 1\2) ** Perm(a.s.x, 1\2) ** a.s.x > 2;
communicate b: b.s -> a: a.s;
} }
\end{lstlisting}
\end{mdframed}
\end{subfigure}
\end{adjustbox}
\caption{Boxed}
\end{figure}
\end{document}
Which ends up looking something like: